记录使用Echarts 实现3D饼状图的过程。
效果图:

1.首先安装echarts 3d插件

"echarts": "^4.7.0",
"echarts-gl": "^1.1.2",
npm install echarts --save
npm install echarts-gl

2.封装组件

<template><divref="chartPanel"id="chart-panel":style="{width: '950PX', height: height}"></div>
</template><script>
import {getPie3D} from '@/utils/largeScreen/sector'
import 'echarts-gl'
import {colorMixin} from '@/store/mixins/color'const colors = ['#13c5a1', '#3de9d4', '#1256dd', '#39a0fe', '#fff942', '#126109', '#9ce3cc', '#a5c9ef', '#cbe5de', '#bfb6db']
export default {name: 'PieChartSolid',mixins: [colorMixin],props: {// options: {//   type: Object,//   default: () => null// },height: {type: String,default: '388PX'}},data() {return {backgroundDots: {'材料成本': '#13c5a1','劳务分包成本': '#3de9d4','人工成本': '#1256dd','设备成本': '#39a0fe','其他费用成本': '#fff942'},notUseColors: [],optionData: [{name: '材料成本',value: 0,itemStyle: {opacity: 0.7,color: '#D6476C'}},{name: '劳务分包成本',value: 0,itemStyle: {opacity: 0.7,color: '#c79caa'}},{name: '人工成本',value: 0,itemStyle: {opacity: 0.7,color: '#804BC6'}},{name: '设备成本',value: 1,itemStyle: {opacity: 0.7,color: '#cbe5de'}},{name: '其他成本',value: 2,itemStyle: {opacity: 0.7,color: '#bfb6db'}}]}},mounted() {this.draw3d()},watch: {},methods: {draw3d(options) {this.optionData = this.getOptionData(options)console.log(this.optionData, '初始化')if (!this.optionData.length) {return}const echarts = this.$echarts// 基于准备好的dom,初始化echarts实例let chartPanel = echarts.init(document.getElementById('chart-panel'))// 传入数据生成 optionlet series = getPie3D(this.optionData, 1.35)let option = {tooltip: {formatter: (params) => {// console.log(params)if (params.seriesName !== 'mouseoutSeries' &&params.seriesName !== 'pie2d') {return `<div style="padding:0 10px;">${params.seriesName}:${(option.series[params.seriesIndex].pieData.proportion * 100).toFixed(2)}%</div>`}}},// left: 100,legend: {// data: legendData,// width: '90%',itemGap: 25,// bottom: 'bottom',icon: 'circle',top: 'center',right: 'right',textStyle: {color: this.colorText,fontSize: 14}},xAxis3D: {min: -1,max: 1},yAxis3D: {min: -1,max: 1},zAxis3D: {min: -1,max: 1},grid3D: {show: false, // 是否显示三维笛卡尔坐标系。boxHeight: 10, // 三维笛卡尔坐标系在三维场景中的高度boxDepth: 100,top: '-8.5%',left: 0,// bottom: '80%',// environment: "#021041", //背景viewControl: {// 用于鼠标的旋转,缩放等视角控制alpha: 50, // 角度distance: 200, // 调整视角到主体的距离,类似调整zoom 重要rotateSensitivity: 0, // 设置为0无法旋转zoomSensitivity: 0, // 设置为0无法缩放panSensitivity: 0, // 设置为0无法平移autoRotate: false // 自动旋转}},series: series}chartPanel.setOption(option)for (let i = 0; i < this.optionData.length; i++) {console.log(this.optionData[i].itemStyle.opacity, 'this.optionData[i].itemStyle.opacity')delete this.optionData[i].itemStyle.opacity}// 是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOptionoption.series.push({name: 'pie2d',type: 'pie',label: {// color: '#333333',fontSize: 12,//  position: 'inner',// formatter: "{b}\n\n",// padding: [0, -40],formatter: (item) => {//  console.log(item)return item.data.name + '\n\n' + item.percent + '%'}},labelLine: {length: 20,length2: 20,lineStyle: {// color: '#6ddb61',// width: 1.5// top: '0PX',// left: '50PX'}},startAngle: 330, // 起始角度,支持范围[0, 360]。 //重要clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式radius: ['40%', '65%'],center: ['50%', '50%'],data: this.optionData,itemStyle: {opacity: 0},left: '0%',top: '0%',avoidLabelOverlap: true // 防止标签重叠})chartPanel.setOption(option)this.initEchart()},getOptionData(options) {const optionData = []this.notUseColors = []console.log(options, 'dd')for (const key in options) {let color = this.backgroundDots[key]if (!color) {color = colors.find(s => !this.notUseColors.includes(s))}if (color) {this.notUseColors.push(color)}const data = {name: key,value: options[key],itemStyle: {opacity: 0.8,color: color}}optionData.push(data)}return optionData},initEchart() {this.$nextTick(() => {let parent = document.getElementById('chart-panel') // 获取父元素let canvas = parent.getElementsByTagName('canvas') // 获取父元素下面的所有canvas元素canvas[1].style.transform = 'rotateX(20deg)'// canvas[1].style.transform = 'rotateY(-20deg)'/* 为了对齐线 */canvas[1].style.top = '-15PX'canvas[1].style.left = '-10PX'})}}
}
</script><style scoped></style>

封装方法

// 生成模拟 3D 饼图的配置项
// pieData(object):饼图数据
// internalDiameterRatio(0~1之间的浮点数):内径/外径的值(默认值 1/2),当该值等于 0 时,
// heigth配置每个数据生成的高度
export function getPie3D(pieData, internalDiameterRatio, height) {let series = []let sumValue = 0let startValue = 0let endValue = 0let legendData = []let k =typeof internalDiameterRatio !== 'undefined'? (1 - internalDiameterRatio) / (1 + internalDiameterRatio): 1 / 3//  计算比例let total = 0for (let i = 0; i < pieData.length; i++) {pieData[i].value = Number(pieData[i].value)// console.log(Number(pieData[i].value))total += Number(pieData[i].value)}// console.log(total)for (let i = 0; i < pieData.length; i++) {pieData[i].proportion = parseFloat(pieData[i].value / total).toFixed(4)//  console.log(pieData[i].proportion)}// 为每一个饼图数据,生成一个 series-surface 配置for (let i = 0; i < pieData.length; i++) {sumValue += pieData[i].valuelet seriesItem = {name:typeof pieData[i].name === 'undefined'? `series${i}`: pieData[i].name,type: 'surface',parametric: true,wireframe: {show: false},pieData: pieData[i],pieStatus: {selected: pieData[i].selected ? pieData[i].selected : false,hovered: pieData[i].hovered ? pieData[i].hovered : false,k: k}}if (typeof pieData[i].itemStyle != 'undefined') {let itemStyle = {}typeof pieData[i].itemStyle.color != 'undefined'? (itemStyle.color = pieData[i].itemStyle.color): nulltypeof pieData[i].itemStyle.opacity != 'undefined'? (itemStyle.opacity = pieData[i].itemStyle.opacity): nullseriesItem.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// console.log(series[i]);series[i].pieData.startRatio = startValue / sumValueseries[i].pieData.endRatio = endValue / sumValueseries[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio,series[i].pieData.endRatio,series[i].pieStatus.selected,series[i].pieStatus.hovered,k,height ? series[i].pieData.proportion * height : 1 //自己自定义传入高度,每个类型按比例生成高度// series[i].pieData.value   ==>这个是饼图默认自己生成高度// 1 设置为1所有的扇形高度都一样高)startValue = endValuelegendData.push(series[i].name)}// console.log(series);return series
}// startRatio(浮点数): 当前扇形起始比例,取值区间[0, endRatio)
// endRatio(浮点数): 当前扇形结束比例,取值区间(startRatio, 1]
// isSelected(布尔值): 是否选中,效果参照二维饼图选中效果(单选)
// isHovered(布尔值): 是否放大,效果接近二维饼图高亮(放大)效果(未能实现阴影)
// k(0~1之间的浮点数):用于参数方程的一个参数,取值 0~1 之间,通过「内径 / 外径」的值换算而来。
//height配置3d扇形高度
export function getParametricEquation(startRatio,endRatio,isSelected,isHovered,k,height
) {// 计算let midRatio = (startRatio + endRatio) / 2let startRadian = startRatio * Math.PI * 2let endRadian = endRatio * Math.PI * 2let 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)let offsetX = isSelected ? Math.cos(midRadian) * 0.2 : 0let offsetY = isSelected ? Math.sin(midRadian) * 0.2 : 0// 计算高亮效果的放大比例(未高亮,则比例为 1)let 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)}return Math.sin(v) > 0 ? 1 * height : -1}}
}

Echarts 3d饼状图相关推荐

  1. 【echarts记录 -- 3d 饼状图实现】

    echarts记录 -- 3d 饼状图实现 实现效果 效果1 效果2 代码 实现效果 效果1 效果2 代码 /************************* pie3D 尝试更新时间: 2020. ...

  2. highcharts实现立体3D饼状图

    最近做一个h5活动页,设计师给我设计出了一个3D饼状图,我当时觉得没啥,觉得强大的echarts应该能做出来的,因为公司的项目涉及到图表的都用的echarts,但是后来去echarts官网一查,没这个 ...

  3. Jpgraph php怎么变异,php使用Jpgraph绘制3D饼状图的方法

    此文实例介绍了php使用Jpgraph绘制3D饼状图的方法.分享给大伙供大家参考.具体实现方法如下: include ("src/jpgraph.php"); include (& ...

  4. JFreeChart在Struts2中实现3D饼状图统计

    在Struts2中,用JFreeChart实现3D饼状图统计 前段时间学习了一下JFreeChart,现在来整理一下自己所作的实例. 下面分别用两种方式来实现: 一种是以java应用程序的方式,一种是 ...

  5. echarts制作饼状图如何设置不同类别之间有一定间隔?

    解决echarts饼状图不同类之间有一定间隔 用echarts制作饼状图时,为了有利于区分不同类别,一般通过设置不同的颜色代表不同的类别即可,但为了进一步体现不同类别之间的区分,可通过设置不同类别之间 ...

  6. Ehcarts绘制3D饼状图

    需要用到echarts.min.js和echarts-gl.min.js 网上找了半天没找到靠谱的自己查资料弄一个了方便自己以后看 直接复制到html文件中即可运行 <!DOCTYPE html ...

  7. highcharts实现3D饼状图

    刚接触前端的时候作图大多数时候都用echarts,但今天项目中一个需求是要实现3D的饼状图,所以转向highcharts来实现,具体实现过程如下. 首先要引入所需的js文件,在官网详细说明该引入那些j ...

  8. python饼状图颜色一样_使用echarts画饼状图,设置饼状图颜色

    前言: 前面已经跟大家分享了使用echarts画柱状图.折线图,一些之前自己遇到的坑也跟大家说了,这次就不再赘述.官方有配置文档,很详细,大家不懂的地方也可以交流. 今日分享重点:画饼状图. 1.引入 ...

  9. 使用echarts画饼状图,设置饼状图颜色

    前言: 使用echarts遇到过的坑: 一定要给图表容器添加宽度与高度. 图表在容器中可以调整位置,让图表显示的更完整. 今日分享重点:画饼状图. 1.引入相关js <script type=& ...

最新文章

  1. 模拟一下goldengate中断后,重新同步操作
  2. 几款xshell绝佳配色方案
  3. MySQL 磁盘空间不够用 方案_Mysql数据磁盘不足,不停机扩容方案
  4. mysql存储过程打不开了_请问mysql存储过程的问题,我找了几个例子一个都运行不起来,...
  5. HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别
  6. 孙宇晨终于和巴菲特共进晚餐 还赠送数字币作为见面礼
  7. ps练习实例_拥有一份史上最全面的50集ps抠图学习教程是什么一种体验?
  8. python和循环语句_Python 小白零基础入门 -- 条件语句和循环语句
  9. windows C++删除非空文件夹
  10. Procexp.exe —— 强大的进程管理器
  11. 康佳电视系统升级服务器地址,康佳电视各平台升级方法及强制刷机汇总
  12. python个人所得税怎么写_Python计算个人所得税!
  13. 增长黑客读书笔记(一)搭建增长团队
  14. transact sql mysql_Sql Server数据库常用Transact-SQL脚本(推荐)
  15. (React入门)ref
  16. 博科光纤交换机常用命令
  17. matlab中将数据导出到Excel表格、.txt、.xml等文件中
  18. 彻底解决Torch[mat1 dim 1 must match mat2 dim 0]
  19. 从通达信中获取得到股票、期货等金融标的的分时数据。
  20. Brightcove推出业务连续性套件,以帮助安全地管理业务沟通

热门文章

  1. 怎样把照片中的头像扶正_在水下摄影中,怎样拍出好看的鱼类照片
  2. Flask之jinja2模板(二)
  3. 一文带你分分钟掌握智能手机处理器的前世今生,再也不用担心妈妈老婆女友让我选手机啦
  4. 全国首个!这所双一流大学成立人工智能教育学部
  5. 2021-2027中国半导体掩膜版市场现状及未来发展趋势
  6. 商汤科技2021届校园招聘+两大顶尖人才计划强势来袭
  7. 策划,程序,美术,运营,市场,你到底有多重要?
  8. [SpringMVC笔记] SpringMVC-18-拦截器链配置
  9. 大连四六级英语培训百家外语英语四六级和雅思考试难度差多少?
  10. DVD压缩碟简单制作