用echarts实现3d饼图

2023-10-28

安装echarts和echarts-gl

npm install echarts

npm install echarts-gl

echarts版本5.x的话需要对应echarts-gl版本2.x

echarts版本4.x的话需要对应echarts-gl版本1.x

指定版本命令 npm install echarts-gl@1.1.2

1.关键函数,生成扇形的曲面参数方程,用于 series-surface

Documentation - Apache ECharts官网series-surface介绍 Documentation - Apache ECharts

getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {

    // 计算

    const midRatio = (startRatio + endRatio) / 2;

    const startRadian = startRatio * Math.PI * 2;

    const endRadian = endRatio * Math.PI * 2;

    const midRadian = midRatio * Math.PI * 2;

    // 如果只有一个扇形,则不实现选中效果。

    if (startRatio === 0 && endRatio === 1) {

        isSelected = false;

    }

    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)

    k = 1;

    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)

    const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;

    const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;

    // 计算高亮效果的放大比例(未高亮,则比例为 1)

    const 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) * h * 0.1;

            }

            return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;

        },

    };

  }

2.构建饼图函数,绘制3d图。internalDiameterRatio为透明的空心占比,0就是普通饼1就镂空

getPie3D(pieData, internalDiameterRatio) {

    const series = [];

    let sumValue = 0;

    let startValue = 0;

    let endValue = 0;

    const legendData = [];

    const k =

        typeof internalDiameterRatio !== 'undefined'

            ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)

            : 1 / 3;

    // 为每一个饼图数据,生成一个 series-surface 配置

    for (let i = 0; i < pieData.length; i += 1) {

        sumValue += pieData[i].value;

        const 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,

            },

            itemStyle:{}

        };

        if (typeof pieData[i].itemStyle !== 'undefined') {

            const itemStyle :any= {};

            if (typeof pieData[i].itemStyle.color !== 'undefined') {

                itemStyle.color = pieData[i].itemStyle.color;

            }

            if (typeof pieData[i].itemStyle.opacity !== 'undefined') {

                itemStyle.opacity = pieData[i].itemStyle.opacity;

            }

            seriesItem.itemStyle = itemStyle;

        }

        series.push(seriesItem);

    }

    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,

    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。

    for (let i = 0; i < series.length; i += 1) {

        endValue = startValue + series[i].pieData.value;

        series[i].pieData.startRatio = startValue / sumValue;

        series[i].pieData.endRatio = endValue / sumValue;

        console.log(series[i].pieData.startRatio,

            series[i].pieData.endRatio,

            false,  

            false,

            k,

            series[i].pieData.value)

            series[i].parametricEquation = this.getParametricEquation(

            series[i].pieData.startRatio,

            series[i].pieData.endRatio,

            false,

            false,

            k,

            25//高度

        );

        startValue = endValue;

        legendData.push(series[i].name);

    }

    return series;

  }

3.绘制2d饼图,添加label指引线

series.push({

      name: 'pie2d',

      type: 'pie',

      label: {

          opacity: 1,

          fontSize: 14,

          lineHeight: 20,

      },

      labelLine: {

          length: 50,

          length2: 50,

      },

      startAngle: -50, //起始角度,支持范围[0, 360]。

      clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式

      radius: ['20%', '50%'],

      center: ['50%', '50%'],

      data: optionsData,

      itemStyle: {

          opacity: 0,

      },

    });

