<template>
    <div class="pie-3d">
        <div :id="domId" :style="{ width: w, height: h }"></div>
    </div>
</template>

<script setup>
import { ref, reactive, inject, defineProps, defineEmits } from 'vue';
import { onMounted } from 'vue';
import 'echarts-gl';

const props = defineProps({
    id: String,
    w: {
        type: Number,
        default: 200
    },
    h: {
        type: Number,
        default: 200
    },
    title: {
        type: String,
        default: '饼状图'
    },
    data: {
        type: Array,
        default: []
    }
});
const emits = defineEmits(['click']);
const echarts = inject('echarts');
const domId = ref(props.id);
const w = ref(`${props.w}px`);
const h = ref(`${props.h}px`);

const getParametricEquation = (startRatio, endRatio) => {
    let midRatio = (startRatio + endRatio) / 2;
    let startRadian = startRatio * Math.PI * 2;
    let endRadian = endRatio * Math.PI * 2;
    let midRadian = midRatio * Math.PI * 2;
    let offsetX = 0;
    let offsetY = 0;
    let offsetZ = 0;
    let tmp;
    return {
        u: {
            min: 0,
            max: Math.PI * 2,
            step: Math.PI / 250,
        },
        v: {
            min: 0,
            max: Math.PI,
            step: Math.PI / 50,
        },
        x: function (u, v) {
            if (midRatio < 0.5) {
                if (u < startRadian || u > midRadian + Math.PI) {
                    tmp =
                        u - Math.PI - midRadian < 0
                            ? u + Math.PI - midRadian
                            : u - Math.PI - midRadian;
                    return (
                        offsetX +
                        (Math.sin(startRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
                if (u > endRadian && u < midRadian + Math.PI) {
                    tmp = midRadian + Math.PI - u;
                    return (
                        offsetX +
                        (Math.sin(endRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
            } else {
                if (u < startRadian && u > midRadian - Math.PI) {
                    tmp = u + Math.PI - midRadian;
                    return (
                        offsetX +
                        (Math.sin(startRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
                if (u > endRadian || u < midRadian - Math.PI) {
                    tmp =
                        midRadian - Math.PI - u < 0
                            ? midRadian + Math.PI - u
                            : midRadian - Math.PI - u;
                    return (
                        offsetX +
                        (Math.sin(endRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
            }
            return offsetX + Math.sin(v) * Math.sin(u);
        },
        y: function (u, v) {
            if (midRatio < 0.5) {
                if (u < startRadian || u > midRadian + Math.PI) {
                    tmp =
                        u - Math.PI - midRadian < 0
                            ? u + Math.PI - midRadian
                            : u - Math.PI - midRadian;
                    return (
                        offsetX +
                        (Math.cos(startRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
                if (u > endRadian && u < midRadian + Math.PI) {
                    tmp = midRadian + Math.PI - u;
                    return (
                        offsetX +
                        (Math.cos(endRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
            } else {
                if (u < startRadian && u > midRadian - Math.PI) {
                    tmp = u + Math.PI - midRadian;
                    return (
                        offsetX +
                        (Math.cos(startRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
                if (u > endRadian || u < midRadian - Math.PI) {
                    tmp =
                        midRadian - Math.PI - u < 0
                            ? midRadian + Math.PI - u
                            : midRadian - Math.PI - u;
                    return (
                        offsetX +
                        (Math.cos(endRadian) * tmp) /
                        (Math.PI - midRadian + startRadian)
                    );
                }
            }
            return offsetX + Math.sin(v) * Math.cos(u);
        },
        z: function (u, v) {
            return offsetZ + (Math.cos(v) > 0 ? 0.1 : -0.1);
        },
    };
}
// 生成模拟 3D 饼图的配置项
const getPie3D = (pieData) => {
    let series = [];
    let sumValue = 0;
    let startValue = 0;
    let endValue = 0;
    let legendData = [];
    for (let i = 0; i < pieData.length; i++) {
        sumValue += pieData[i].value;
        let seriesItem = {
            name: !pieData[i].name ? `series${i}` : pieData[i].name,
            type: "surface",
            parametric: true,
            wireframe: {
                show: false,
            },
            pieData: pieData[i],
            pieStatus: {
                selected: false,
                hovered: false,
            },
        };

        if (pieData[i].itemStyle) {
            let itemStyle = {};
            if (pieData[i].itemStyle.color) {
                itemStyle.color = pieData[i].itemStyle.color;
            }
            if (pieData[i].itemStyle.opacity) {
                itemStyle.opacity = pieData[i].itemStyle.opacity;
            }
            seriesItem.itemStyle = itemStyle;
        }
        series.push(seriesItem);
    }
    for (let i = 0; i < series.length; i++) {
        endValue = startValue + series[i].pieData.value;
        series[i].pieData.startRatio = startValue / sumValue;
        series[i].pieData.endRatio = endValue / sumValue;
        series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio);
        startValue = endValue;
        legendData.push(series[i].name);
    }
    let option = {
        legend: {
            show: true,
            type: 'scroll',
            orient: 'vertical',
            right: 60,
            top: 20,
            bottom: 20,
            textStyle: {
                color: '#FFF'
            },
            data: legendData,
        },
        tooltip: {
            formatter: (params) => {
                if (params.seriesName !== "mouseoutSeries") {
                    return `${params.seriesName}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>${option.series[params.seriesIndex].pieData.value}`;
                }
            },
        },
        xAxis3D: {
            min: -0.6,
            max: 0.6,
        },
        yAxis3D: {
            min: -0.6,
            max: 0.6,
        },
        zAxis3D: {
            min: -0.6,
            max: 0.6,
        },
        grid3D: {
            show: false,
            boxHeight: 100, // 厚度
            top: 0,
            left: -80,
            viewControl: {
                //3d效果可以放大、旋转等，请自己去查看官方配置
                alpha: 40, // 角度
                beta: 180, // 饼块开始位置角度
                rotateSensitivity: 0,
                zoomSensitivity: 0,
                panSensitivity: 0,
                autoRotate: false,
            },
            light: {
                main: {
                    color: "rgb(85, 84, 84)", // 主光源的颜色。
                    shadow: false, // 主光源是否投射阴影
                    alpha: 80, // 主光源绕 x 轴，即上下旋转的角度
                },
            },
        },
        series: series,
    };
    return option;
}

const dataSource = [
    {
        name: "啤酒",
        value: 15,
    },
    {
        name: "高粱酒",
        value: 33,
    },
    {
        name: "桃花酿",
        value: 66,
    },
    {
        name: "白酒",
        value: 13,
    },
];

const init = () => {
    // const colorList = ["#D98053", "#E2B062", "#5A9CF1", "#6ED3D3"];
    const colorList = [];
    const paramsList = props.data.map((item, index) => {
        return {
            ...item,
            shading: "realistic",
            itemStyle: {
                color: colorList[index],
            },
        };
    });
    let option = getPie3D(paramsList);
    var chart = echarts.init(document.getElementById(domId.value));
    chart.setOption(option);
    chart.on('click', (params) => {
        emits('click', {
            index: params.seriesIndex,
            name: props.data[params.seriesIndex].name,
            value: props.data[params.seriesIndex].value
        })
    })
}

onMounted(() => {
    init();
});

</script>

<style lang="stylus" scoped>

</style>