3D饼环图
参考博客
https://blog.csdn.net/m0_67266787/article/details/123155878
插件引入
- echarts.js
- echarts-gl.min.js
效果图

代码
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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 |
| }) |
| |
| 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) |
| } |
| |
| |
| |
| 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 / sumValue, 4) |
| legendData.push({ |
| name: series[i].name, |
| value: bfb |
| }) |
| legendBfb.push({ |
| name: series[i].name, |
| value: bfb |
| }) |
| } |
| let legends_left = legendData.splice(0, legendData.length / 2) |
| const boxHeight = getHeight3D(series, pieHeight) + 0.005 |
| |
| const option = { |
| legend: [{ |
| show: true, |
| data: legends_left, |
| orient: 'horizontal', |
| right: 50, |
| top: -5, |
| itemHeight: 15, |
| itemWidth: 15, |
| itemGap: 80, |
| textStyle: { |
| color: '#fff', |
| rich: { |
| value: { |
| fontSize: 22, |
| width: 50, |
| color: "#fff", |
| fontWeight: 800, |
| lineHeight: 30 |
| }, |
| name: { |
| width: 50, |
| fontSize: 14, |
| color: "#565F68", |
| } |
| } |
| }, |
| icon: 'rect', |
| formatter: function (param) { |
| const item = legendBfb.filter(item => item.name === param)[0] |
| const bfs = fomatFloat(item.value * 100, 2) + '%' |
| return [ |
| `{value|${bfs}}`, |
| `{name|${item.name}}` |
| ].join('\n') |
| }, |
| }, { |
| show: true, |
| data: legendData, |
| orient: 'horizontal', |
| right: 50, |
| top: 55, |
| itemHeight: 15, |
| itemWidth: 15, |
| itemGap: 80, |
| textStyle: { |
| color: '#fff', |
| rich: { |
| value: { |
| fontSize: 22, |
| color: "#fff", |
| fontWeight: 800, |
| lineHeight: 30, |
| width: 50, |
| }, |
| name: { |
| fontSize: 14, |
| color: "#565F68", |
| width: 50, |
| } |
| } |
| }, |
| icon: 'rect', |
| formatter: function (param) { |
| const item = legendBfb.filter(item => item.name === param)[0] |
| const bfs = fomatFloat(item.value * 100, 2) + '%' |
| return [ |
| `{value|${bfs}}`, |
| `{name|${item.name}}` |
| ].join('\n') |
| } |
| }], |
| labelLine: { |
| show: true, |
| lineStyle: { |
| color: '#fff' |
| } |
| }, |
| label: { |
| show: true, |
| position: 'center', |
| formatter: '{b} {c} {d}%' |
| }, |
| tooltip: { |
| backgroundColor: '#033b77', |
| borderColor: '#21f2c4', |
| textStyle: { |
| color: '#fff', |
| fontSize: 13 |
| }, |
| formatter: params => { |
| if ( |
| params.seriesName !== 'mouseoutSeries' && |
| params.seriesName !== 'pie2d' |
| ) { |
| const bfb = ( |
| (option.series[params.seriesIndex].pieData.endRatio - |
| 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;background-color:${params.color};"></span>` + |
| `${bfb}%` |
| ) |
| } |
| } |
| }, |
| xAxis3D: { |
| min: -1, |
| max: 1 |
| }, |
| yAxis3D: { |
| min: -1, |
| max: 1 |
| }, |
| zAxis3D: { |
| min: -1, |
| max: 1 |
| }, |
| grid3D: { |
| show: false, |
| left: -190, |
| boxHeight: boxHeight, |
| viewControl: { |
| |
| alpha, |
| distance, |
| rotateSensitivity: 0, |
| zoomSensitivity: 0, |
| panSensitivity: 0, |
| autoRotate: false |
| } |
| }, |
| series: series |
| } |
| return option |
| } |
| |
| |
| |
| |
| 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 = typeof k !== 'undefined' ? k : 1 / 3 |
| |
| const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0 |
| const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0 |
| |
| const hoverRate = isHovered ? 1.1 : 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 |
| } |
| } |
| } |
| |
| |
| |
| |
| 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) |
| let s = f.toString() |
| let rs = s.indexOf('.') |
| |
| if (rs < 0) { |
| rs = s.length |
| s += '.' |
| } |
| while (s.length <= rs + n) { |
| s += '0' |
| } |
| return s |
| } |
| var option_6 = getPie3D(optionData, 0.8, 110, 20, 15, 1); |
| |
| myChart_6.setOption(option_6); |
| let hoveredIndex = '' |
| let optionName = 'option_6' |
| myChart_6.on('mouseover', (params) => { |
| |
| let isSelected |
| let isHovered |
| let startRatio |
| let endRatio |
| let k |
| |
| |
| |
| if (hoveredIndex === params.seriesIndex) { |
| |
| } else { |
| |
| if (hoveredIndex !== '') { |
| |
| 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 |
| |
| this[optionName].series[ |
| hoveredIndex |
| ].parametricEquation = getParametricEquation( |
| startRatio, |
| endRatio, |
| isSelected, |
| isHovered, |
| k, |
| this[optionName].series[hoveredIndex].pieData.value |
| ) |
| this[optionName].series[hoveredIndex].pieStatus.hovered = isHovered |
| |
| hoveredIndex = '' |
| } |
| |
| if ( |
| params.seriesName !== 'mouseoutSeries' && |
| params.seriesName !== 'pie2d' |
| ) { |
| |
| isSelected = |
| this[optionName].series[params.seriesIndex].pieStatus.selected |
| isHovered = true |
| startRatio = |
| this[optionName].series[params.seriesIndex].pieData.startRatio |
| endRatio = this[optionName].series[params.seriesIndex].pieData.endRatio |
| k = this[optionName].series[params.seriesIndex].pieStatus.k |
| |
| this[optionName].series[ |
| params.seriesIndex |
| ].parametricEquation = getParametricEquation( |
| startRatio, |
| endRatio, |
| isSelected, |
| isHovered, |
| k, |
| this[optionName].series[params.seriesIndex].pieData.value + 60 |
| ) |
| this[optionName].series[ |
| params.seriesIndex |
| ].pieStatus.hovered = isHovered |
| |
| hoveredIndex = params.seriesIndex |
| } |
| |
| myChart_6.setOption(this[optionName]) |
| } |
| }) |
| |
| myChart_6.on('globalout', () => { |
| |
| let isSelected |
| let isHovered |
| let startRatio |
| let endRatio |
| let k |
| if (hoveredIndex !== '') { |
| |
| 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 |
| |
| this[optionName].series[ |
| hoveredIndex |
| ].parametricEquation = getParametricEquation( |
| startRatio, |
| endRatio, |
| isSelected, |
| isHovered, |
| k, |
| this[optionName].series[hoveredIndex].pieData.value |
| ) |
| this[optionName].series[hoveredIndex].pieStatus.hovered = isHovered |
| |
| hoveredIndex = '' |
| } |
| |
| myChart_6.setOption(this[optionName]) |
| }) |
| |
复制
仪表盘
插件引入
效果图

