echarts实现3D饼图

news2024/11/17 17:35:17

先看下最终效果

3d饼图旋转效果

实现思路

使用echarts-gl的曲面图(surface)类型
通过parametric绘制曲面参数实现3D效果

代码实现

<template>
    <div id="surfacePie"></div>
</template>
<script setup>
    import {onMounted} from 'vue'
    import * as echarts from "echarts";
    import "echarts-gl";
	// 图表数据
    const chartData = [
        { name: '性能测试',value: 134},
        { name: '安全',value: 56},
        { name: '功能',value: 57},
        { name: '代码',value: 11},
        { name: '易用性',value: 51}
    ]
    // 自定义颜色
    const colorList = [
        'rgba(23,122,219)',
        'rgba(219,129,2)',
        'rgba(113,74,219)',
        'rgba(12,255,246)',
        'rgba(37,26,231)',
        'rgba(219,91,23)',
    ]
    // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
    function getParametricEquation(startRatio, endRatio, k, h) {
        // 计算
        let startRadian = startRatio * Math.PI * 2;
        let endRadian = endRatio * Math.PI * 2;

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

        // 返回曲面参数方程
        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 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;
            },
        };
    }
    // 生成模拟 3D 饼图的配置项
    function getPie3D(pieData, internalDiameterRatio) {
        let series = [];
        let sumValue = 0; // 总值 计算比例用
        let startValue = 0;
        let endValue = 0;
        // 根据传入的内外径比例,计算饼图空心大小
        let k =
            typeof internalDiameterRatio !== 'undefined'
                ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
                : 1 / 3;

        // 为每一个饼图数据,生成一个 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]
            };
            // 为每一项设置颜色和透明度
            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,
                k,
                series[i].pieData.value
            );

            startValue = endValue;
        }

        // 准备待返回的配置项,把准备好的 legendData、series 传入。
        let option = {
            // 图例
            legend: {
                type:'scroll',
                pageIconSize: 12,
                icon: 'none', // 需求要显示实心点 提供类型没有 所以这个设置不显示
                data: pieData.map((dItem,dIndex) => {
                    return {
                        ...dItem,
                        // 设置单个图例项的文本样式
                        textStyle: {
                            rich: {
                                // 用富文本为每一个图例项画一个对应颜色的实心点
                                iconName: {
                                    width: 4,
                                    height: 4,
                                    borderRadius: 5,
                                    backgroundColor: colorList[dIndex],
                                },
                            }
                        },
                    }
                }),
                top: 'bottom',
                left: 'center',
                itemGap: 5,
                selectedMode: false, // 关闭图例选择
                width: '100%',
                //  统一设置图例的文本样式
                textStyle: {
                    color: '#fff',
                    fontSize: 12,
                    fontFamily: 'Source Han Sans CN',
                    rich: {
                        // 富文本统一设置 图例的样式
                        name: {
                            fontSize: 12,
                            padding: [0, 0, 0, 10],
                            width: 50,
                        },
                        percent: {
                            fontSize: 12,
                            padding: [0, 0, 0, 5],
                            width: 15,
                        },
                        unit: {
                            fontSize: 12,
                            padding: [0, 0, 0, 1]
                        }
                    }
                },
                // 格式化图例
                formatter: name => {
                    let obj = pieData.find(item => item.name === name);
                    let total = 0;
                    let target = obj.value
                    for (let i = 0; i < pieData.length; i++) {
                        total += Number(pieData[i].value);
                    }
                    const legendStyle = `{iconName|}{name|${name}}{percent|${((target / total) * 100).toFixed(0)}}{unit|%}`
                    return legendStyle
                }
            },
            xAxis3D: {},
            yAxis3D: {},
            zAxis3D: {},
            // 设置三维笛卡尔坐标系
            grid3D: {
                viewControl: {
                   autoRotate: true, // 自动旋转
                },
                left: 'center',
                top: '-8%',
                show: false, // 坐标系设置不显示
                boxHeight: 100,
                boxWidth: 150,
                boxDepth: 150,
            },
            series: series,
        };
        return option;
    }
 </script>

