大屏中有时候会用3D 的echarts,效果图如下


首先在vue里面的使用,引入就不讲了

 <echarts3DPieref="pei3D":DpieData="DpieData"  // 接口获取的值传到组件里去:key="pei3Dkey"  // 传参后pei3Dkey++ 可以刷新组件/>

以下是

3D echarts的封装

<template><div class="echart3DPie-container"><div class="chart" ref="chart"></div><!-- 底座背景 --><div class="bg"></div></div>
</template><script>
import { getPie3D, getParametricEquation } from "./chart"; //工具类js,页面路径自己修改const color = ["#33CCCC", "#7299BF", "#BFEAFF", "#DBB36E"];export default {name: "chart",data() {return {optionData: [{name: "巡检工单",value: 45,},{name: "养护工单",value: 25,},{name: "维修工单",value: 12,},{name: "其他工单",value: 8,},],statusChart: null,option: {},};},props: {DpieData: {type: Object,default: () => {},},},created() {// 此处为赋值if (this.DpieData) {let num1 = this.DpieData.inspectionRate;let num2 = this.DpieData.maintainRate;let num3 = this.DpieData.repairRate;let num4 = this.DpieData.otherRate;this.optionData.map((val) => {val.value =val.name == "巡检工单"? num1: val.name == "养护工单"? num2: val.name == "维修工单"? num3: num4;});}this.setLabel();},mounted() {this.initChart();//根据窗口变化自动调节图表大小const that = this;window.onresize = function () {that.changeSize();};},methods: {// 初始化label样式setLabel(val) {this.optionData.forEach((item, index) => {item.itemStyle = {color: color[index],};item.label = {normal: {show: false,color: color[index],formatter: ["{b|{b}}", "{d|{d}%}"], // 用\n来换行rich: {b: {color: "#fff",lineHeight: 25,align: "left",},c: {fontSize: 22,color: "#fff",textShadowColor: "#1c90a6",textShadowOffsetX: 0,textShadowOffsetY: 2,textShadowBlur: 5,},d: {color: color[index],align: "left",},},},};item.labelLine = {normal: {show: false,lineStyle: {width: 1,color: "rgba(255,255,255,0.7)",},},};});},// 图表初始化initChart() {this.statusChart = this.$echarts.init(this.$refs.chart);// 传入数据生成 option, 构建3d饼状图, 参数工具文件已经备注的很详细this.option = getPie3D(this.optionData, 0.8, 240, 22, 15, 0.8);this.statusChart.setOption(this.option);// 是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOptionthis.option.series.push({name: "工单数量占比", //自己根据场景修改backgroundColor: "transparent",type: "pie",label: {show: false,opacity: 1,fontSize: 13,lineHeight: 20,},startAngle: -40, // 起始角度,支持范围[0, 360]。clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式radius: ["20%", "50%"],center: ["50%", "35%"],data: this.optionData,itemStyle: {opacity: 0, //这里必须是0,不然2d的图会覆盖在表面},});this.statusChart.setOption(this.option);this.bindListen(this.statusChart);},// 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。// optionName是防止有多个图表进行定向option传递,单个图表可以不传,默认是opitonbindListen(myChart, optionName = "option") {let selectedIndex = "";let hoveredIndex = "";// 监听点击事件,实现选中效果(单选)myChart.on("click", (params) => {// 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。const isSelected =!this[optionName].series[params.seriesIndex].pieStatus.selected;const isHovered =this[optionName].series[params.seriesIndex].pieStatus.hovered;const k = this[optionName].series[params.seriesIndex].pieStatus.k;const startRatio =this[optionName].series[params.seriesIndex].pieData.startRatio;const endRatio =this[optionName].series[params.seriesIndex].pieData.endRatio;// 如果之前选中过其他扇形,将其取消选中(对 option 更新)if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) {this[optionName].series[selectedIndex].parametricEquation =getParametricEquation(this[optionName].series[selectedIndex].pieData.startRatio,this[optionName].series[selectedIndex].pieData.endRatio,false,false,k,this[optionName].series[selectedIndex].pieData.value);this[optionName].series[selectedIndex].pieStatus.selected = false;}// 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)this[optionName].series[params.seriesIndex].parametricEquation =getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,this[optionName].series[params.seriesIndex].pieData.value);this[optionName].series[params.seriesIndex].pieStatus.selected =isSelected;// 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndexselectedIndex = isSelected ? params.seriesIndex : null;// 使用更新后的 option,渲染图表myChart.setOption(this[optionName]);});// 监听 mouseover,近似实现高亮(放大)效果myChart.on("mouseover", (params) => {// 准备重新渲染扇形所需的参数let isSelected;let isHovered;let startRatio;let endRatio;let k;// 如果触发 mouseover 的扇形当前已高亮,则不做操作if (hoveredIndex === params.seriesIndex) {// 否则进行高亮及必要的取消高亮操作} else {// 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)if (hoveredIndex !== "" &&this[optionName].series[hoveredIndex].pieStatus) {// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。isSelected =this[optionName].series[hoveredIndex].pieStatus.selected;isHovered = false;startRatio =this[optionName].series[hoveredIndex].pieData.startRatio;endRatio = this[optionName].series[hoveredIndex].pieData.endRatio;k = this[optionName].series[hoveredIndex].pieStatus.k;// 对当前点击的扇形,执行取消高亮操作(对 option 更新)this[optionName].series[hoveredIndex].parametricEquation =getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,this[optionName].series[hoveredIndex].pieData.value);this[optionName].series[hoveredIndex].pieStatus.hovered = isHovered;// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空hoveredIndex = "";}// 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)if (params.seriesName !== "mouseoutSeries" &&params.seriesName !== "pie2d" &&this[optionName].series[params.seriesIndex].pieStatus) {let seriesData = this[optionName].series[params.seriesIndex];// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。isSelected = seriesData.pieStatus.selected;isHovered = true;startRatio = seriesData.pieData.startRatio;endRatio = seriesData.pieData.endRatio;k = seriesData.pieStatus.k;// 对当前点击的扇形,执行高亮操作(对 option 更新)this[optionName].series[params.seriesIndex].parametricEquation =getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,seriesData.pieData.value + 30);this[optionName].series[params.seriesIndex].pieStatus.hovered =isHovered;// 记录上次高亮的扇形对应的系列号 seriesIndexhoveredIndex = params.seriesIndex;this[optionName].title.text = seriesData.pieData.value + "%";this[optionName].title.subtext = seriesData.pieData.name;}// 使用更新后的 option,渲染图表myChart.setOption(this[optionName]);}});// 修正取消高亮失败的 bugmyChart.on("globalout", () => {// 准备重新渲染扇形所需的参数let isSelected;let isHovered;let startRatio;let endRatio;let k;if (hoveredIndex !== "" &&this[optionName].series[hoveredIndex].pieStatus) {// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。isSelected = this[optionName].series[hoveredIndex].pieStatus.selected;isHovered = false;k = this[optionName].series[hoveredIndex].pieStatus.k;startRatio = this[optionName].series[hoveredIndex].pieData.startRatio;endRatio = this[optionName].series[hoveredIndex].pieData.endRatio;// 对当前点击的扇形,执行取消高亮操作(对 option 更新)this[optionName].series[hoveredIndex].parametricEquation =getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,this[optionName].series[hoveredIndex].pieData.value);this[optionName].series[hoveredIndex].pieStatus.hovered = isHovered;// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空hoveredIndex = "";this[optionName].title.text = "";this[optionName].title.subtext = "";}// 使用更新后的 option,渲染图表myChart.setOption(this[optionName]);});},// 取消高亮cancelHighLight() {},// 自适应宽高changeSize() {this.statusChart.resize();},},
};
</script><style lang="less" scoped>
.echart3DPie-container {position: relative;width: 100%;height: 100%;.chart,.bg {width: 100%;height: 100%;}.bg {position: absolute;bottom: 45%;left: 50%;z-index: -1;width: 312px;height: 134px;background: url("~@/assets/images/bigScreen/asset/echarts3DPie-bg.png") 100%100% no-repeat;transform: translateX(-50%);}
}
</style>