代码
| var val = 36.5; |
| var value = val / 100; |
| var startAngle = 215; |
| var endAngle = -30; |
| var splitCount = 40; |
| var fontSize = 45; |
| var pointerAngle = (startAngle - endAngle) * (1 - value) + endAngle; |
| option = { |
| backgroundColor: "#062a44", |
| tooltip: { |
| show: true, |
| }, |
| title: { |
| show: true, |
| x: "center", |
| y: "70%", |
| text: "示例详情", |
| textStyle: { |
| color: "#1483ED", |
| fontWeight: "bold", |
| fontSize: 25, |
| }, |
| }, |
| series: [ |
| { |
| |
| type: "gauge", |
| radius: "75%", |
| startAngle: pointerAngle, |
| endAngle: endAngle, |
| splitNumber: 1, |
| axisLine: { |
| show: false, |
| lineStyle: { |
| width: 4, |
| opacity: 0, |
| }, |
| }, |
| title: { |
| show: false, |
| }, |
| detail: { |
| color: "#fff", |
| fontSize, |
| offsetCenter: [0, 0], |
| formatter: `${val}%`, |
| }, |
| splitLine: { |
| show: false, |
| }, |
| axisTick: { |
| length: 20, |
| splitNumber: Math.ceil((1 - value) * splitCount), |
| lineStyle: { |
| color: "#2E3B4A", |
| width: 3, |
| }, |
| }, |
| axisLabel: { |
| show: false, |
| }, |
| pointer: { |
| show: false, |
| }, |
| itemStyle: {}, |
| markPoint: { |
| animation: true, |
| silent: false, |
| data: [ |
| { |
| symbolSize: 280, |
| itemStyle: { |
| borderWidth: 3, |
| }, |
| }, |
| { |
| symbol: "circle", |
| symbolSize: 200, |
| }, |
| ], |
| }, |
| data: [ |
| { |
| value: value, |
| name: "test gauge", |
| }, |
| ], |
| }, |
| { |
| |
| type: "gauge", |
| radius: "75%", |
| startAngle: startAngle, |
| endAngle: pointerAngle, |
| splitNumber: 1, |
| axisLine: { |
| show: false, |
| lineStyle: { |
| width: 3, |
| opacity: 0, |
| }, |
| }, |
| tooltip: { |
| show: true, |
| }, |
| title: { |
| show: false, |
| }, |
| detail: { |
| show: false, |
| }, |
| splitLine: { |
| show: false, |
| }, |
| axisTick: { |
| length: 20, |
| splitNumber: Math.ceil(value * splitCount), |
| lineStyle: { |
| color: "#0096FD", |
| width: 3, |
| }, |
| }, |
| axisLabel: { |
| show: false, |
| }, |
| pointer: { |
| show: false, |
| }, |
| itemStyle: {}, |
| data: [ |
| { |
| value: value, |
| name: "test gauge", |
| }, |
| ], |
| }, |
| ], |
| }; |
| |
复制
电池图
插件引入
效果图

