• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

echarts开发的3D饼图

武飞扬头像
橘哥哥
帮助1

学新通

可以自动旋转,鼠标高亮选中

第一步

echarts-gl 装包

  1.  
    "echarts": "^5.2.0",
  2.  
    "echarts-gl": "^2.0.8",

我用的是上面两个版本,最开始因为echarts-gl 和echarts 版本不对应,报错找了半天,大坑,所以一定要下载对应的版本,建议直接复制到项目中package.json文件中,然后npm i 自动装包就行了

第二步

封装成了一个插件,可以直接复制到自己项目中查看,数据为模拟数据

  1.  
    <template>
  2.  
    <div style="width:100%;height:100%">
  3.  
    <div ref="basicDataPie" style="width:100%;height:100%"></div>
  4.  
    </div>
  5.  
    </template>
  6.  
    <script>
  7.  
    import * as echarts from "echarts";
  8.  
    import "echarts-gl";
  9.  
    export default {
  10.  
    data() {
  11.  
    return {
  12.  
    data: [
  13.  
    { name: "视频", value: 20, itemStyle: { color: "#0783FA" } },
  14.  
    { name: "作业", value: 18, itemStyle: { color: "#07D1FA" } },
  15.  
    { name: "考试", value: 22, itemStyle: { color: "#20E6A4" } },
  16.  
    { name: "课件", value: 15, itemStyle: { color: "#D18161" } },
  17.  
    { name: "实验", value: 25, itemStyle: { color: "#FFE649" } },
  18.  
    ],
  19.  
    };
  20.  
    },
  21.  
    mounted() {
  22.  
    this.$nextTick(() => {
  23.  
    this.echartsPie();
  24.  
    });
  25.  
    },
  26.  
    methods: {
  27.  
    echartsPie() {
  28.  
    let hoveredIndex = "";
  29.  
    let chartDom = this.$refs["basicDataPie"];
  30.  
    let myChart = echarts.init(chartDom);
  31.  
    const getPie3D = (pieData, internalDiameterRatio) => {
  32.  
    //internalDiameterRatio:透明的空心占比
  33.  
    let series = [];
  34.  
    let sumValue = 0;
  35.  
    let startValue = 0;
  36.  
    let endValue = 0;
  37.  
    let k = 1;
  38.  
    pieData.sort((a, b) => {
  39.  
    return b.value - a.value;
  40.  
    });
  41.  
    // 为每一个饼图数据,生成一个 series-surface 配置
  42.  
    for (let i = 0; i < pieData.length; i ) {
  43.  
    sumValue = pieData[i].value;
  44.  
    let seriesItem = {
  45.  
    name:
  46.  
    typeof pieData[i].name === "undefined"
  47.  
    ? `series${i}`
  48.  
    : pieData[i].name,
  49.  
    type: "surface",
  50.  
    parametric: true,
  51.  
    wireframe: {
  52.  
    show: false,
  53.  
    },
  54.  
    pieData: pieData[i],
  55.  
    pieStatus: {
  56.  
    selected: false,
  57.  
    hovered: false,
  58.  
    k: k,
  59.  
    },
  60.  
    radius: "50%",
  61.  
    center: ["10%", "10%"],
  62.  
    };
  63.  
     
  64.  
    if (typeof pieData[i].itemStyle != "undefined") {
  65.  
    let itemStyle = {};
  66.  
    typeof pieData[i].itemStyle.color != "undefined"
  67.  
    ? (itemStyle.color = pieData[i].itemStyle.color)
  68.  
    : null;
  69.  
    typeof pieData[i].itemStyle.opacity != "undefined"
  70.  
    ? (itemStyle.opacity = pieData[i].itemStyle.opacity)
  71.  
    : null;
  72.  
    seriesItem.itemStyle = itemStyle;
  73.  
    }
  74.  
    series.push(seriesItem);
  75.  
    }
  76.  
     
  77.  
    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
  78.  
    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
  79.  
    for (let i = 0; i < series.length; i ) {
  80.  
    endValue = startValue series[i].pieData.value;
  81.  
    series[i].pieData.startRatio = startValue / sumValue;
  82.  
    series[i].pieData.endRatio = endValue / sumValue;
  83.  
    series[i].parametricEquation = getParametricEquation(
  84.  
    series[i].pieData.startRatio,
  85.  
    series[i].pieData.endRatio,
  86.  
    false,
  87.  
    false,
  88.  
    k,
  89.  
    series[i].pieData.value
  90.  
    );
  91.  
    startValue = endValue;
  92.  
    }
  93.  
    let boxHeight = getHeight3D(series, 15); //通过传参设定3d饼/环的高度,26代表26px
  94.  
    // 准备待返回的配置项,把准备好的 legendData、series 传入。
  95.  
    let option = {
  96.  
    backgroundColor: "#fff",
  97.  
    tooltip: {
  98.  
    backgroundColor: "#fff",
  99.  
    formatter: (params) => {
  100.  
    if (
  101.  
    params.seriesName !== "mouSEO((Search Engine Optimization))utSeries" &&
  102.  
    params.seriesName !== "pie3d"
  103.  
    ) {
  104.  
    let bfb = (
  105.  
    (option.series[params.seriesIndex].pieData.endRatio -
  106.  
    option.series[params.seriesIndex].pieData.startRatio) *
  107.  
    100
  108.  
    ).toFixed(2);
  109.  
    return (
  110.  
    `${params.seriesName}<br/>`
  111.  
    `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>`
  112.  
    `${bfb}%`
  113.  
    );
  114.  
    }
  115.  
    },
  116.  
    },
  117.  
    legend: {
  118.  
    bottom: "3%",
  119.  
    itemGap: 20,
  120.  
    icon: "path://M0,12L12,12C12,5.37258,6.62742,0,0,0L0,12Z",
  121.  
    },
  122.  
    title: {
  123.  
    text: "课程总课时:68",
  124.  
    left: "left",
  125.  
    top: "2%",
  126.  
    textStyle: {
  127.  
    fontWeight: 500,
  128.  
    fontSize: 16,
  129.  
    color: "#3D3D3D",
  130.  
    },
  131.  
    },
  132.  
    xAxis3D: {
  133.  
    min: -1,
  134.  
    max: 1,
  135.  
    },
  136.  
    yAxis3D: {
  137.  
    min: -1,
  138.  
    max: 1,
  139.  
    },
  140.  
    zAxis3D: {
  141.  
    min: -1,
  142.  
    max: 1,
  143.  
    },
  144.  
    grid3D: {
  145.  
    show: false,
  146.  
    boxHeight: boxHeight, //圆环的高度
  147.  
    left: 0,
  148.  
    top: 0, //3d饼图的位置
  149.  
    viewControl: {
  150.  
    //3d效果可以放大、旋转等,请自己去查看官方配置
  151.  
    alpha: 25, //角度
  152.  
    distance: 250, //调整视角到主体的距离,类似调整zoom
  153.  
    rotateSensitivity: 0, //设置为0无法旋转
  154.  
    zoomSensitivity: 0, //设置为0无法缩放
  155.  
    panSensitivity: 0, //设置为0无法平移
  156.  
    autoRotate: true, //自动旋转
  157.  
    },
  158.  
    },
  159.  
    series: series,
  160.  
    };
  161.  
    return option;
  162.  
    };
  163.  
     
  164.  
    //获取3d丙图的最高扇区的高度
  165.  
    const getHeight3D = (series, height) => {
  166.  
    series.sort((a, b) => {
  167.  
    return b.pieData.value - a.pieData.value;
  168.  
    });
  169.  
    return (height * 15) / series[0].pieData.value;
  170.  
    };
  171.  
     
  172.  
    // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
  173.  
    const getParametricEquation = (
  174.  
    startRatio,
  175.  
    endRatio,
  176.  
    isSelected,
  177.  
    isHovered,
  178.  
    k,
  179.  
    h
  180.  
    ) => {
  181.  
    // 计算
  182.  
    let midRatio = (startRatio endRatio) / 2;
  183.  
    let startRadian = startRatio * Math.PI * 2;
  184.  
    let endRadian = endRatio * Math.PI * 2;
  185.  
    let midRadian = midRatio * Math.PI * 2;
  186.  
    // 如果只有一个扇形,则不实现选中效果。
  187.  
    if (startRatio === 0 && endRatio === 1) {
  188.  
    isSelected = false;
  189.  
    }
  190.  
    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
  191.  
    k = typeof k !== "undefined" ? k : 1 / 3;
  192.  
    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
  193.  
    let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  194.  
    let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
  195.  
    // 计算高亮效果的放大比例(未高亮,则比例为 1)
  196.  
    let hoverRate = isHovered ? 1.05 : 1;
  197.  
    // 返回曲面参数方程
  198.  
    return {
  199.  
    u: {
  200.  
    min: -Math.PI,
  201.  
    max: Math.PI * 3,
  202.  
    step: Math.PI / 32,
  203.  
    },
  204.  
    v: {
  205.  
    min: 0,
  206.  
    max: Math.PI * 2,
  207.  
    step: Math.PI / 20,
  208.  
    },
  209.  
    x: function (u, v) {
  210.  
    if (u < startRadian) {
  211.  
    return (
  212.  
    offsetX
  213.  
    Math.cos(startRadian) * (1 Math.cos(v) * k) * hoverRate
  214.  
    );
  215.  
    }
  216.  
    if (u > endRadian) {
  217.  
    return (
  218.  
    offsetX
  219.  
    Math.cos(endRadian) * (1 Math.cos(v) * k) * hoverRate
  220.  
    );
  221.  
    }
  222.  
    return offsetX Math.cos(u) * (1 Math.cos(v) * k) * hoverRate;
  223.  
    },
  224.  
    y: function (u, v) {
  225.  
    if (u < startRadian) {
  226.  
    return (
  227.  
    offsetY
  228.  
    Math.sin(startRadian) * (1 Math.cos(v) * k) * hoverRate
  229.  
    );
  230.  
    }
  231.  
    if (u > endRadian) {
  232.  
    return (
  233.  
    offsetY
  234.  
    Math.sin(endRadian) * (1 Math.cos(v) * k) * hoverRate
  235.  
    );
  236.  
    }
  237.  
    return offsetY Math.sin(u) * (1 Math.cos(v) * k) * hoverRate;
  238.  
    },
  239.  
    z: function (u, v) {
  240.  
    if (u < -Math.PI * 0.5) {
  241.  
    return Math.sin(u);
  242.  
    }
  243.  
    if (u > Math.PI * 2.5) {
  244.  
    return Math.sin(u) * h * 0.1;
  245.  
    }
  246.  
    return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
  247.  
    },
  248.  
    };
  249.  
    };
  250.  
     
  251.  
    let option = getPie3D(this.data, 0.8);
  252.  
    //是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption
  253.  
    option.series.push({
  254.  
    // name: "pie3d",
  255.  
    type: "pie",
  256.  
    label: {
  257.  
    show: false,
  258.  
    position: "inside",
  259.  
    formatter: "{c}%",
  260.  
    },
  261.  
    // startAngle: -25, //起始角度,支持范围[0, 360]。
  262.  
    clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
  263.  
    radius: ["65%", "65%"],
  264.  
    center: ["55%", "48%"], //指示线的位置
  265.  
    itemStyle: {
  266.  
    opacity: 0,
  267.  
    },
  268.  
    });
  269.  
    option && myChart.setOption(option);
  270.  
     
  271.  
    myChart.on("mouSEO((Search Engine Optimization))ver", function (params) {
  272.  
    // 准备重新渲染扇形所需的参数
  273.  
    let isSelected;
  274.  
    let isHovered;
  275.  
    let startRatio;
  276.  
    let endRatio;
  277.  
    let k;
  278.  
    let i;
  279.  
     
  280.  
    // 如果触发 mouSEO((Search Engine Optimization))ver 的扇形当前已高亮,则不做操作
  281.  
    if (hoveredIndex === params.seriesIndex) {
  282.  
    return;
  283.  
     
  284.  
    // 否则进行高亮及必要的取消高亮操作
  285.  
    } else {
  286.  
    // 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
  287.  
    if (hoveredIndex !== "") {
  288.  
    // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
  289.  
    isSelected = option.series[hoveredIndex].pieStatus.selected;
  290.  
    isHovered = false;
  291.  
    startRatio = option.series[hoveredIndex].pieData.startRatio;
  292.  
    endRatio = option.series[hoveredIndex].pieData.endRatio;
  293.  
    k = option.series[hoveredIndex].pieStatus.k;
  294.  
    i =
  295.  
    option.series[hoveredIndex].pieData.value ===
  296.  
    option.series[0].pieData.value
  297.  
    ? 35
  298.  
    : 10;
  299.  
    // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
  300.  
    option.series[hoveredIndex].parametricEquation =
  301.  
    getParametricEquation(
  302.  
    startRatio,
  303.  
    endRatio,
  304.  
    isSelected,
  305.  
    isHovered,
  306.  
    k,
  307.  
    i
  308.  
    );
  309.  
    option.series[hoveredIndex].pieStatus.hovered = isHovered;
  310.  
     
  311.  
    // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
  312.  
    hoveredIndex = "";
  313.  
    }
  314.  
     
  315.  
    // 如果触发 mouSEO((Search Engine Optimization))ver 的扇形不是透明圆环,将其高亮(对 option 更新)
  316.  
    if (
  317.  
    params.seriesName !== "mouSEO((Search Engine Optimization))utSeries" &&
  318.  
    option.series[params.seriesIndex].pieStatus
  319.  
    ) {
  320.  
    // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
  321.  
    isSelected = option.series[params.seriesIndex].pieStatus.selected;
  322.  
    isHovered = true;
  323.  
    startRatio = option.series[params.seriesIndex].pieData.startRatio;
  324.  
    endRatio = option.series[params.seriesIndex].pieData.endRatio;
  325.  
    k = option.series[params.seriesIndex].pieStatus.k;
  326.  
     
  327.  
    // 对当前点击的扇形,执行高亮操作(对 option 更新)
  328.  
    option.series[params.seriesIndex].parametricEquation =
  329.  
    getParametricEquation(
  330.  
    startRatio,
  331.  
    endRatio,
  332.  
    isSelected,
  333.  
    isHovered,
  334.  
    k,
  335.  
    option.series[params.seriesIndex].pieData.value 5
  336.  
    );
  337.  
    option.series[params.seriesIndex].pieStatus.hovered = isHovered;
  338.  
     
  339.  
    // 记录上次高亮的扇形对应的系列号 seriesIndex
  340.  
    hoveredIndex = params.seriesIndex;
  341.  
    }
  342.  
     
  343.  
    // 使用更新后的 option,渲染图表
  344.  
    myChart.setOption(option);
  345.  
    }
  346.  
    });
  347.  
    },
  348.  
    },
  349.  
    };
  350.  
    </script>

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgbhjhk
系列文章
更多 icon
同类精品
更多 icon
继续加载