补充说明

  1. echarts版本5.51
  2. echarts-gl版本2.0.9
  3. vue版本3.4.29
  4. vite版本5.3.1

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kafka(三)Producer第二篇

一&#xff0c;生产者架构 生产者客户端由两个线程协调运行&#xff0c;分别为主线程和Sender线程&#xff08;发送线程&#xff09;。 主线程&#xff1a;KafkaProducer创建消息&#xff0c;通过拦截器、序列化器和分区器之后缓存到消息收集器RecordAccumulator中&#xff1b;…

Java面试八股之MySQL如何使用explain优化SQL和索引

MySQL如何使用explain优化SQL和索引 在MySQL中&#xff0c;EXPLAIN是一个非常有用的工具&#xff0c;用于分析和优化SQL查询。它可以帮助你理解查询执行计划&#xff0c;包括如何使用索引、表的连接方式、是否使用了临时表或文件排序等。以下是一些使用EXPLAIN来优化SQL查询和…

VBA经典应用69例应用5:使用VBA拆分窗格

《VBA经典应用69例》&#xff08;版权10178981&#xff09;&#xff0c;是我推出的第九套教程&#xff0c;教程是专门针对初级、中级学员在学习VBA过程中可能遇到的案例展开&#xff0c;这套教程案例众多&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以便…

卷积神经网络可视化的探索

文章目录 训练LeNet模型下载FashionMNIST数据训练保存模型 卷积神经网络可视化加载模型一个测试图像不同层对图像处理的可视化第一个卷积层的处理第二个卷积层的处理 卷积神经网络是利用图像空间结构的一种深度学习网络架构&#xff0c;图像在经过卷积层、激活层、池化层、全连…

防火墙详解(USG6000V)

0、防火墙组网模式 防火墙能够工作在三种模式下分别是路由模式、透明模式、旁路检测模式、混合模式 0.1、路由模式 路由模式&#xff1a;防火墙全部以第三层对外连接&#xff0c;即接口具有IP 地址。一般都用在防火墙是边界的场景下 防火墙需要的部署/配置&#xff1a; 接…

自动连点鼠标器是什么?好用的鼠标连点器分享

你听说过自动鼠标连点器吗&#xff1f;自动连点鼠标器是一种软件工具&#xff0c;用于自动模拟鼠标点击操作。这种工具可以设置为在特定位置和时间间隔内自动点击鼠标&#xff0c;减轻手动点击的负担。自动连点器通常可以在很多生活场景中帮助我们节省时间成本&#xff0c;今天…

OS Copilot测评

1.按照第一步管理重置密码时报错了,搞不懂为啥?本来应该跳转到给的那个实例的,我的没跳过去 2.下一步重置密码的很丝滑没问题 3安全组新增入库22没问题 很方便清晰 4.AccessKey 还能进行预警提示 5.远程连接,网速还是很快,一点没卡,下载很棒 6.替换的时候我没有替换<>括…

Python | Leetcode Python题解之第224题基本计算器

题目&#xff1a; 题解&#xff1a; class Solution:def calculate(self, s: str) -> int:ops [1]sign 1ret 0n len(s)i 0while i < n:if s[i] :i 1elif s[i] :sign ops[-1]i 1elif s[i] -:sign -ops[-1]i 1elif s[i] (:ops.append(sign)i 1elif s[i] …

嵌入式Linux系统编程 — 7.4 fork、vfork函数创建子进程

目录 1 父进程与子进程概念 2 fork创建子进程 3 系统调用 vfork()函数 4 vfork与 fork函数如何选择 1 父进程与子进程概念 进程与子进程是操作系统中的一个基本概念&#xff0c;用于描述进程之间的层级关系。下面是对这一概念的简要说明&#xff1a; 父进程&#xff1a;在…

线程池的合理使用