以下是3D echarts的js用来配置文件

/*** 绘制3d图* @param pieData 总数据* @param internalDiameterRatio:透明的空心占比* @param distance 视角到主体的距离* @param alpha 旋转角度* @param pieHeight 立体的高度* @param opacity 饼或者环的透明度*/
const getPie3D = (pieData,internalDiameterRatio,distance,alpha,pieHeight,opacity = 1
) => {const series = [];let sumValue = 0;let startValue = 0;let endValue = 0;let legendData = [];let legendBfb = [];const k = 1 - internalDiameterRatio;pieData.sort((a, b) => {return b.value - a.value;});// 为每一个饼图数据,生成一个 series-surface 配置for (let i = 0; i < pieData.length; i++) {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,},center: ["10%", "50%"],};if (typeof pieData[i].itemStyle !== "undefined") {const itemStyle = {};itemStyle.color =typeof pieData[i].itemStyle.color !== "undefined"? pieData[i].itemStyle.color: opacity;itemStyle.opacity =typeof pieData[i].itemStyle.opacity !== "undefined"? pieData[i].itemStyle.opacity: opacity;seriesItem.itemStyle = itemStyle;}series.push(seriesItem);}// 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。legendData = [];legendBfb = [];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);startValue = endValue;const bfb = fomatFloat(series[i].pieData.value / 100, 4);legendData.push({name: series[i].name,value: bfb,});legendBfb.push({name: series[i].name,value: bfb,});}const boxHeight = getHeight3D(series, pieHeight); // 通过pieHeight设定3d饼/环的高度,单位是px// 准备待返回的配置项,把准备好的 legendData、series 传入。const option = {title: {show: true,text: "",subtext: "",textStyle: {color: "#D8EBFF",fontFamily: "PangMenZhengDao",fontSize: 40,lineHeight: 50,},subtextStyle: {fontSize: 23,color: "#D8EBFF",lineHeight: 35,},left: "center",top: "20%",},legend: {show: true,data: legendData,left: "center",bottom: "15%",itemGap: 30,itemWidth: 12,itemHeight: 12,textStyle: {color: "#fff",rich: {title: {fontSize: 17,padding: [0, 0, 0, 14],fontFamily: "PingFangSC-Regular",},value: {fontSize: 17,padding: [0, 30, 0, 30],fontFamily: "RobotoCondensed-Bold",},},},formatter: function (param) {const item = legendBfb.filter((item) => item.name === param)[0];const bfs = fomatFloat(item.value * 100, 2) + "%";return "{title|" + `${item.name}` + "}{value|" + `${bfs}` + "}";},},labelLine: {show: true,lineStyle: {color: "#fff",},},label: {show: true,position: "outside",formatter: "{b} \n{c} {d}%",},tooltip: {show: false,backgroundColor: "#033b77",borderColor: "#21f2c4",textStyle: {color: "#fff",fontSize: 13,},formatter: (params) => {let obj = option.series[params.seriesIndex].pieData;if (params.seriesName !== "mouseoutSeries" &&params.seriesName !== "pie2d" &&obj) {const bfb = ((obj.endRatio - obj.startRatio) * 100).toFixed(2);return (`${params.seriesName}<br/>` +`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +`${bfb}%`);}},},xAxis3D: {min: -1,max: 1,},yAxis3D: {min: -1,max: 1,},zAxis3D: {min: -1,max: 1,},grid3D: {show: false,boxHeight: boxHeight, // 圆环的高度viewControl: {// 3d效果可以放大、旋转等,请自己去查看官方配置alpha, // 角度distance, // 调整视角到主体的距离,类似调整zoomrotateSensitivity: 0, // 设置为0无法旋转zoomSensitivity: 0, // 设置为0无法缩放panSensitivity: 0, // 设置为0无法平移autoRotate: false, // 自动旋转},top: "-15%",},series: series,};return option;
};/*** 生成扇形的曲面参数方程,用于 series-surface.parametricEquation*/
const 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 = typeof k !== "undefined" ? k : 1 / 3;// 计算选中效果分别在 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丙图的最高扇区的高度*/
const getHeight3D = (series, height) => {series.sort((a, b) => {return b.pieData.value - a.pieData.value;});return (height * 25) / series[0].pieData.value;
};/*** 格式化浮点数*/
const fomatFloat = (num, n) => {let f = parseFloat(num);if (isNaN(f)) {return false;}f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂let s = f.toString();let rs = s.indexOf(".");// 判定如果是整数,增加小数点再补0if (rs < 0) {rs = s.length;s += ".";}while (s.length <= rs + n) {s += "0";}return s;
};export { getPie3D, getParametricEquation };

