vue3.0 使用echarts与echarts-gl 实现3D饼图

效果

安装echarts

npm install echarts
npm install echarts-gl

3d饼图组件:

<template>
    <div style="width: 100%; height: 100%" ref="echart"></div>
</template>

<script setup>
import { reactive, ref, onMounted, watch } from 'vue'
import * as echarts from 'echarts'
import 'echarts-gl'

const boxHeight = ref([])
const legendData = ref([])
const echart = ref()

const props = defineProps({
    optionsData: []
})

const echartInit = () => {
    var myChart = echarts.init(echart.value)
    const series = getPie3D(props.optionsData, 0.7)
    series.push({
        center: ['10%', '90%'],
        name: 'pie2d',
        type: 'pie',
        label: {
        show: false,
        opacity: 1,
        fontSize: 12,
        lineHeight: 10,
        textStyle: {
            fontSize: 12,
            color: '#fff',
        },
        },
        labelLine: {
        length: 30,
        length2: 30,
        },
        startAngle: -30, //起始角度,支持范围[0, 360]。
        clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
        radius: ['40%', '60%'],
        //data: props.optionsData,
        data: props.optionsData.map(item => {
          item.itemStyle.opacity = 0
          return item
        }),

        itemStyle: {
        opacity: 0,
        
        }
    })
    // 准备待返回的配置项,把准备好的 legendData、series 传入。
    let option = {
        legend: {
        show: true,
        tooltip: {
            show: true,
        },
        orient: 'vertical',
        //data: ['待办', '已办', '未处理'],
        data: legendData.value,
        top: 'center',
        // 设置图例为矩形
        itemWidth: 14,   // 图例标记的宽度,默认为14
        itemHeight: 14,  // 图例标记的高度,默认为12
        itemStyle: {
            // 设置边框圆角,可以设置为 0 实现正方形
            borderRadius: 5
        },
        itemGap: 12,
        right: '2%',
        textStyle: {
            color: '#fff',
            fontSize: 12,
        },
        formatter: (param)=> {
            let item = legendData.value.filter(item => item.name == param)[0];
            let bfs = fomatFloat(item.value * 100, 2) + "%";
            let v = item.value2;
            //return `${item.name}  ${bfs}`;
            return `${item.name}  ${v}`;
        }
        },
        animation: true,
        tooltip: {
        formatter: (params) => {
            if (
            params.seriesName !== 'mouseoutSeries' &&
            params.seriesName !== 'pie2d'
            ) {
            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 + '台'
            }`
            }
        },
        textStyle: {
            fontSize: 12,
        },
        },
        title: {
        x: 'center',
        top: '20',
        textStyle: {
            color: '#fff',
            fontSize: 12,
        },
        },
        // backgroundColor: '#FFF',
        labelLine: {
        show: false,
        lineStyle: {
            color: '#7BC0CB',
        },
        normal: {
            show: false,
            length: 10,
            length2: 10,
        },
        },
        label: {
        show: false,
        position: 'outside',
        formatter: '{b} \n{d}%',
        textStyle: {
            color: '#fff',
            fontSize: '14px',
        },
        },
        xAxis3D: {
        min: -1,
        max: 1,
        },
        yAxis3D: {
        min: -1,
        max: 1,
        },
        zAxis3D: {
        min: -1,
        max: 1,
        },
        grid3D: {
        show: false,
        //boxHeight: 0.01,
        boxHeight: boxHeight.value,
        //top: '30%',
        bottom: '50%',
        left: '-18%',
        // environment: "rgba(255,255,255,0)",
        viewControl: {
            distance: 180,//这个数值越大图就越小
            alpha: 25,//倾斜角度
            beta: 60,//起始渲染角度
            autoRotate: false, // 自动旋转
            rotateSensitivity: 1,//旋转灵敏度,鼠标按住不放可进行角度偏移
            zoomSensitivity: 1,//缩放灵敏度,鼠标滚轮可修改大小
            panSensitivity: 0,// 平移操作的灵敏度,值越大越灵敏。默认为1,设置为0后无法平移。支持使用数组分别设置横向和纵向的平移灵敏度
        },
        },
        series: series,
    }
    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option)
    }
    
    function fomatFloat(num, n) {
    var f = parseFloat(num);
    if (isNaN(f)) {
        return false;
    }
    f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂   
    var s = f.toString();
    var rs = s.indexOf('.');
    //判定如果是整数,增加小数点再补0
    if (rs < 0) {
        rs = s.length;
        s += '.';
    }
    while (s.length <= rs + n) {
        s += '0';
    }
    return s;
}

// 获取3d饼图的最高扇区的高度
function getHeight3D(series, height) {
    series.sort((a, b) => {
        return (b.pieData.value - a.pieData.value);
    })
    return height * 25 / series[0].pieData.value;
}
function getParametricEquation(
    startRatio,
    endRatio,
    isSelected,
    isHovered,
    k,
    height,
) {

    // 计算
    let midRatio = (startRatio + endRatio) / 2

    let startRadian = startRatio * Math.PI * 2
    let endRadian = endRatio * Math.PI * 2
    let midRadian = midRatio * Math.PI * 2

    // 如果只有一个扇形,则不实现选中效果。
    if (startRatio === 0 && endRatio === 1) {
        isSelected = false
    }

    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
    k = typeof k !== 'undefined' ? k : 1 / 3

    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
    let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0
    let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0

    // 计算高亮效果的放大比例(未高亮,则比例为 1)
    let 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)
        }
        return Math.sin(v) > 0 ? 1 * height : -1
        },
    }
    }
    // 生成模拟 3D 饼图的配置项
    function getPie3D(pieData, internalDiameterRatio) {
    let series = []
    let sumValue = 0
    let startValue = 0
    let endValue = 0
    //let legendData = []

    let k = typeof internalDiameterRatio !== 'undefined' ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3

    pieData.sort((a, b) => {
        return (b.value - a.value);
    });

    // 为每一个饼图数据,生成一个 series-surface 配置
    for (let i = 0; i < pieData.length; i++) {
        sumValue += pieData[i].value
        let 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') {
        let itemStyle = {}
        typeof pieData[i].itemStyle.color != 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null
        typeof pieData[i].itemStyle.opacity != 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null
        seriesItem.itemStyle = itemStyle
        }
        series.push(seriesItem)
    }

    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
    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,
        false,
        false,
        k,
        series[i].pieData.value,
        )
        boxHeight.value = getHeight3D(series, 2);//通过传参设定3d饼/环的高度,26代表26px

        startValue = endValue

        //legendData.value.push(series[i].name)
        let bfb = fomatFloat(series[i].pieData.value / sumValue, 4);
        legendData.value.push({
        name: series[i].name,
        value: bfb,
        value2: series[i].pieData.value
    });
    }
    return series
    }

watch(
    () => [props.optionsData],
    () => {
        echartInit()
    }
)

onMounted(() => {
    echartInit()
})


</script>

vue中的使用:

<My3DPie :optionsData="optionsData" />

vue的js引入组件

// 传入数据生成 option
         const optionsData = ref([
            {
              name: '饮料',
              value: 36,
              itemStyle: {
                opacity: 0.8,
                color: '#14EC92',
              },
            },
            {
              name: '小食品',
              value: 29,
              itemStyle: {
                opacity: 0.8,
                color: '#42A2D8',
              },
            }
            
          ])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/875745.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

质量追溯管理在MES系统中举足轻重

1. 质量追溯管理概述 质量追溯管理是指通过记录和监控产品在生产过程中的关键信息&#xff0c;确保在产品出现质量问题时&#xff0c;能够迅速追踪到问题源头&#xff0c;并采取相应措施的一种管理方法。在现代制造业中&#xff0c;质量追溯管理对于保障产品质量、提升客户满意…

关于 vue/cli 脚手架实现项目编译运行的源码解析

1.vue项目运行命令解析 在日常开发中&#xff0c;vue 项目通过vue-cli-service脚手架包将项目运行起来&#xff0c;常用的命令例如&#xff1a; npm run serve npm run build 上述执行命令实际一般对应为项目中 package.json 文件的 scripts属性中编写的脚本命令&#xff0c;在…

Python 课程5-NumPy库

在数据处理和科学计算中&#xff0c;NumPy 是一个非常强大且基础的库。除了基本的创建数组功能之外&#xff0c;NumPy 提供了许多强大的函数和方法&#xff0c;用于执行高级的矩阵运算、统计分析、逻辑操作等。以下是一些常用且非常有用的 NumPy 指令&#xff0c;涵盖了创建数组…

java: 程序包org.junit.jupiter.api不存在

明明idea没有报错&#xff0c;引用包也没问题&#xff0c;为啥提示java: 程序包org.junit.jupiter.api不存在&#xff1f; 配置&#xff01;还TMD是配置&#xff01; 如果是引用包的版本不对或者其他&#xff0c;直接就是引用报错或者pom里面飘红了。 这个应该是把generat…

设置使用阿里云服务器DNS

由于云服务器是从腾讯云迁移到阿里云&#xff0c;然后使用ssl验证时一直无法使用dns验证&#xff0c;也无法创建三级域名&#xff0c;原来需要把阿里云服务器改成阿里云的dns使用 如果使用其他服务器DNS会下面会显示当前DNS服务器&#xff0c;

冯诺依曼体结构与系统

冯诺依曼结构 我们的计算机&#xff0c;以及服务器&#xff0c;还有我我们日常使用的洗衣机都遵循冯诺依曼体结构。 以我们日常使用qq聊天时举例&#xff0c;冯诺依曼体结构可以这样画 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成 输入单元…

基于SpringBoot+Vue+MySQL的美术馆管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 随着文化艺术产业的蓬勃发展&#xff0c;美术馆作为展示与传播艺术的重要场所&#xff0c;其管理工作变得日益复杂。为了提升美术馆的运营效率、优化参观体验并加强艺术品管理&#xff0c;我们开发了基于SpringBootVueMySQL的美…

SAP B1 营销单据 - 单据字段介绍(中)

背景 营销单据&#xff0c;SAP B1 中一群神秘的单据&#xff0c;在官方说明文档中并未指明【营销单据】范围&#xff0c;却经常使用这一说法。它们结构相似&#xff0c;在 用户定义字段(UDF) 功能里统一受【营销单据】部分增加字段的影响&#xff0c;可以相互复制&#xff08;…

POI生成Excel文件增加数据验证(下拉序列)

POI版本为5.2.2 正常的如果不超过255字符的数据验证可以参照如下代码&#xff1a; /*** <p>设置某列的数据验证</p>* param Sheet 作用于哪一个sheet* param colIndex 需要增加数据验证的列的索引* String[] names 数据验证的序列&#xff0c;就是excel下拉列表的内…

codesys将自定义的功能块或者函数保存到本地库

将通过ST代码实现的自定义功能保存到codesys的本地库&#xff0c;其他project可以直接实现调用。提高灵活性和效率。 1、创建库工程 这里可能会提示涉及个别库没有安装或版本更新&#xff0c;根据提示安装对应库或更新即可。 2、添加功能块和函数 3、编写功能块和函数的参数定…

【Linux】查看操作系统开机时初始化的驱动模块列表的一个方法

这个方法是摸索出来的&#xff0c;也不一定对&#xff1a; 1、驱动层module_init(module_init_function)作为模块初始化&#xff0c;并且提供模块内部初始化的函数名&#xff1b; 2、找到所有驱动目录drivers下所有module_init(module_init_function)&#xff0c;在内核6.9.0…

js 深入理解生成器

目录 概述1 . 生成器基础2. 与普通函数的区别3. 通过 yield 中断执行3.1 yield 是干嘛的&#xff1f;3.2 yield 和 return 的区别3.3 每个生成器对象作用域都是独立的3.4 yeild 的使用位置3.5 生成器对象作为可迭代对象3.6 使用 yield 实现输入和输出3.6.1 yield实现输入3.6.1 …

4G物联网智能电表是什么?什么叫4G物联网智能电表?

4G物联网智能电表是一种结合了4G无线通信技术的新型电能计量设备&#xff0c;用于实时采集和传输用户的用电数据。它通过集成现代信息技术和电力电子技术&#xff0c;不仅能够精确测量电力消耗&#xff0c;还能实现远程数据传输、数据分析、远程控制等多种功能。本文将详细介绍…

【运维监控】influxdb 2.0+grafana 监控java 虚拟机以及方法耗时情况(2)

运维监控系列文章入口&#xff1a;【运维监控】系列文章汇总索引 文章目录 四、grafana集成influxdb监控java 虚拟机以及方法耗时情况1、添加grafana数据源2、添加grafana的dashboard1&#xff09;、选择新建dashboard方式2&#xff09;、导入dashboard 3、验证 关于java应用的…

CSS学习17--CSS3 过渡、2D变形、3D变形、动画

CSS3 过渡、2D变形、3D变形、动画 一、过渡二、2D变形 transform1.移动 translate2.缩放 scale3. 旋转 rotate4. 倾斜 skew 三、3D变形1. rotateX&#xff08;&#xff09;rotateY&#xff08;&#xff09; rotateZ&#xff08;&#xff09;2. 体会透视 perspective3. translat…

[数据集][目标检测]车油口挡板开关闭合检测数据集VOC+YOLO格式138张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;138 标注数量(xml文件个数)&#xff1a;138 标注数量(txt文件个数)&#xff1a;138 标注类别…

CleanMyMac X2024破解版mac电脑清理工具

今天&#xff0c;我要跟大家分享一个让我彻底告别电脑卡顿的秘密武器——CleanMyMac X。这不仅仅是一款普通的清理工具&#xff0c;它是你电脑的私人健身教练&#xff0c;让电脑焕发青春活力&#xff01; CleanMyMac直装官方版下载地址&#xff1a; http://wm.makeding.com/i…

【通用分割模型】SAM 2论文翻译

文章目录 摘要1 引言2 相关工作3 任务&#xff1a;可提示视觉分割4 模型5 数据5.1 数据引擎5.2 SA-V数据集 6 零样本实验6.1 视频任务6.1.1 提示视频分割6.1.2 半监督视频对象分割6.1.3 公平性评估 6.2 图像任务 7 与半监督VOS的最新技术的比较8 数据和模型消融8.1 数据消融8.2…

JavaSE篇之内部类和图书系统

1.内部类(类中类) 在Java中&#xff0c;将一个类定义在另一个类内部&#xff0c;前者称为内部类&#xff0c;后者称为外部类。 注意事项&#xff1a; 1. 1.静态内部类&#xff08;被static修饰的内部类&#xff09; 1.在静态内部类的方法中不能直接引用外部类的成员变量&…

手把手教你捏一个自己的Agent

01 前言 Modelscope AgentFabric是一个基于ModelScope-Agent的交互式智能体应用&#xff0c;用于方便地创建针对各种现实应用量身定制智能体&#xff0c;目前已经在生产级别落地。 AgentFabric围绕可插拔和可定制的LLM构建&#xff0c;并增强了指令执行、额外知识检索和利用…