当前位置:   article > 正文

vue项目基于D3js的3D饼图实现(一)_vue 3d饼图

vue 3d饼图

最终效果图如下,一个具有鼠标滑过提示框,图例联动,图例翻页的3D饼图

一、创建基本3D饼图展示

1、创建Pie3D.vue文件

  1. <template>
  2. <div>
  3. <p>D3JS实现的3D饼图</p>
  4. <div id="abc"></div>
  5. </div>
  6. </template>
  7. <script setup>
  8. import pie from '../utils/pie'
  9. import { onMounted, reactive } from 'vue';
  10. let config = reactive({
  11. color:["#0f7eee","#24Daff","#FFFF80","#caf982","#80DCff"]
  12. })
  13. //基础数据
  14. const salesData = [
  15. {label: "2023-05-01", value: 61, DWMC:'俩'},
  16. {label: "2023-05-02", value: 70, DWMC:'俩'},
  17. {label: "2023-05-03", value: 67, DWMC:'俩'},
  18. {label: "2023-05-04", value: 21, DWMC:'俩'},
  19. {label: "2023-05-05", value: 23, DWMC:'俩'},
  20. {label: "2023-05-06", value: 82, DWMC:'俩'},
  21. {label: "2023-05-06", value: 26, DWMC:'俩'},
  22. {label: "2023-05-06", value: 57, DWMC:'俩'}
  23. ];
  24. onMounted(() => {
  25. pie('#abc', 700, 400, salesData, 250, 200, 150, 100, 30, config)
  26. })
  27. </script>
  28. <style>
  29. /* 样式 */
  30. #abc{
  31. width: 700px;
  32. height: 400px;
  33. }
  34. </style>

2、在utils目录中创建pie.js文件 该文件就是渲染3D饼图的主文件

  1. import * as d3 from 'd3';
  2. import { pieInner, pieTop, pieOuter } from '../utils/renderUtils'
  3. /**
  4. * 生成3d饼图
  5. * @param {*} id :id唯一标识
  6. * @param {*} width :svg的宽
  7. * @param {*} height :svg的高
  8. * @param {*} data :要渲染的数据
  9. * @param {*} x :横向偏移量
  10. * @param {*} y :纵向偏移量
  11. * @param {*} rx :饼图的横向半径
  12. * @param {*} ry :饼图的纵向半径
  13. * @param {*} h :饼图的高度
  14. */
  15. export default function pie(id, width, height, data, x, y, rx, ry, h, config,ir=0){
  16. //先移除所有的svg
  17. d3.select(id).selectAll('svg').remove();
  18. //创建一个svg容器,用来存放饼图
  19. const pieSvg = d3
  20. .select(id)
  21. .append('svg')
  22. .attr('width','100%')
  23. .attr('height','100%');
  24. pieSvg.append('g').attr('id','pie_chart');
  25. //生成饼图数据
  26. const dataset = d3
  27. .pie()
  28. .sort(null)
  29. .value((d) => {
  30. return d.value
  31. })(data);
  32. // 获取上面插入的g
  33. const slices = d3
  34. .select('#pie_chart')
  35. .append('g')
  36. .attr('transform','translate(350,200)')
  37. .attr('class','slices')
  38. .style('cursor','pointer');
  39. //生成环形内曲面
  40. slices
  41. .selectAll('.innerSlice')
  42. .data(dataset)
  43. .enter()
  44. .append('path')
  45. .attr('class','innerSlice')
  46. .style('fill',(d,index) => {
  47. let colorIndex = index % config.color.length
  48. return d3.hsl(config.color[colorIndex]).darker(0.7)
  49. })
  50. .attr('d',d => {
  51. return pieInner(d, rx+0.5, ry+0.5, h, ir)
  52. });
  53. //上层2D平面
  54. slices.selectAll('.topSlice')
  55. .data(dataset)
  56. .enter()
  57. .append('path')
  58. .transition()
  59. .delay(0)
  60. .duration(500)
  61. .attrTween('d',(d) => {
  62. //动画效果
  63. let interpolate = d3.interpolate(d.startAngle, d.endAngle);
  64. return function(t){
  65. d.endAngle = interpolate(t);
  66. return pieTop(d, rx, ry, ir)
  67. }
  68. })
  69. .attr('class','topSlice')
  70. .style('fill',(d,index) => {
  71. let colorIndex = index % config.color.length
  72. return config.color[colorIndex]
  73. })
  74. .style('stroke',(d,index) => {
  75. let colorIndex = index % config.color.length
  76. console.log(config.color[colorIndex],'==config.color[colorIndex]')
  77. return config.color[colorIndex]
  78. })
  79. //侧面曲面
  80. slices.selectAll('.outerSlice')
  81. .data(dataset)
  82. .enter()
  83. .append('path')
  84. .transition()
  85. .delay(0)
  86. .duration(500)
  87. .attrTween('d',(d) => {
  88. //动画效果
  89. let interpolate = d3.interpolate(d.startAngle, d.endAngle);
  90. return function(t){
  91. d.endAngle = interpolate(t);
  92. return pieOuter(d, rx- 0.5, ry - 0.5, h)
  93. }
  94. })
  95. .attr('class','outerSlice')
  96. .style('fill',(d,index) => {
  97. let colorIndex = index % config.color.length
  98. return d3.hsl(config.color[colorIndex]).darker(0.7)
  99. });
  100. }