3D echarts在vue中的使用相关推荐

  1. 【3d地图】vue中使用echarts geo3D

    文章目录 前言 一.echarts是什么? 二.使用步骤 1.引入echarts库,3d地图必须安装echarts-gl依赖 2.制作地图JSON文件 2.1 制作自己的json 3.引入到vue组件 ...

  2. vue echarts div变化_数据可视化之echarts在Vue中的使用

    数据可视化的本质是将数据通过各种视觉通道映射成图形,可以使得用户更快.更准确的理解数据. 一.为什么选择echarts: 简单上手容易 满足绝大部分的开发需要 在可视化库中有较好的体验和口碑 二.在V ...

  3. 【Vue+Echarts】Vue中Echarts图表的使用(三)—— 组件模块调用不同类型的Echarts图表(动态图表生成)

    这节也是这个系列最后的一篇文章了. 第二篇文章,将Echarts封装成了组件,在使用的时候,只需将ChartsOption传递进去即可,同时,提供了监听事件,当Option发生变化时,会刷新图表. 因 ...

  4. echarts中x轴 y轴配置(字体颜色,线的颜色,分割线,y周单位颜色)。vue中直接使用echarts以及vue中使用vue-echarts如何配置横向渐变与纵向渐变(后者适用于前者)

    vue中直接使用echarts //var myChart = this.$echarts.init(document.getElementById("echart-twoline" ...

  5. axios vue 加载效果动画_在vue中通过axios异步使用echarts

    现实的工作中, 数据不可能是像之前的demo演示的那样把数据写死的. 所有的数据都应该通过发送请求进行获取, 所以, 这篇文章, 我将在Vue项目中使用Echarts: 在Vue中引入Echarts中 ...

  6. 【Echarts】在Vue中使用Echarts

    在Vue中使用Echarts 引入第三方库vue-echarts vue-echarts安装与使用 vue2中使用Echarts vue-echarts安装 vue2中使用Echarts vue3中使 ...

  7. vue2.0_在vue中使用echarts图表插件

    说明:本例子基于vue-cli脚手架搭建 首先,安装echarts依赖 npm install echarts -S 注:安装NodeJS之后,使用npm来安装包使用的是国外的地址,经常会出现超时错误 ...

  8. Vue中使用Echarts构建3D地球层+模拟时钟

    文章目录 前言 一.Echarts示例 二.使用步骤 1.引入库 2.完整代码 总结 前言   Echarts官网上的例子大多是原生js,那么我们在vue项目中该如何使用?本文举两个例子. 一.Ech ...

  9. vue中基于echarts和基于高德地图的两种地图下钻与上浮方式

    ** vue中基于echarts和基于高德地图的两种地图下钻与上浮方式 ** 基于echarts的地图下钻与上浮(浙江省为例) 第一步:在<template>中构建承载echarts的do ...