线程池的合理使用 一、简介二、为什么要使用线程池三、核心参数四、如何合理配置线程参数1.1 corePoolSize && maximumPoolSize1.2 Handler 拒绝策略1.2.1AbortPolicy&#xff1a;优势&#xff1a;劣势&#xff1a; 1.2.2 DiscardPolicy&#xff1a;优势&#xff1a;劣…

3Python的Pandas:数据选取

1.数据选取操作 1.1. 选取单列 df[Q1]df[Q2]1.2. 选取多列 df[[team,Q1]]df.loc[:,[team,Q1]]1.3.选择行 使用指定索引选择 df[df.indexAck]选择前n行 df[0:3]df.iloc[:10,:]1.4. 前n行&#xff0c;每隔m选择一个 df[0:10:3]1.5. 条件选择 df[df.Q1>90]df[(df.teamC…

linxu驱动入门基础课一(GPIO控制LED灯)基于RK3568

虽然GPIO控制LED 是最简单的linux驱动&#xff0c;但是是初学者入门必须跨过的门槛&#xff0c;里面很多基础知识点&#xff0c;有GPIO的控制原理&#xff0c;字符设备驱动&#xff0c;设备树&#xff0c;gpio和pinctrl子系统&#xff0c;内核模块原理等等&#xff0c;这些知识…

APP明暗主题设置

1.preference.xml 增加一个暗色主题 SwitchPreference 2.每个 Activity 的 setContentView 前面增加 setTheme SharedPreferences sharedPreferences PreferenceManager.getDefaultSharedPreferences(this); if (sharedPreferences.getBoolean("switch_dark_theme"…

Windows下编译OpenSSL静态库

目录 1. 版本与下载地址 2. 下载与安装VS2015 3. 下载与安装Perl 4. 测试ActivePerl是否安装正确 5. 下载OpenSSL 6. 编译32位OpenSSL静态库 6.1 解压openssl-1.0.2l.tar.gz 6.2 打开VS2015 x86本机工具命令提示符 6.3 输入命令进入到openssl的目录中 6.4 执行配置命…

加密与安全_密钥体系的三个核心目标之不可否认性解决方案

文章目录 Pre概述不可否认性数字签名&#xff08;Digital Signature&#xff09;证书是什么证书使用流程 PKICA证书层级多级证书证书链是如何完成认证的&#xff1f; 其他疑问1. Alice能直接获取Bob的公钥&#xff0c;是否还需要证书&#xff1f;2. 为什么即使能直接获取公钥也…

世界人工智能大会 | 江行智能大模型解决方案入选“AI赋能新型工业化创新应用优秀案例”

日前&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议在上海启幕。本次大会主题为“以共商促共享&#xff0c;以善治促善智”&#xff0c;汇聚了上千位全球科技、产业界领军人物&#xff0c;共同探讨大模型、数据、新型工业化等人工智能深度发展时代下的热点话题…

CLIP编码器调用时刚开始正常,然后输出全部变为NaN

碰到了这个问题&#xff1a;输入是正常的&#xff0c;输出全是NaN 网上办法不多&#xff0c;找了半天终于看到问题所在&#xff0c;但是没有说在哪里改的&#xff0c;故记录一下。 改一下模型精度就正常了&#xff0c;默认的是fp16&#xff0c;改为fp32即可 具体步骤如下&…

渲染引擎之ECS架构介绍

1.什么是ECS&#xff1f; 我们先简单地介绍一下什么是ECS&#xff1a; E -- Entity 实体&#xff0c;本质上是存放组件的容器C -- Component 组件&#xff0c;引擎所需的所有数据结构S -- System 系统&#xff0c;根据组件数据处理逻辑状态的管理器 ECS全称Entity-Component-…

免费压缩pdf文件大小软件收费吗?pdf如何压缩文件大小?12款压缩应用推荐!

在数字化时代&#xff0c;PDF文件因其跨平台、格式统一的特点而广受欢迎。然而&#xff0c;随着文件内容的增加&#xff0c;PDF文件的大小也逐渐增大&#xff0c;给存储和传输带来了诸多不便。因此&#xff0c;寻找一款合适的PDF压缩软件成为了许多用户的需求。本文将详细介绍1…