3、创建renderUtils.js文件里面包含渲染3D饼图的算法函数

  1. //生成内曲面
  2. export function pieInner(d,rx,ry,h,ir){
  3. const startAngle = d.startAngle < Math.PI ? Math.PI : d.startAngle;
  4. const endAngle = d.endAngle < Math.PI ? Math.PI : d.endAngle;
  5. const sx = ir * rx * Math.cos(startAngle);
  6. const sy = ir * ry * Math.sin(startAngle);
  7. const ex = ir * rx * Math.cos(endAngle);
  8. const ey = ir * ry * Math.sin(endAngle);
  9. const ret = [];
  10. ret.push(
  11. 'M',
  12. sx,
  13. sy,
  14. 'A',
  15. ir * rx,
  16. ir * ry,
  17. '0 0 1',
  18. ex,
  19. ey,
  20. 'L',
  21. ex,
  22. h + ey,
  23. 'A',
  24. ir * rx,
  25. ir * ry,
  26. '0 0 0',
  27. sx,
  28. h + sy,
  29. 'z'
  30. );
  31. return ret.join(' ');
  32. }
  33. // 生成饼图的顶部
  34. export function pieTop(d, rx, ry, ir) {
  35. if (d.endAngle - d.startAngle === 0) { return 'M 0 0'; }
  36. const sx = rx * Math.cos(d.startAngle);
  37. const sy = ry * Math.sin(d.startAngle);
  38. const ex = rx * Math.cos(d.endAngle);
  39. const ey = ry * Math.sin(d.endAngle);
  40. const ret = [];
  41. ret.push(
  42. 'M',
  43. sx,
  44. sy,
  45. 'A',
  46. rx,
  47. ry,
  48. '0',
  49. d.endAngle - d.startAngle > Math.PI ? 1 : 0,
  50. '1',
  51. ex,
  52. ey,
  53. 'L',
  54. ir * ex,
  55. ir * ey
  56. );
  57. ret.push(
  58. 'A',
  59. ir * rx,
  60. ir * ry,
  61. '0',
  62. d.endAngle - d.startAngle > Math.PI ? 1 : 0,
  63. '0',
  64. ir * sx,
  65. ir * sy,
  66. 'z'
  67. );
  68. return ret.join(' ');
  69. }
  70. // 外曲面算法
  71. export function pieOuter(d, rx, ry, h) {
  72. const startAngle = d.startAngle > Math.PI ? Math.PI : d.startAngle;
  73. const endAngle = d.endAngle > Math.PI ? Math.PI : d.endAngle;
  74. const sx = rx * Math.cos(startAngle);
  75. const sy = ry * Math.sin(startAngle);
  76. const ex = rx * Math.cos(endAngle);
  77. const ey = ry * Math.sin(endAngle);
  78. const ret = [];
  79. ret.push(
  80. 'M',
  81. sx,
  82. h + sy,
  83. 'A',
  84. rx,
  85. ry,
  86. '0 0 1',
  87. ex,
  88. h + ey,
  89. 'L',
  90. ex,
  91. ey,
  92. 'A',
  93. rx,
  94. ry,
  95. '0 0 0',
  96. sx,
  97. sy,
  98. 'z'
  99. );
  100. return ret.join(' ');
  101. }

文件运行结果如下,此时已经创建了基本的3D饼图

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

闽ICP备14008679号