echarts实现3D饼图

先看下最终效果

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

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

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

相关文章

烧烤炉发霉怎么处理 烧烤炉发霉的原因分析

仓库储存的烧烤炉表面布满了霉菌是什么原因&#xff1f;烧烤炉发霉不仅影响外观和卖点&#xff0c;若是出口给到客户手上还会导致面临客户的索赔的问题 &#xff0c;经ihaoer防霉人士介绍烧烤炉发霉处理方法如下&#xff1a; 烧烤炉发霉的原因分析 一、储存的环境潮湿&#xff…

【算法篇】KMP算法,一种高效的字符串匹配算法

我们今天了解一个字符串匹配算法-KMP算法&#xff0c;内容难度相对来说较高&#xff0c;建议先收藏再细品&#xff01;&#xff01;&#xff01; KMP算法的基本概念 KMP算法是一种高效的字符串匹配算法&#xff0c;由D.E.Knuth&#xff0c;J.H.Morris和V.R.Pratt提出的&#…

SPI协议——对外部SPI操作(跨页读写)

关于W25Q32JVSSIQ的详细内容在之前的两篇文章中已经详细介绍&#xff0c;本文不做太多赘述&#xff0c;如果对芯片的了解有缺失的话&#xff0c;可以参考&#xff1a; SPI协议——对外部SPI Flash操作-CSDN博客 SPI协议——读取外部SPI Flash ID_spi flash 读取id-CSDN博客 目录…

快手矩阵管理系统:引领短视频运营新潮流

在短视频行业蓬勃发展的今天&#xff0c;如何高效运营和优化内容创作已成为企业和创作者关注的焦点。快手矩阵管理系统以其强大的核心功能&#xff0c;为短视频内容的创作、发布和管理提供了一站式解决方案。 智能创作&#xff1a;AI自动生成文案 快手矩阵管理系统的智能创作…

如何快速将Excel定义的表结构转换为MySQL的建表语句

目录 引言 方法一&#xff1a;使用Python编程 步骤一&#xff1a;安装必要的库 步骤二&#xff1a;读取Excel文件 步骤三&#xff1a;编写函数生成建表语句 注意事项 方法二&#xff1a;使用Excel VBA 步骤一&#xff1a;启用VBA编辑器 步骤二&#xff1a;编写VBA代码…

随手记录: Ubuntu NVIDIA显卡驱动安装后 屏幕亮度无法调节 无法连接外显示器等问题

背景 一句话&#xff1a;简单记录帮身边人装系统发现 GPU和外接显示器的无法连接&#xff0c;同时亮度无法调节等新问题 设备型号&#xff1a; 联想笔记本&#xff1a;ThinkBook 16p Gen2CPU&#xff1a;AMD Ryzen 7 5800HGPU&#xff1a;RTX 3060 问题描述及流程&#xff…

金蝶API取数+JSON解析,FDL助力高效数据处理

目录 一、企业介绍 二、业务难题与挑战 商管预算管理瓶颈凸显&#xff1a;金蝶数据手工导出&#xff0c;跨库关联分析时效受限 金蝶API数据提取&#xff1a;挑战重重的技术攻坚战 三、解决方案 商管预算管理升级&#xff1a;API取数JSON解析&#xff0c;FineDataLink助力高效数…

文华财经多空波段均线交易黄金分割线指标公式源码

文华财经多空波段均线交易黄金分割线指标公式源码&#xff1a; 多:EMA(C,3),COLORYELLOW; 空:EMA(C,5),COLOR00FF00; 均衡:EMA(空,5),COLORWHITE; VARF1:COUNT(CROSS(多,均衡),2)1; VARF2:COUNT(CROSS(空,均衡),2)1; ZAI:FILTER(VARF1 AND VARF2,2); DRAWTEXT(ZAI,均衡*…

Java基础回顾

1.一个Java程序有且仅有一个main方法作为程序的入口 由main方法所关联的 2.权限修饰符 修饰类 修饰方法 修饰域 public 都可以访问 都可以访问 都可以访问 protected 不能修饰类 子类可以继承&#xff0c;可以访问&#xff0c;同包下的类也可以访问。可以直接访问父…

JNPF-V5.x重磅来袭!

背景概述 行业背景 低代码⾏业经过⼏年的发展、沉淀&#xff0c;其产品的能⼒定位已逐渐清晰&#xff0c;低代码的核⼼价值是提升专业开发 ⼈员的效率&#xff0c;更便捷的调⽤多种能⼒的接⼝&#xff0c;适合IT能⼒强、IT背景复杂的企业使⽤。同时在客户认知层 ⾯上也以⽇…

【Sql Server】sql server 2019设置远程访问,外网服务器需要设置好安全组入方向规则

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言1、无法链接…

股票分析系统设计方案大纲与细节

股票分析系统设计方案大纲与细节 一、引言 随着互联网和金融行业的迅猛发展,股票市场已成为重要的投资渠道。投资者在追求财富增值的过程中,对股票市场的分析和预测需求日益增加。因此,设计并实现一套高效、精准的股票分析系统显得尤为重要。本设计方案旨在提出一个基于大…

Redis基础教程(十五):Redis GEO地理信息查询与管理

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

Leetcode—97. 交错字符串【中等】

2024每日刷题&#xff08;140&#xff09; Leetcode—97. 交错字符串 2d动规实现代码 class Solution { public:bool isInterleave(string s1, string s2, string s3) {int m s1.length();int n s2.length();int len s3.length();if(m n ! len) {return false;}vector<…

从零开始做题:easycap

题目 给出一个pcap文件 解题 注&#xff1a;传输控制协议&#xff08;TCP&#xff0c;Transmission Control Protocol&#xff09;是为了在不可靠的互联网络上提供可靠的端到端字节流而专门设计的一个传输协议 .pcap文件需要用Wireshark打开 用Wireshark打开easycap.pcap文…

详解IPXProxy海外代理与Morelogin指纹浏览器集成使用策略

在进行网络活动时&#xff0c;安全性是用户关注的重点。Morelogin指纹浏览器能够创建并管理多个独立的浏览器环境&#xff0c;每个环境都拥有独特的设置&#xff0c;这样用户在登录时可以拥有不同的身份。然而想要避免平台的检测&#xff0c;海外代理IP是必不可少的工具&#x…

代码随想录-Day53

739. 每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 示例 1: …

【渗透测试】利用hook技术破解前端JS加解密 - JS-Forward

前言 在做渗透测试项目时&#xff0c;尤其是金融方面&#xff0c;经常会遇到前端JS加解密技术&#xff0c;看着一堆堆密密麻麻的密文&#xff0c;会给人一种无力感。Hook技术则会帮助我们无需获取加解密密钥的前提下&#xff0c;获取明文进行渗透测试 环境准备 JS-Forward Burp…

(附源码)c#+winform实现远程开机(广域网可用)

实现逻辑 利用UDP协议发送特定格式的魔术包&#xff0c;以远程唤醒具有特定MAC地址的目标计算机。目标计算机的BIOS和网络配置需要支持Wake-on-LAN&#xff08;WOL&#xff09;功能&#xff0c;并且需要在目标计算机上配置正确的网络唤醒设置。 源码在最后 准备工作 进入Bio…

NB!小哥竟然绕过了安全启动,Dump了SoC的BootROM。

原文&#xff1a;Amlogic S905 SoC: bypassing the (not so) Secure Boot to dump the BootROM译者&#xff1a;TrustZone 推荐语&#xff1a; 这是一篇关于如何绕过安全启动&#xff0c;然后实现破解BootRom的文章。通过这篇文章&#xff0c;可以让你对于ATF、安全启动等有个…