js代码:

  setPie(){
    const optionsData = [
      {      
          name: 'aa',
          value: 20,
          itemStyle: {
              color: '#38ACEC',
              // opacity: 1,
          },
      },
      {
        name: 'bb',
        value: 15,
        itemStyle: {
            color: '#6960EC',
            // opacity: 1,
        },
      },
      {
          name: 'cc',
          value: 25,
          itemStyle: {
              color: '#6CBB3C',
              // opacity: 1,
          },
      },
    ];
    const series = this.getPie3D(optionsData, 0.5,);
    series.push({
      name: 'pie2d',
      type: 'pie',
      label: {
          opacity: 1,
          fontSize: 14,
          lineHeight: 20,
      },
      labelLine: {
          length: 50,
          length2: 50,
      },
      startAngle: -50, //起始角度,支持范围[0, 360]。
      clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
      radius: ['20%', '50%'],
      center: ['50%', '50%'],
      data: optionsData,
      itemStyle: {
          opacity: 0,
      },
    });

    this.option1 = 
    {
      legend: {
          tooltip: {
              show: true,
          },
          data: ['aa', 'bb', 'cc'],
          right: '2%',
          textStyle: {
              color: '#fff',
              fontSize: 12,
          },
      },
      tooltip: {
          formatter: (params) => {
              if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
                  let bfb = (
                      (this.option.series[params.seriesIndex].pieData.endRatio -
                          this.option.series[params.seriesIndex].pieData.startRatio) *
                      100
                  ).toFixed(2);
                  return (
                      `${params.seriesName}<br/>` +
                      `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;"></span>` +
                      `${bfb}%`
                  );
              }
          },
      },
      title: {
          text: '3D 饼图',
          x: 'center',
          top: '5%',
          textStyle: {
              color: '#fff',
              fontSize: 22,
          },
      },
      labelLine: {
          show: true,
          lineStyle: {
              color: '#7BC0CB',
          },
      },
      label: {
          show: true,
          position: 'outside',
          formatter: '{b} \n{c} {d}%',
      },
      xAxis3D: {
          min: -1,
          max: 1,
      },
      yAxis3D: {
          min: -1,
          max: 1,
      },
      zAxis3D: {
          min: -1,
          max: 1,
      },
      grid3D: {
          show: false,
          boxHeight: 25, // 三维笛卡尔坐标系在三维场景中的高度
          viewControl: {
              alpha: 45,
              // beta: 1000,
              distance: 300, //调整视角到主体的距离,类似调整zoom
              // rotateSensitivity: 0, // 设置为0无法旋转
              zoomSensitivity: 0, // 设置为0无法缩放
              panSensitivity: 0, // 设置为0无法平移
              autoRotate: false, // 自动旋转
          },
      },
      series: series,
    };
  }
   // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
  getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
    // 计算
    const midRatio = (startRatio + endRatio) / 2;
    const startRadian = startRatio * Math.PI * 2;
    const endRadian = endRatio * Math.PI * 2;
    const midRadian = midRatio * Math.PI * 2;
    // 如果只有一个扇形,则不实现选中效果。
    if (startRatio === 0 && endRatio === 1) {
        isSelected = false;
    }
    // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
    k = 1;
    // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
    const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
    const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
    // 计算高亮效果的放大比例(未高亮,则比例为 1)
    const 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) * h * 0.1;
            }
            return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
        },
    };
  }
  //构建饼图数据,绘制3d图  internalDiameterRatio:透明的空心占比
  getPie3D(pieData, internalDiameterRatio) {
    const series = [];
    let sumValue = 0;
    let startValue = 0;
    let endValue = 0;
    const legendData = [];
    const k =
        typeof internalDiameterRatio !== 'undefined'
            ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio)
            : 1 / 3;
    // 为每一个饼图数据,生成一个 series-surface 配置
    for (let i = 0; i < pieData.length; i += 1) {
        sumValue += pieData[i].value;
        const 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,
            },
            itemStyle:{}
        };
        if (typeof pieData[i].itemStyle !== 'undefined') {
            const itemStyle :any= {};
            if (typeof pieData[i].itemStyle.color !== 'undefined') {
                itemStyle.color = pieData[i].itemStyle.color;
            }
            if (typeof pieData[i].itemStyle.opacity !== 'undefined') {
                itemStyle.opacity = pieData[i].itemStyle.opacity;
            }
            seriesItem.itemStyle = itemStyle;
        }
        series.push(seriesItem);
    }
    // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
    // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
    for (let i = 0; i < series.length; i += 1) {
        endValue = startValue + series[i].pieData.value;
        series[i].pieData.startRatio = startValue / sumValue;
        series[i].pieData.endRatio = endValue / sumValue;
        console.log(series[i].pieData.startRatio,
            series[i].pieData.endRatio,
            false,  
            false,
            k,
            series[i].pieData.value)
            series[i].parametricEquation = this.getParametricEquation(
            series[i].pieData.startRatio,
            series[i].pieData.endRatio,
            false,
            false,
            k,
            25//高度
        );
        startValue = endValue;
        legendData.push(series[i].name);
    }
    return series;
  }

html代码:

<div  id="option" echarts [options]="option1"  style="width:100%;height:100%"></div>

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用echarts实现3d饼图 的相关文章

