当前位置:   article > 正文

用echarts实现3d饼图_echarts 3d饼图

echarts 3d饼图

安装echarts和echarts-gl

npm install echarts

npm install echarts-gl

echarts版本5.x的话需要对应echarts-gl版本2.x

echarts版本4.x的话需要对应echarts-gl版本1.x

指定版本命令 npm install echarts-gl@1.1.2

1.关键函数,生成扇形的曲面参数方程,用于 series-surface

Documentation - Apache ECharts官网series-surface介绍 Documentation - Apache ECharts

getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {

    // 计算

    const midRatio = (startRatio + endRatio) / 2;

    const startRadian = startRatio * Math.PI * 2;

    const endRadian = endRatio * Math.PI * 2;

    const midRadian = midRatio * Math.PI * 2;

    // 如果只有一个扇形,则不实现选中效果。

    if (startRatio === 0 && endRatio === 1) {

        isSelected = false;

    }

    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)

    k = 1;

    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)

    const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;

    const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;

    // 计算高亮效果的放大比例(未高亮,则比例为 1)

    const hoverRate = isHovered ? 1.05 : 1;

    // 返回曲面参数方程

    return {

        u: {

            min: -Math.PI,

            max: Math.PI * 3,

            step: Math.PI / 32,

        },

        v: {

            min: 0,

            max: Math.PI * 2,

            step: Math.PI / 20,

        },

        x: function (u, v) {

            if (u < startRadian) {

                return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;

            }

            if (u > endRadian) {

                return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;

            }

            return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;

        },

        y: function (u, v) {

            if (u < startRadian) {

                return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;

            }

            if (u > endRadian) {

                return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;

            }

            return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;

        },

        z: function (u, v) {

            if (u < -Math.PI * 0.5) {

                return Math.sin(u);

            }

            if (u > Math.PI * 2.5) {

                return Math.sin(u) * h * 0.1;

            }

            return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;

        },

    };

  }

2.构建饼图函数,绘制3d图。internalDiameterRatio为透明的空心占比,0就是普通饼1就镂空

getPie3D(pieData, internalDiameterRatio) {

    const series = [];

    let sumValue = 0;

    let startValue = 0;

    let endValue = 0;

    const legendData = [];

    const k =

        typeof internalDiameterRatio !== 'undefined'

            ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)

            : 1 / 3;

    // 为每一个饼图数据,生成一个 series-surface 配置

    for (let i = 0; i < pieData.length; i += 1) {

        sumValue += pieData[i].value;

        const seriesItem = {

            name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,

            type: 'surface',

            parametric: true,

            wireframe: {

                show: false,

            },

            pieData: pieData[i],

            pieStatus: {

                selected: false,

                hovered: false,

                k: k,

            },

            itemStyle:{}

        };

        if (typeof pieData[i].itemStyle !== 'undefined') {

            const itemStyle :any= {};

            if (typeof pieData[i].itemStyle.color !== 'undefined') {

                itemStyle.color = pieData[i].itemStyle.color;

            }

            if (typeof pieData[i].itemStyle.opacity !== 'undefined') {

                itemStyle.opacity = pieData[i].itemStyle.opacity;

            }

            seriesItem.itemStyle = itemStyle;

        }

        series.push(seriesItem);

    }

    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,

    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。

    for (let i = 0; i < series.length; i += 1) {

        endValue = startValue + series[i].pieData.value;

        series[i].pieData.startRatio = startValue / sumValue;

        series[i].pieData.endRatio = endValue / sumValue;

        console.log(series[i].pieData.startRatio,

            series[i].pieData.endRatio,

            false,  

            false,

            k,

            series[i].pieData.value)

            series[i].parametricEquation = this.getParametricEquation(

            series[i].pieData.startRatio,

            series[i].pieData.endRatio,

            false,

            false,

            k,

            25//高度

        );

        startValue = endValue;

        legendData.push(series[i].name);

    }

    return series;

  }

3.绘制2d饼图,添加label指引线

