echart之饼图 3D效果

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Echarts Demo</title>
    <script src="../echart/echarts.min.js"></script><!-- echart官网下载 -->
    <script src="../echart/echarts-gl.min.js"></script><!-- echart官网下载 -->
    <script src="./echart-pie.js"></script><!-- 下方JavaScript文件 -->
</head>

<body>
    <div id="main" style="width: 600px;height:400px;"></div>
</body>
<script type="text/javascript">
    const optionsData = [
        {
            name: 'aa',
            value: 15,
            itemStyle: {
                color: '#5c7cfa',
                // opacity: 1,
            },
        },
        {
            name: 'cc',
            value: 15,
            itemStyle: {
                color: '#20c997',
                // opacity: 1,
            },
        },
        {
            name: 'bb',
            value: 23,
            itemStyle: {
                color: '#ff6b6b',
                // opacity: 1,
            },
        },
    ];
    const option = {
        legend: {
            show: true
        }
    }
    $echartPie('main', optionsData, option)
</script>

</html>

javascript

/** 使用示例
 *  const optionsData = [
        {
            name: 'aa',
            value: 15,
            itemStyle: {
                color: '#5c7cfa',
                // opacity: 1,
            },
        },
        {
            name: 'cc',
            value: 15,
            itemStyle: {
                color: '#20c997',
                // opacity: 1,
            },
        },
        {
            name: 'bb',
            value: 23,
            itemStyle: {
                color: '#ff6b6b',
                // opacity: 1,
            },
        },
    ];
    const option = {
        legend: {
            show: true
        }
    }
    $echartPie('main', optionsData, option)
 */

((window) => {
    let echartPie
    echartPie = function (selector, optionsData = [], setOption) {
        return echartPie.fn.init(selector, optionsData, setOption)
    }
    echartPie.fn = echartPie.prototype = {
        series: [],
        /**
         * 
         * @param {*} optionsData 系列选项内容
         * @param {*} optionCallback 回调函数
         */
        init(selector, optionsData = [], setOption) {
            if (Array.isArray(optionsData) && optionsData.length) {

                var myChart = echarts.init(document.getElementById(selector));
                this.series = this.getPie3D(optionsData, 0.8, 240, 28, 26, 0.5)
                this.series.push({
                    // name: 'pie2d',
                    // 显示每个块信息
                    // type: 'pie',
                    // label: {
                    //     opacity: 1,
                    //     fontSize: 13,
                    //     lineHeight: 20,
                    // },
                    // labelLine: {
                    //     length: 30,
                    //     length2: 30,
                    // },
                    startAngle: -30, //起始角度,支持范围[0, 360]。
                    clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
                    radius: ['20%', '50%'],
                    center: ['50%', '50%'],
                    data: optionsData,
                    itemStyle: {
                        opacity: 0,
                    },
                })
                // 默认配置,后面通过回调函数扩充配置
                const option = {
                    title: {
                        text: '3D 饼图',
                        x: 'center',
                        top: '20',
                        textStyle: {
                            color: '#fff',
                            fontSize: 22,
                        },
                    },
                    backgroundColor: 'transparent',
                    labelLine: {
                        show: false,
                        lineStyle: {
                            color: '#7BC0CB',
                        },
                    },
                    label: {
                        show: false,
                        position: 'outside',
                        formatter: '{b} \n{c} {d}%',
                    },
                    xAxis3D: {
                        min: -1,
                        max: 1,
                    },
                    yAxis3D: {
                        min: -1,
                        max: 1,
                    },
                    zAxis3D: {
                        min: -1,
                        max: 1,
                    },
                    grid3D: {
                        show: false,
                        boxHeight: 30, // 三维笛卡尔坐标系在三维场景中的高度
                        viewControl: {
                            alpha: 40,
                            beta: 40,
                            distance: 500, //调整视角到主体的距离,类似调整zoom
                            rotateSensitivity: 0, // 设置为0无法旋转
                            zoomSensitivity: 0, // 设置为0无法缩放
                            panSensitivity: 0, // 设置为0无法平移
                            autoRotate: true, // 自动旋转
                        },
                    },
                    series: this.series,
                }
                myChart && myChart.setOption({ ...option, ...setOption || {} });
            }
        },
        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;
                },
            };
        },
        getPie3D(pieData, internalDiameterRatio, distance, alpha, pieHeight, opacity = 1) {
            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,
                    },
                };
                if (typeof pieData[i].itemStyle !== 'undefined') {
                    const itemStyle = {};
                    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;
                series[i].parametricEquation = this.getParametricEquation(
                    series[i].pieData.startRatio,
                    series[i].pieData.endRatio,
                    false,
                    false,
                    k,
                    series[i].pieData.value
                );
                startValue = endValue;
                legendData.push(series[i].name);
            }
            return series;
        }
    }
    echartPie.fn.init.prototype = echartPie.fn;
    window.$echartPie = echartPie
})(window)
posted @ 2022-12-01 17:47  走我们钓鱼去  阅读(246)  评论(0编辑  收藏  举报