随机推荐

  • Redis设计与实现---Sentinel

    Sentinel Redis的高可用性解决方案 由一个或多个Sentinel实例组成的系统可以监视任意多个主服务器 以及这些主服务器属下的所有从服务器 并在被监视的主服务器进入下线状态时 自动将下线主服务器属下的某个从服务器升级为新的主服务
  • 考研复试数据库原理课后习题(十)——数据库恢复技术

    数据库恢复技术 1 事务是用户定义的一个数据库操作序列 这些操作要么全做 要么不做 是一个不可分隔的工作单位 事务具有四个特性 ACID 原子性 一致性 隔离性 持续性 原子性 事务是数据库的逻辑工作单位 一个事务中包括的操作要么全做 要么
  • Swagger的常用配置

    一 可在项目中创建SwaggerConfig配置类 对文档详细信息进行配置 swagger配置类 用于配置swagger的详细信息 比如标题 网站 邮箱 Configuration public class SwaggerConfig 返回
  • linux 大量的TIME_WAIT解决办法

    原文地址 http www cnblogs com softidea p 6062147 html 统计在一台前端机上高峰时间TCP连接的情况 统计命令 netstat n awk tcp S NF END for a in S print
  • 计算机科学想象作文500,六年级想象作文600字

    第一篇 描写月亮的作文 你们听说过 超级月亮 吗 什么 没听说过 那么 我就带你们去看看前几天的超级月亮吧 今天 我像往常一样去广场滑滑板 忽然 我看一栋楼房的左 作文500字 未来的城市一场暴雨过后 阳光洒在充满绿意的城市 街道上没有积水
  • 09_Pandas从多个条件(AND,OR,NOT)中提取行

    09 Pandas从多个条件 AND OR NOT 中提取行 使用Pandas从多个条件 AND OR NOT 中提取行的方法 有以下2点需要注意 的使用 and or not的错误 使用比较运算符时 请将每个条件括在括号中 以下数据为例
  • 驱动名、设备名和设备文件名的关系

    编写一个驱动文件的时候生成一个name1 ko文件 这个name1就是驱动名 使用insmod name1 ko指令之后 用lsmod能看见一个名为name1的驱动 在调用了alloc chrdev region函数或register ch
  • 满分回答教你如何应对面试中项目经验这一难关

    给前端瓶子君加星标 提升前端技能 作者 亦逊 https juejin im post 5e7aed9c6fb9a07cac1d872d 前言 本篇文章的作者是来自阿里淘系用户增长前端团队的 亦逊 18年作为双非本科生通过层层面试 校招进入
  • CSS下划线与文字间距,下划线粗细以及下划线颜色的设置

    最开始的时候了解下划线的属性是 text decoration underline 1 但是 很遗憾的是 对于设计做的下划线用浏览器默认属性样式很难调整 使用这个属性并不能调整下划线与文字的间距 而且对于下划线的颜色也不好调整 而使用 u
  • 2014年仍然是DX11设备仿真和软引擎年

    先说点题外话 2014年1月比较浮躁 2月过年 回家后 与亲戚家的同龄人一比较 发现自己很废 不知道他们是不是在吹牛 想急功近利挣点钱 所以一度想进行OSG或者COCOS2DX 诚然 以后会进行这样的一种或两种 但是 今年不是时候 因为水平
  • MFC之创建插入符,写字,换行与退格11

    概述 我们按照前面文章根据向导创建项目 1 创建插入符 由于插入符是在创建窗口后并且做我们用户操作前需要使用 所以我们将插入符的创建放在OnCreate函数中即WM CRATE信号 int CInsertFuView OnCreate LP
  • reacthook的ref循环多个子组件

    父组件 ref值挂在这里 父子和兄弟都可以使用 const bodyRefs useRef
  • sklearn 随机森林(Random Forest)多分类问题

    模型 随机森林是集成学习算法的一种 sklearn更多的集成学习算法 RandomForestClassifier 参数详解 重要的参数有基分类器的个数 n estimators 特征选择算法 critirion 单个决策树的最大深度 ma
  • 使用wps2019快速翻译视频文字

    问题 视频中的英文如何翻译 如图 方法如下 1 使用wps 2019 截屏工具截取屏幕 2 使用 翻译文字 3 结果
  • SpringBoot+redis实现消息队列(发布/订阅)

    1 引入依赖
  • 2021解决ERROR:ModuleNotFoundError: No module named ‘sklearn‘

    2021解决ERROR ModuleNotFoundError No module named sklearn 在Python中 出现 no module named sklean 的原因是 没有正确安装sklean包 很多博文直接给出了这
  • 反向代理与 Real-IP 和 X-Forwarded-For

    开篇语 开涛新作 亿级流量网站架构核心技术 出版计划公布以来 博文视点遭受到一波又一波读者询问面世时间的DDos攻击 面对亿级流量的热情 感激之余 我们也很庆幸 这部作品质量的确过硬 不会辜负拥趸厚望 更有开涛的高度负责和体贴周到加持 让她
  • ARM学习之定时器Timer0实验

    Project Timer0实验 Writer SHOW Time 2011 10 16 Hareware 硬件平台 mini2440 J link Function 通过定时器0实现LED1以1s的时间间隔闪烁 Direction 这个实
  • 原来Github上的README.md文件这么有意思——Markdown语言详解

    转载 https blog csdn net zhaokaiqiang1992 article details 41349819 之前一直在使用github 也在上面分享了不少的项目和Demo 每次创建新项目的时候 使用的都是默认的READ
  • 用echarts实现3d饼图

    安装echarts和echarts gl npm install echarts npm install echarts gl echarts版本5 x的话需要对应echarts gl版本2 x echarts版本4 x的话需要对应echa