series.push({

      name: 'pie2d',

      type: 'pie',

      label: {

          opacity: 1,

          fontSize: 14,

          lineHeight: 20,

      },

      labelLine: {

          length: 50,

          length2: 50,

      },

      startAngle: -50, //起始角度,支持范围[0, 360]。

      clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式

      radius: ['20%', '50%'],

      center: ['50%', '50%'],

      data: optionsData,

      itemStyle: {

          opacity: 0,

      },

    });

js代码:

  1. setPie(){
  2. const optionsData = [
  3. {
  4. name: 'aa',
  5. value: 20,
  6. itemStyle: {
  7. color: '#38ACEC',
  8. // opacity: 1,
  9. },
  10. },
  11. {
  12. name: 'bb',
  13. value: 15,
  14. itemStyle: {
  15. color: '#6960EC',
  16. // opacity: 1,
  17. },
  18. },
  19. {
  20. name: 'cc',
  21. value: 25,
  22. itemStyle: {
  23. color: '#6CBB3C',
  24. // opacity: 1,
  25. },
  26. },
  27. ];
  28. const series = this.getPie3D(optionsData, 0.5,);
  29. series.push({
  30. name: 'pie2d',
  31. type: 'pie',
  32. label: {
  33. opacity: 1,
  34. fontSize: 14,
  35. lineHeight: 20,
  36. },
  37. labelLine: {
  38. length: 50,
  39. length2: 50,
  40. },
  41. startAngle: -50, //起始角度,支持范围[0, 360]。
  42. clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
  43. radius: ['20%', '50%'],
  44. center: ['50%', '50%'],
  45. data: optionsData,
  46. itemStyle: {
  47. opacity: 0,
  48. },
  49. });
  50. this.option1 =
  51. {
  52. legend: {
  53. tooltip: {
  54. show: true,
  55. },
  56. data: ['aa', 'bb', 'cc'],
  57. right: '2%',
  58. textStyle: {
  59. color: '#fff',
  60. fontSize: 12,
  61. },
  62. },
  63. tooltip: {
  64. formatter: (params) => {
  65. if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
  66. let bfb = (
  67. (this.option.series[params.seriesIndex].pieData.endRatio -
  68. this.option.series[params.seriesIndex].pieData.startRatio) *
  69. 100
  70. ).toFixed(2);
  71. return (
  72. `${params.seriesName}<br/>` +
  73. `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;"></span>` +
  74. `${bfb}%`
  75. );
  76. }
  77. },
  78. },
  79. title: {
  80. text: '3D 饼图',
  81. x: 'center',
  82. top: '5%',
  83. textStyle: {
  84. color: '#fff',
  85. fontSize: 22,
  86. },
  87. },
  88. labelLine: {
  89. show: true,
  90. lineStyle: {
  91. color: '#7BC0CB',
  92. },
  93. },
  94. label: {
  95. show: true,
  96. position: 'outside',
  97. formatter: '{b} \n{c} {d}%',
  98. },
  99. xAxis3D: {
  100. min: -1,
  101. max: 1,
  102. },
  103. yAxis3D: {
  104. min: -1,
  105. max: 1,
  106. },
  107. zAxis3D: {
  108. min: -1,
  109. max: 1,
  110. },
  111. grid3D: {
  112. show: false,
  113. boxHeight: 25, // 三维笛卡尔坐标系在三维场景中的高度
  114. viewControl: {
  115. alpha: 45,
  116. // beta: 1000,
  117. distance: 300, //调整视角到主体的距离,类似调整zoom
  118. // rotateSensitivity: 0, // 设置为0无法旋转
  119. zoomSensitivity: 0, // 设置为0无法缩放
  120. panSensitivity: 0, // 设置为0无法平移
  121. autoRotate: false, // 自动旋转
  122. },
  123. },
  124. series: series,
  125. };
  126. }
  127. // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
  128. getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
  129. // 计算
  130. const midRatio = (startRatio + endRatio) / 2;
  131. const startRadian = startRatio * Math.PI * 2;
  132. const endRadian = endRatio * Math.PI * 2;
  133. const midRadian = midRatio * Math.PI * 2;
  134. // 如果只有一个扇形,则不实现选中效果。
  135. if (startRatio === 0 && endRatio === 1) {
  136. isSelected = false;
  137. }
  138. // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
  139. k = 1;
  140. // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
  141. const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  142. const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
  143. // 计算高亮效果的放大比例(未高亮,则比例为 1)
  144. const hoverRate = isHovered ? 1.05 : 1;
  145. // 返回曲面参数方程
  146. return {
  147. u: {
  148. min: -Math.PI,
  149. max: Math.PI * 3,
  150. step: Math.PI / 32,
  151. },
  152. v: {
  153. min: 0,
  154. max: Math.PI * 2,
  155. step: Math.PI / 20,
  156. },
  157. x: function (u, v) {
  158. if (u < startRadian) {
  159. return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
  160. }
  161. if (u > endRadian) {
  162. return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
  163. }
  164. return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
  165. },
  166. y: function (u, v) {
  167. if (u < startRadian) {
  168. return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
  169. }
  170. if (u > endRadian) {
  171. return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
  172. }
  173. return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
  174. },
  175. z: function (u, v) {
  176. if (u < -Math.PI * 0.5) {
  177. return Math.sin(u);
  178. }
  179. if (u > Math.PI * 2.5) {
  180. return Math.sin(u) * h * 0.1;
  181. }
  182. return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
  183. },
  184. };
  185. }
  186. //构建饼图数据,绘制3d图 internalDiameterRatio:透明的空心占比
  187. getPie3D(pieData, internalDiameterRatio) {
  188. const series = [];
  189. let sumValue = 0;
  190. let startValue = 0;
  191. let endValue = 0;
  192. const legendData = [];
  193. const k =
  194. typeof internalDiameterRatio !== 'undefined'
  195. ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
  196. : 1 / 3;
  197. // 为每一个饼图数据,生成一个 series-surface 配置
  198. for (let i = 0; i < pieData.length; i += 1) {
  199. sumValue += pieData[i].value;
  200. const seriesItem = {
  201. name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
  202. type: 'surface',
  203. parametric: true,
  204. wireframe: {
  205. show: false,
  206. },
  207. pieData: pieData[i],
  208. pieStatus: {
  209. selected: false,
  210. hovered: false,
  211. k: k,
  212. },
  213. itemStyle:{}
  214. };
  215. if (typeof pieData[i].itemStyle !== 'undefined') {
  216. const itemStyle :any= {};
  217. if (typeof pieData[i].itemStyle.color !== 'undefined') {
  218. itemStyle.color = pieData[i].itemStyle.color;
  219. }
  220. if (typeof pieData[i].itemStyle.opacity !== 'undefined') {
  221. itemStyle.opacity = pieData[i].itemStyle.opacity;
  222. }
  223. seriesItem.itemStyle = itemStyle;
  224. }
  225. series.push(seriesItem);
  226. }
  227. // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
  228. // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
  229. for (let i = 0; i < series.length; i += 1) {
  230. endValue = startValue + series[i].pieData.value;
  231. series[i].pieData.startRatio = startValue / sumValue;
  232. series[i].pieData.endRatio = endValue / sumValue;
  233. console.log(series[i].pieData.startRatio,
  234. series[i].pieData.endRatio,
  235. false,
  236. false,
  237. k,
  238. series[i].pieData.value)
  239. series[i].parametricEquation = this.getParametricEquation(
  240. series[i].pieData.startRatio,
  241. series[i].pieData.endRatio,
  242. false,
  243. false,
  244. k,
  245. 25//高度
  246. );
  247. startValue = endValue;
  248. legendData.push(series[i].name);
  249. }
  250. return series;
  251. }

html代码:

<div  id="option" echarts [options]="option1"  style="width:100%;height:100%"></div>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/105345
推荐阅读