一颗努力的大土豆 2024-03-30 15:47 采纳率: 92.5%
浏览 314
已结题

vue+echarts,生成的3D饼图每部分和数据的位置对应不上怎么办?

vue+echarts,生成的3D饼图每部分和数据的位置对应不上怎么办?
图片展示
问题描述:每块颜色的部分和百分数的位置对应不上

img


代码展示

<template>
    <div class="chart-container">
        <div class="chart" :ref="refName" id="chart-panel"></div>
        <!-- 底座背景 -->
        <div class="bg"></div>
    </div>
</template>

<script>
import * as echarts from 'echarts';
require('echarts/theme/macarons') // echarts theme
import 'echarts-gl' // 3d图表库
import resize from './mixins/resize'
import { getPie3D, getParametricEquation } from '@/utils/chart.js' //工具类js,页面路径自己修改
const color1 = ["#00a8ff ", "#878ffa", "#3bedde", "#44da84"]
const color2 = ["#00a8ff", "#878ffa", "#3bedde", "#44da84", "#317bf6"]
export default {
    mixins: [resize],
    props: {
        className: {
            type: String,
            default: 'chart'
        },
        width: {
            type: String,
            default: '100%'
        },
        height: {
            type: String,
            default: '300px'
        },
        refName: {
            type: String,
            required: true,
            default: ''
        },
        chartData: {
            type: Array,
            required: true,
            default: []
        }
    },
    watch: {
        chartData: {
            deep: true,
            handler(val) {
                // 避免处理同一个数据地址引起无限监听
                const temVal = JSON.parse(JSON.stringify(val))
                this.setLabel(temVal);
                this.setOptions(temVal)
            }
        }
    },
    data() {
        return {
            statusChart: null,
            option: {}
        }
    },
    created() {
        this.setLabel(this.chartData)
    },
    mounted() {
        this.$nextTick(() => {
            this.initChart()
        })
    },
    beforeDestroy() {
        if (!this.chart) {
            return
        }
        this.chart.dispose()
        this.chart = null
    },
    methods: {
        // 初始化label样式
        setLabel(chartData) {
            chartData.forEach((item, index) => {
                item.itemStyle = {
                    color: item.color
                }
                item.label = {
                    normal: {
                        show: true,
                        color: item.color,
                        formatter: function (data) {
                            //let   a   =  data.name
                            let b = data.percent.toFixed(0) + "%"
                            //let   c   =   a + ' ' + b
                            return b
                        },
                        fontWeight: 900,
                        fontSize: 13,
                        color: '#64e7ff',
                    }
                }
                item.labelLine = {
                    normal: {
                        lineStyle: {
                            width: 1,
                            color: '#64e7ff',
                            type: 'dashed'//设置为虚线
                        }
                    }
                }
            })
        },
        initChart() {
            // 使用同一个组件时,需要动态给定ref,在窗口大小改变时都动态变化
            this[this.refName] = echarts.init(this.$refs[this.refName]);
            this.setOptions(this.chartData)
        },
        setOptions(chartData) {
            // 传入数据生成 option, 构建3d饼状图, 参数工具文件已经备注的很详细
            chartData ? this.option = getPie3D(chartData, 0, 240, 28, 26, 0.5) : ""
            this[this.refName].setOption(this.option)
            // 是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption
            this.option.series.push({
                name: "人员比例", //自己根据场景修改
                backgroundColor: 'transparent',
                type: 'pie',
                label: {
                    opacity: 1,
                    fontSize: 13,
                    lineHeight: 20
                },
                startAngle: -30, // 起始角度,支持范围[0, 360]。
                clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
                radius: ['30%', '50%'],
                center: ['50%', '45%'],
                data: chartData,
                itemStyle: {
                    opacity: 0 //这里必须是0,不然2d的图会覆盖在表面
                }
            })
            this[this.refName].setOption(this.option);
            // 添加图例配置
            /* this.option.legend = {
                show: true,
                orient: 'horizontal',
                left: 'center', // 水平居中
                bottom: '0px', // 调整底部距离
                data: chartData.map(item => item.name),
                itemWidth: 8, // 设置图例项的宽度
                itemHeight: 8, // 设置图例项的高度
                formatter: function (name) {
                    return name;
                }
            }; */

            // 更新图表配置
            this[this.refName].setOption(this.option);

        },
        // 自适应宽高
        // 使用同一个组件时,需要动态给定ref,在窗口大小改变时都动态变化
        changeSize(refName) {
            this[refName].resize();
        },
    }
}
</script>
<style lang="scss" scoped>
.chart-container {
    position: relative;
    width: 100%;
    height: 100%;
    //margin-bottom:15 px; /* 调整图表向上移动的距离,根据需要自行调整 */

    .chart {
        z-index: 1;
    }

    .chart,
    .bg {
        width: 100%;
        height: 100%;
    }

    .bg {
        position: absolute;
        width: 280px;
        height: 58%;
        bottom: 25px;
        left: 50%;
        z-index: 0;
        background: no-repeat center;
        background-image: url('../../assets/images/pie_bottom.png');
        background-size: 100% 100%;
        transform: translateX(-50%);
    }
}
</style>

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-03-30 15:47
    关注

    引自免费微信小程序:皆我百晓生

    在Vue+ECharts中,生成的3D饼图每个部分和数据的位置对应不上可能有以下几个原因:

    1. echarts配置错误:确保option.series数组的正确组成。在你的例子中,饼图由三个子系列组成,分别是“人员比例”、“品牌数量”和一个饼形图用于显示color1color2对应的百分比。这三者之间没有明确的数据依赖关系。你需要确保在饼图的相应位置(radius属性)插入正确的数据点(name字段),并且保证饼形图与数据相关的部分绘制正常。

    2. 饼形图的位置设置不准确:饼图中的每个部分都应该与数据点相对应。对于第一部分("人物比例"),根据你的图表数据,将其放入中心位置。对于第二部分("品牌数量"),它应该位于一个特定的圆心上,这可以通过在圆心处进行中心偏移实现。此外,饼图本身应该有一个合适的顶点,可以作为这三个部分的起点。

    3. 缩放方式不正确:确保您在图表配置选项中设置了scale-mode属性。通常情况下,scale-mode属性选择"x"时,绘图区域的缩放范围为垂直轴,且视图水平方向宽度以最大值显示。如果你看到的"男性比例"和"女性比例"位于不同的区域,可能是由于缩放模式的选择导致了不同数值之间的相互遮挡。

    4. 内存溢出或资源消耗过大:尝试减小图表实例的内存占用,比如通过在resize钩子函数中合并多行元素的逻辑来减少元素树的数量。同时,确保updateSize方法可以在窗口大小改变时更新图表大小,并保持其在用户界面的高度固定。

    5. .getPie3D.getParametricEquation工具包调用错误:这两个工具包提供了一个将三维坐标转换为二维数据并绘制图形的功能。但你并未提供这些工具的具体使用,因此我猜测它们的调用可能有误,导致数据或部分数据无法被正确转换并渲染到饼图中。确保这两个工具包在正确的工作区域内并正确地应用到你的需求上。

    以下是一个简单的示例,演示如何解决以上问题:

    1. 首先,我们需要在setup钩子函数中初始化饼图:
    initChart() {
        // 创建一个新的饼图实例
        const pie3D = echarts.init(this.$refs[this.refName]);
    
        // 绘制饼图
        const series = [
            // "人员比例"的数据点和渲染
            {
                name: "人员比例",
                type: "pie",
                radius: ["30%", "50%"],
                center: ["50%", "45%"],
                data: chartData.map(item => ({
                    name: item.name,
                    value: item.percent.toFixed(0) + "%",
                    itemStyle: {
                        color: item.color,
                        opacity: 0
                    }
                })),
                legend: {
                    show: true,
                    orient: 'vertical',
                    left: 'center',
                    bottom: '0px',
                    data: chartData.map(item => item.name),
                    itemWidth: 8,
                    itemHeight: 8,
                    formatter: function (name) {
                        return name;
                    }
                }
            }
        ];
    
        // 给已有的饼图添加饼形图
        this.getPie3D(series);
    
        // 将饼图关联到图表容器
        this.chartContainer.appendChild(pie3D);
    },
    
    1. 然后,我们使用resize钩子函数合并多个行元素以减少元素树的数量:
    resize() {
        const dataBeforeResize = this.chart.data.slice(0);
        const marginBeforeResize = this.chart.config.margin;
    
        this.chart.updateSize(
            {
                width: this.width,
                height: this.height,
                margin: {
                    top: 0,
                    right: 0,
                    bottom: 0,
                    left: 0,
                },
            },
            () => {
                // 将合并后的元素对象放入chart的新的数据链中
                this.chart.data = [...dataBeforeResize];
                this.chart.config.margin = {
                    top: marginBeforeResize.top + "px",
                    right: marginBeforeResize.right + "px",
                    bottom: marginBeforeResize.bottom + "px",
                    left: marginBeforeResize.left + "px",
                };
            }
        );
    }
    
    1. watch钩子函数中获取饼图和数据配置:
    watch: {
        chartData(newVal) {
            // 根据更改的chartData重新渲染饼图
            this.renderPieChart(newVal);
        }
    },
    
    1. 最后,我们定义饼图的标题、内边距和外边距:
    title() {
        const label = new Option("人员比例", "", "");
        label.type = "text";
        this.chart.data.forEach(item => {
            item.title = `${item.name}: ${item.value}%`;
        });
        this.chart.setOption(label);
    }
    
    barWidth() {
        const { width } = this.chart.config;
        return width / this.chart.data.length;
    }
    
    legendMarginLeft() {
        return this.chart.config.legend.left + "px";
    }
    
    legendMarginRight() {
        return this.chart.config.legend.right + "px";
    }
    

    这些步骤中,我们首先创建了一个饼图实例,然后通过合并多行元素的方法减少元素树的数量。接着,我们在resize钩子函数中更新元素尺寸,将合并后的数据对象添加到原有的数据链中,然后将图表的数据配置重置为原样,以保持当前工作环境下的数据映射关系。在watch钩子函数中,我们监控饼图和数据的变化,每当数据发生变化时就调用renderPieChart方法重新渲染饼图。

    注意,这段代码只展示了基本的饼图组件结构和方法,实际操作中还需要考虑诸如字体样式、3D效果、鼠标悬停事件、高度管理等细节。此外,您还需要根据实际情况对getPie3DparametricEquationgetColor工具包进行相应的调整以满足您的需求。例如,如果color1color2的配色方案不一致,您可能需要在工具包内部进行数据校验和色彩转化。如果有JavaScript深度学习模型支持,还可以尝试结合基于模型的颜色插值或替换算法。

    以上是生成3D饼图位置对应问题的基本解决方案,具体实施可能涉及到更多的步骤和变量处理。如果您需要更详细的代码示例或具体问题解决,请提供更具体的问题描述或相关代码片段,以便我能更好地为您提供帮助。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 7月17日
  • 已采纳回答 7月9日
  • 创建了问题 3月30日