代码
| var option_4 = { |
| grid: [{ |
| left: 55, |
| bottom: 40, |
| top: 20, |
| right: 10 |
| }], |
| yAxis: { |
| show: true, |
| axisLine: { |
| show: true, |
| lineStyle: { |
| color: "#fff", |
| width: 1, |
| type: 'solid', |
| opacity: 1 |
| }, |
| |
| }, |
| axisTick: { |
| show: false, |
| inside: false, |
| length: 5, |
| lineStyle: { |
| color: "#fff", |
| width: 1, |
| } |
| }, |
| axisLabel: { |
| show: true, |
| color: "#fff", |
| fontSize: 12, |
| rotate: 0, |
| }, |
| splitLine: { |
| show: true, |
| lineStyle: { |
| color: ['#fff'], |
| type: 'dashed', |
| opacity: .5 |
| } |
| } |
| }, |
| xAxis: { |
| data: category, |
| show: true, |
| axisLabel: { |
| color: '#a9aabc', |
| fontSize: 12, |
| interval: 0, |
| padding: [10, 0, 0, 0], |
| formatter: function (params) { |
| var newParamsName = ""; |
| var paramsNameNumber = params.length; |
| var provideNumber = 5; |
| var rowNumber = Math.ceil(paramsNameNumber / provideNumber); |
| if (paramsNameNumber > provideNumber) { |
| for (var p = 0; p < rowNumber; p++) { |
| var tempStr = ""; |
| var start = p * provideNumber; |
| var end = start + provideNumber; |
| if (p == rowNumber - 1) { |
| tempStr = params.substring(start, paramsNameNumber); |
| } else { |
| tempStr = params.substring(start, end) + "\n"; |
| } |
| newParamsName += tempStr; |
| } |
| } else { |
| newParamsName = params; |
| } |
| return newParamsName; |
| } |
| }, |
| axisLine: { |
| show: false |
| }, |
| axisTick: { |
| show: false, |
| }, |
| }, |
| tooltip: { |
| trigger: 'axis', |
| formatter: '时间:{b} <br/>订单数:{c0}', |
| backgroundColor: "rgba(8, 36, 92, 0.8)", |
| axisPointer: { |
| type: 'none' |
| } |
| }, |
| |
| series: [{ |
| name: '', |
| type: 'pictorialBar', |
| symbol: 'roundRect', |
| barWidth: '11%', |
| barMaxWidth: '20%', |
| symbolMargin: '3', |
| animationDelay: (dataIndex, params) => { |
| return params.index * 50; |
| }, |
| itemStyle: { |
| normal: { |
| color: "#1EE6E7" |
| |
| } |
| }, |
| z: 1, |
| symbolRepeat: true, |
| symbolSize: [15, 6], |
| data: count, |
| animationEasing: 'elasticOut', |
| label: { |
| normal: { |
| show: true, |
| position: 'top', |
| textStyle: { |
| color: "#fff" |
| } |
| } |
| }, |
| |
| }] |
| } |
复制