首页 > 其他分享 >3D饼图

3D饼图

时间:2024-10-29 14:46:46浏览次数:1  
标签:function return item step var Math 3D

1.实现思路

  • Echarts本身没有这类图形,可以使用其扩展echarts-gl进行绘制,echarts-gl曲面图可以完成这类需求
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts-gl/dist/echarts-gl.min.js"></script>
  • 图形分解:这个3D饼图分为3个圆环,每个圆环有6个面,完成这个3D饼图需要绘制3*6=18个面

2.曲面图基本使用

  • echarts-gl曲面图的类别是 surface ,一个series数据对应一个面,面的数据通常通过函数 parametricEquation 进行生成
  • parametricEquation参数说明:共有5个参数(u,v,x,y,z),其中u,v是自变量,u代表水平角度,v代表垂直角度,他们的值是一个区间,并且有step步进,以此融合生成(x,y,z)数据,最后所有生成的(x,y,z)数据就可以绘制出一个曲面
  • parametricEquation实例解析:带经纬度的3D地球,u的范围覆盖水平方向一圈,会生成40条经度线,v的范围覆盖180度,为每条经度绘制20个点,所以会生成 40 * 20 = 800个点,连接这些点,就是一个3D地球
series: [
    {
      type: 'surface',
      parametric: true,
      // shading: 'albedo',
      parametricEquation: {
        u: {
          min: -Math.PI,
          max: Math.PI,
          step: Math.PI / 20
        },
        v: {
          min: 0,
          max: Math.PI,
          step: Math.PI / 20
        },
        x: function (u, v) {
          return Math.sin(v) * Math.sin(u);
        },
        y: function (u, v) {
          return Math.sin(v) * Math.cos(u);
        },
        z: function (u, v) {
          return Math.cos(v);
        }
      }
    }

3.细节及关键点

  • 前面说到,一个饼图分成好几个圆环,每个圆环需要绘制6个面,但是其实绘制3个面就够了(前,顶,后),其他面因为视角遮挡的问题看不见,无需绘制
  • 缩放控制:zoomSensitivity(缩放灵敏度),默认开启缩放,设为0将关闭此功能
  • 旋转控制:rotateSensitivity(旋转灵敏度),默认开启旋转,设为0将关闭此功能
  • 视角距离:distance,默认200,越远图形显示越小
  • 曲面网格线:wireframe,建议取消展示

4.使用方式

  • 数据格式
var data = [
        {
            value: 10,name: "百度",color: "#ff9f7e"
        },
        {
            value: 20,name: "谷歌",color: "#06d3c4"
        },
        {
            value: 20,name: "必应",color: "#6173d6"
        }
    ]
  • 引入组件,传入数据
//引入3d饼图
import zyPie3d from '@/components/zy-pie-3d.vue' 
<div style="height:400px;">
    <zy-pie-3d :data="pie3dData"></zy-pie-3d>
</div>
  • 效果:

5.组件代码:

<template>
    <div style="height:100%" ref="pie3d"></div>
</template>

<script>
export default{
    props: {
        data: {
            type:Array,
            default: function(){
                return []
            }
        },
        //内径大小
        radius: {
            type: Number,
            default: 0.7
        },
        //位置
        top: {
            type: [Number,String],
            default: "-30%"
        },
        left: {
            type: [Number,String],
            default: "-15%"
        },
        //距离
        distance: {
            type: Number,
            default: 170
        },
        //旋转灵敏度
        rotateSensitivity: {
            type: Number,
            default: 1
        },
        //缩放灵敏度
        zoomSensitivity: {
            type: Number,
            default: 0
        }
    },
    data(){
        return {
            myChart: null
        }
    },
    mounted(){
        //渲染
        this.renderEcharts()
    },
    watch: {
        //监听数据变化
        data(){
            //渲染
            this.renderEcharts()
        }
    },
    methods: {
        //渲染
        renderEcharts(){
            //实例化
            if(!this.myChart){
                this.myChart = this.$echarts.init(this.$refs.pie3d)
            }
            var option = {
                tooltip: {
                    formatter: function(e){
                        return e.seriesName
                    }
                },
                legend: {
                    selectedMode: false,
                    orient: "vertical",
                    right: '20%',
                    top: "center",
                    textStyle:{
                        color: "rgba(255,255,255,0.8)",
                    },//正常状态的文本样式
                },
                xAxis3D: {
                    min: -1, max: 1
                },
                yAxis3D: {
                    min: -1, max: 1
                },
                zAxis3D: {
                    min: 0, max: 1
                },
                grid3D: {
                    show: false,
                    top: this.top,
                    left: this.left,
                    width: "100%", height: "100%",
                    viewControl: {
                        rotateSensitivity: this.rotateSensitivity,//禁止旋转
                        zoomSensitivity: this.zoomSensitivity,//禁止缩放
                        distance: this.distance,//距离,可以用来缩放
                    }
                },
                series: this.getPie3DConfig(this.data)
            }
            
            // 使用刚指定的配置项和数据显示图表。
            this.myChart.setOption(option)
        },
        //生成饼图配置(每个数据想包括开启角度,结束角度,颜色)
        getPie3DConfig(data = []){
            //计算总数
            var total = data.reduce((total,item)=>{
                return total += (item.value)
            },0)
            //为数据添加占比和角度值
            var startAngle = 0
            var endAngle = 0
            var _data = data.map((item,index)=>{
                //拷贝数据项
                var _item= {...item}
                //计算比值和角度
                var rotio = item.value / total
                //占位角度
                var angle = Math.PI * 2 * rotio
                //开始角度(上一个项目的结束角度)
                startAngle = endAngle
                //结束角度(开始角度+占位角度)
                if(index >= data.length - 1){
                    endAngle = Math.PI * 2 
                }else{
                    endAngle = startAngle + angle
                }
                //挂载到数据项中
                _item.startAngle = startAngle
                _item.endAngle = endAngle
                _item.angle = angle
                _item.rotio = rotio
                //返回新的数据结构
                return _item
            })

            //饼图固定配置项
            //高度
            var height = 0.1
            //内径
            var radius = this.radius
            //步进
            var step = Math.PI*2/1200

            //3D饼图配置项合集
            var seriesItems = []

            //循环数据项,生成绘制曲面的配置
            _data.forEach(item=>{
                //series配置(一个配置项目绘制一个面,每个数据项至少需要配置2个面)

                var baseSeries = {
                    type: 'surface',
                    name: item.name,
                    wireframe: {
                        show: false
                    },
                    parametric: true,
                }

                //正面
                var seriesItemFront = {
                    ...baseSeries,
                    parametricEquation: {
                        u: {
                            min: item.startAngle,
                            max: item.endAngle,
                            step: step
                        },
                        v: {
                            min: 0,
                            //饼图高度
                            max: height,
                            step: height
                        },
                        x: function (u, v) {
                            return Math.sin(u)
                        },
                        y: function (u, v) {
                            return Math.cos(u)
                        },
                        z: function (u, v) {
                            return v
                        }
                    },
                    itemStyle: {
                        color: item.color
                    }
                }

                //背面
                var seriesItemBack = {
                    ...baseSeries,
                    parametricEquation: {
                        u: {
                            min: item.startAngle,
                            max: item.endAngle,
                            step: step
                        },
                        v: {
                            min: 0,
                            //饼图高度
                            max: height,
                            step: height
                        },
                        x: function (u, v) {
                            return radius * Math.sin(u)
                        },
                        y: function (u, v) {
                            return radius * Math.cos(u)
                        },
                        z: function (u, v) {
                            return v;
                        }
                    },
                    itemStyle: {
                        color: item.color
                    }
                }

                //上面
                var seriesItemAbove = {
                    ...baseSeries,
                    parametricEquation: {
                        u: {
                            min: item.startAngle,
                            max: item.endAngle,
                            step: step
                        },
                        v: {
                            min: 0,
                            max: height,
                            step: height
                        },
                        x: function (u, v) {
                            if(v==0){
                                //内圈
                                return radius * Math.sin(u)
                            }else{
                                //外圈
                                return Math.sin(u);
                            }
                        },
                        y: function (u, v) {
                            if(v==0){
                                //内圈
                                return radius * Math.cos(u)
                            }else{
                                //外圈
                                return Math.cos(u);
                            }
                        },
                        z: function (u, v) {
                            return height
                        }
                    },
                    itemStyle: {
                        color: item.color
                    }
                }

                seriesItems.push(seriesItemFront, seriesItemBack, seriesItemAbove)
            })
            return seriesItems
        }
    }
}
</script>

标签:function,return,item,step,var,Math,3D
From: https://www.cnblogs.com/OrochiZ-/p/18513179

相关文章

  • FreGS: 3D Gaussian Splatting with Progressive Frequency Regularization
    Abstract3DGShasachievedveryimpressiveperformanceinreal-timenovelviewsynthesis.However,itoftensuffersfromover-reconstructionduringGaussiandensificationwherehigh-varianceimageregionsarecoveredbyafewlargeGaussiansonly,leading......
  • 未来已来:3D建模技术引领就业新趋势
    3D建模‌是将现实世界中的物体或场景转化为三维数字模型的过程。这项技术连接着现实与虚拟两个世界,通过3D建模,我们可以将名胜古迹、雕塑艺术品等以三维的形式呈现于互联网,让用户体验到更加真实、立体的视觉感受。3D建模的应用领域广泛,包括但不限于游戏开发、电影和动画制作、建......
  • 3D在UI上的应用
    一、传统管理系统登录页的局限性在过去,传统的管理系统登录页通常采用平面设计,以简洁的布局和清晰的文字为主。虽然这种设计能够满足基本的功能需求,但也存在一些局限性。 首先,平面设计缺乏立体感和深度感,容易给人单调、乏味的感觉。用户在面对这样的登录页时,往往缺乏足够的视觉......
  • 边境游戏遭遇d3dx9_43.dll缺失危机?揭秘边境游戏d3dx9_43.dll缺失的真正原因与解决方案
    当你在享受《边境》这款游戏的精彩内容时,突然弹出一个错误提示:“d3dx9_43.dll缺失”。这个提示可能会让你感到困惑和沮丧,但不必过于担心,本文将为你揭秘d3dx9_43.dll缺失的真正原因,并提供有效的解决方案。d3dx9_43.dll文件的重要性d3dx9_43.dll是DirectX9的一个关键组件,是Wi......
  • d3dx9_43.dll缺失导致小小世界Smalland无法启动?小小世界Smalland玩家必看d3dx9_43.dll
    当d3dx9_43.dll文件缺失导致小小世界Smalland无法启动时,作为玩家,你可以采取以下紧急应对措施来解决这一问题:一、了解d3dx9_43.dll文件的重要性d3dx9_43.dll是DirectX9.0c的一个重要组件,它负责为基于DirectX技术的游戏和应用程序提供图形和声音效果的支持。如果该文件缺失或......
  • Unity3D学习FPS游戏(6)武器发射子弹
    前言:上一篇中设置好了武器的瞄准,本篇将实现一个武器发射子弹的效果。子弹子弹发射位置在Weapon01下面新建一个GameObject用来设置发射子弹的位置,调整Position放在枪口位置。子弹模型子弹模型在下面路径找到子弹模型,然后拖入到项目中,并右键Prefab-unpack(为了避免影响......
  • 3D数学基础:图形和游戏开发(第二版)--读书笔记(1)
    简介:本书是关于3D数学、三维空间的几何和代数的入门教材。它旨在告诉你如何使用数学描述三维中的物体及其位置、方向和轨迹。这不是一本关于计算机图形学、模拟,甚至计算几何的书,但是,如果读者打算研究这些科目,那么肯定需要这里的信息。这是一本适宜视频游戏程序开发人员阅读的图......
  • BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View阅读小
    BEVDet:High-PerformanceMulti-Camera3DObjectDetectioninBird-Eye-ViewBEVDet高性能多相机鸟瞰视图3D目标检测论文概述BEVDet是一种模块化设计的3D目标检测框架,以鸟瞰视图(Bird-Eye-View,BEV)执行3D目标检测,通过现有模块构建其框架,并通过定制数据增强策略和优化非......
  • Diffusion Probabilistic Models for 3D Point Cloud Generation——点云论文阅读(8)
    此内容是论文总结,重点看思路!!文章概述该文献介绍了一种用于3D点云生成的概率模型。点云是表示3D物体和场景的常用方式,但由于其不规则的采样模式,与图像相比,点云生成更具挑战性。现有方法如GANs、流模型和自回归模型在点云生成方面取得了进展,但它们在训练稳定性、生成顺序假设和......
  • Python工程数学7VPython制作3D图形和动画(上)坐标系、基本形状、点和线
    7简介VPython是一个基于Python语言的开源库,专门用于创建三维图形和动画。它为用户提供了一种简单而直观的方式,通过Python代码构建出生动的三维场景。VPython的设计初衷是让用户能够轻松地将物理概念可视化,因此在教学、科研和学习物理等领域得到了广泛应用。VPython的特点易......