3D饼图堆叠

描述:当前是关于Echarts图表中的 饼图 示例。
 
            
// 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
function getParametricEquation(startRatio, endRatio, k, h) {

    let startRadian = startRatio * Math.PI * 2;
    let endRadian = endRatio * Math.PI * 2;

    // 返回曲面参数方程
    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 Math.cos(startRadian) * (1 + Math.cos(v) * k);
            }
            if (u > endRadian) {
                return Math.cos(endRadian) * (1 + Math.cos(v) * k);
            }
            return Math.cos(u) * (1 + Math.cos(v) * k);
        },

        y: function (u, v) {
            if (u < startRadian) {
                return Math.sin(startRadian) * (1 + Math.cos(v) * k);
            }
            if (u > endRadian) {
                return Math.sin(endRadian) * (1 + Math.cos(v) * k);
            }
            return Math.sin(u) * (1 + Math.cos(v) * k);
        },

        z: function (u, v) {
            if (u < -Math.PI * 0.5) {
                return h;
            }
            if (u > Math.PI * 2.5) {
                return Math.sin(u) + h;
            }
            return Math.sin(v) > 0 ? 0 + h : 1 + h;
        },
    };
}

// 生成模拟 3D 饼图的配置项
function getPie3D(pieData, internalDiameterRatio) {
    let series = [];
    let sumValue = 0;
    let startValue = 0;
    let endValue = 0;
    let legendData = [];
    let k = 1 - internalDiameterRatio;

    // 为每一个饼图数据,生成一个 series-surface 配置
    for (let i = 0; i < pieData.length; i++) {
        sumValue += pieData[i].value;

        let seriesItem = {
            name: pieData[i].name,
            type: 'surface',
            parametric: true,
            wireframe: {
                show: false,
            },
            pieData: pieData[i],
            pieStatus: {
                selected: false,
                hovered: false,
                k: 1 / 10,
            },
            itemStyle: pieData[i].itemStyle
        };
        series.push(seriesItem);
    }
    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
    for (let i = 0; i < series.length; i++) {

        series[i].pieData.startRatio = 0;
        series[i].pieData.endRatio = series[i].pieData.value / sumValue;
        // series[i].pieData.endRatio = 1- 0.2 * (i+1);
        console.log(series[i].pieData.endRatio)
        series[i].parametricEquation = getParametricEquation(
            series[i].pieData.startRatio,
            series[i].pieData.endRatio,
            k,
            i
        );
        legendData.push(series[i].name);
    }

    series.push({
        name: 'mouseoutSeries',
        type: 'surface',
        parametric: true,
        wireframe: {
            show: false,
        },
        itemStyle: {
            opacity: 0
        },
        parametricEquation: {
            u: {
                min: 0,
                max: Math.PI * 2,
                step: Math.PI / 20,
            },
            v: {
                min: 0,
                max: Math.PI,
                step: Math.PI / 20,
            },
            x: function (u, v) {
                return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2;
            },
            y: function (u, v) {
                return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2;
            },
            z: function (u, v) {
                return 0;
            },
        },
    });
    // 准备待返回的配置项,把准备好的 legendData、series 传入。
    let option = {
        animation: true,

        legend: {
            textStyle: {
                fontSize: 18,
            },
            data: legendData,
            formatter: (params) => {
                return params;
            },
        },
        xAxis3D: {},
        yAxis3D: {},
        zAxis3D: {},
        tooltip: {
            formatter: params => {
                if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
                    return `${params.seriesName}:${option.series[params.seriesIndex].pieData.value}`;
                }
            },
            textStyle: {
                fontSize: 20
            },
        },
        labelLine: {
            show: true,
            lineStyle: {
                color: '#7BC0CB',
            },
        },
        label: {
            show: true,
            position: 'outside',
            formatter: '{b} \n{c} {d}%',
        },
        grid3D: {
            viewControl: {
                autoRotate: false,
            },
            left: 'center',
            width: '100%',
            show: false,
            boxHeight: 40,
        },
        series: series,
    };
    return option;
}

// 传入数据生成 option
option = getPie3D(
    [
        {
            name: '拥堵',
            value: 60,
            itemStyle: {
                color: '#10408AEE',
            },
        },
        {
            name: '路障',
            value: 20,
            itemStyle: {
                color: '#83BDFAEE',
            },
        },
        {
            name: '机占非',
            value: 15,
            itemStyle: {
                color: '#51E2DFEE',
            },
        },
        {
            name: '变道',
            value: 5,
            itemStyle: {
                color: '#299EFFEE',
            },
        }
    ],
    0.8
);
console.log(option)