最新文章

  1. SpringBoot笔记:SpringBoot2.3集成Logback日志组件配置
  2. java打印sql表_java程序获得SqlServer数据表的表结构
  3. 树莓派AI视觉云台——6、Linux常用命令及vim编辑器的使用
  4. 机器学习——相似度算法汇总
  5. 炸金花 php算法,php 炸金花牌型 和 比牌 规则
  6. Acwing 1085. 不要62
  7. 外点惩处函数法·约束优化问题
  8. html表格分页打印样式,vue部分打印(多页自动分页、打印样式自定义、多页打印表格页面顶部带表头)...
  9. 如何生成16位流水号
  10. python基础学习笔记(九)
  11. MyBatis配置详解
  12. 全文搜索引擎 Elasticsearch 入门概念
  13. 某人分析的70后,80后,90后
  14. windwos 10打印机服务老是自动关闭
  15. 2B 领域下低代码的探索之路
  16. 大型电子病历系统【整套源代码分享】
  17. ios浏览器无法播放视频-node.js文件传输问题
  18. Could not find or load main class org.apache.hadoop.mapreduce.v2.app.MRAppMaster
  19. 真神奇!敲击桌子就能操控iPad或iPhone
  20. 如何在家远程控制公司的电脑,高效便捷的远程办公?

热门文章

  1. 考公知识积累——人文常识
  2. 如何识别浏览器版本,以及对ieX浏览器以下进行控制
  3. btchina打不开
  4. Android发布APP,IOS发布APP注意事项
  5. 微软修复工具_GitHub 月榜第 3,微软的老照片修复工具火了
  6. 突发性耳鸣的治疗小知识点你知道吗
  7. Mybatis常用的注解
  8. c++string 加引号_朋友圈晒图,为什么越来越多的人喜欢加“白边”?
  9. Python能成为通用编程开发语言的10大原因
  10. 【再生资源】再生资源回收站安全监管解决方案