赞
踩
1、需要安装
import * as echarts from 'echarts'
import 'echarts-gl'
2、使用方法
/** * 需要引入扩展资源 https://cdn.jsdelivr.net/npm/echarts-gl@2/dist/echarts-gl.min.js * 实际项目中需要安装【echarts-gl】插件 * (vue)使用中引入 import "echarts-gl"; */ /** * getParametricEquation 生成扇形的曲面参数方程 生成 3D 扇形环曲面 * @param{} startRatio(浮点数): 当前扇形起始比例,取值区间 [0, endRatio) * @param{} endRatio(浮点数): 当前扇形结束比例,取值区间 (startRatio, 1] * @param{} isSelected(布尔值):是否选中,效果参照二维饼图选中效果(单选) * @param{} isHovered(布尔值): 是否放大,效果接近二维饼图高亮(放大)效果(未能实现阴影) * @param{} k(0~1之间的浮点数):用于参数方程的一个参数,取值 0~1 之间,通过「内径/外径」的值换算而来。 * @param{} h :饼图的初始高度 */ function 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.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(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(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(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; } // 当前图形的高度是Z根据h(每个value的值决定的) return Math.sin(v) > 0 ? 1 * h * 0.1 : -1; } }; } // 饼图数据 var optionData = [ { name: "日化", value: 60 }, { name: "冻品", value: 44 }, { name: "粮食", value: 24 }, { name: "日化1", value: 60 }, { name: "冻品1", value: 44 }, { name: "粮食1", value: 24 }, { name: "日化2", value: 60 }, { name: "冻品2", value: 44 }, { name: "粮食2", value: 24 } ]; // 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环 function 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; 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 } }; if (typeof pieData[i].itemStyle !== "undefined") { const { itemStyle } = pieData[i]; // eslint-disable-next-line no-unused-expressions typeof pieData[i].itemStyle.color !== "undefined" ? (itemStyle.color = pieData[i].itemStyle.color) : null; // eslint-disable-next-line no-unused-expressions typeof pieData[i].itemStyle.opacity !== "undefined" ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null; seriesItem.itemStyle = itemStyle; } series.push(seriesItem); } 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; series[i].parametricEquation = getParametricEquation( series[i].pieData.startRatio, series[i].pieData.endRatio, false, false, k, 10 // 在此处传入饼图初始高度h ); startValue = endValue; legendData.push(series[i].name); } // 准备待返回的配置项,把准备好的series 传入。 const option = { backgroundColor: "#123756", title: { text: "立体旋转饼图/环图", top: "1%", textAlign: "left", left: "1%", textStyle: { color: "#38adb9", fontSize: 32, fontWeight: "600" } }, legend: { show: true, type: "scroll", right: 10, top: 10, orient: "vertical", // 纵向 icon: "circle", // icon 类型 itemHeight: 12, // icon高度 itemWidth: 12, // icon 宽度 itemGap: 5, // 图例间隔 textStyle: { color: "#709DD9", fontSize: 12, fontWeight: "400" }, formatter: name => { if (pieData.length) { const item = pieData.filter(item => item.name === name)[0]; return ` ${name}:${item.value}`; } } }, color: ["#159AFF", "#66E1DF", "#66E193", "#E3F170", "#FFAD6A", "#ffe0ab", "#6bc5f4", "#c08ef2", "#ffda49"], tooltip: { formatter: params => { if (params.seriesName !== "mouseoutSeries") { return `${params.marker}${params.seriesName}:${pieData[params.seriesIndex].value}`; } return ""; } }, xAxis3D: { min: -1, max: 1 }, yAxis3D: { min: -1, max: 1 }, zAxis3D: { min: -1, max: 1 }, grid3D: { show: false, boxHeight: 15, // 修改立体饼图的高度 top: "-10%", left: "0%", viewControl: { // 3d效果可以放大、旋转等, alpha: 20, // 饼图翻转的程度 beta: 30, rotateSensitivity: 1, zoomSensitivity: 0, panSensitivity: 0, autoRotate: true, // 是否自动旋转 distance: 300 // 距离越小看到的饼图越大 } }, series }; return option; } option = getPie3D(optionData, 0)
3、案例
<template> <!-- 病种分类 --> <div class="age_distribution"> <div class="title">{{ title }}</div> <div id="age"></div> <div class="bg"></div> </div> </template> <script> import * as echarts from 'echarts' import 'echarts-gl' export default { props: ['title'], data() { return {} }, mounted() { this.getPeople() }, methods: { // 折线图 getPeople() { var myChart = echarts.init(document.getElementById('age')) function 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.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(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(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(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 } // 当前图形的高度是Z根据h(每个value的值决定的) return Math.sin(v) > 0 ? 1 * h * 0.1 : -1 } } } // 饼图数据 var optionData = [ { name: '18岁以下', value: 7140 }, { name: '19-30岁', value: 8991 }, { name: '31-40岁', value: 37455 }, { name: '41-50岁', value: 25490 }, { name: '51-60岁', value: 7161 } ] function 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 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, radius: ['40%', '60%'], type: 'surface', parametric: true, wireframe: { show: false }, pieData: pieData[i], pieStatus: { selected: false, hovered: false, k } } if (typeof pieData[i].itemStyle !== 'undefined') { const { itemStyle } = pieData[i] // eslint-disable-next-line no-unused-expressions typeof pieData[i].itemStyle.color !== 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null // eslint-disable-next-line no-unused-expressions typeof pieData[i].itemStyle.opacity !== 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null seriesItem.itemStyle = itemStyle } // series = getPie3D(optionData, 0.3) series.push(seriesItem) } 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 series[i].parametricEquation = getParametricEquation( series[i].pieData.startRatio, series[i].pieData.endRatio, false, false, k, 10 // 在此处传入饼图初始高度h ) startValue = endValue legendData.push(series[i].name) } // 准备待返回的配置项,把准备好的series 传入。 const option = { // backgroundColor: '#123756', title: { show: false // text: '', // top: '1%', // textAlign: 'left', // left: '1%', // textStyle: { // color: '#38adb9', // fontSize: 32, // fontWeight: '600' // } }, // 右边提示文本 legend: { show: true, type: 'scroll', right: 50, top: 60, orient: 'vertical', // 纵向 icon: 'rect', // icon 类型 标记类型包括 'circle'圆, 'rect'方, 'roundRect'圆角, 'triangle'三角形, 'diamond'lin, 'arrow'箭头, 'pin', 'arrow', 'none' itemHeight: 12, // icon高度 itemWidth: 12, // icon 宽度 itemGap: 10, // 图例间隔 --每个title之间的间隔 data: legendData, textStyle: { color: '#709DD9', fontSize: 12, fontWeight: '400' }, formatter: name => { if (pieData.length) { const item = pieData.filter(item => item.name === name)[0] // console.log(item, name) var arr = [`{a|${name} :}`, `{b|${item.value}人}`] return arr // return `${name}:${item.value}` } }, textStyle: { rich: { //改样式 和下面formatter一起 a: { color: '#fff', fontSize: 12 // 字体大小被覆盖了,这里重新定义 }, b: { color: '#59e6ed', fontSize: 12 } } } }, // 每一块区域的颜色 color: ['#9f76f2', '#2a9dff', '#fac924', '#5ce5ff', '#6573f3'], tooltip: { formatter: params => { if (params.seriesName !== 'mouseoutSeries') { return `${params.marker}${params.seriesName}:${pieData[params.seriesIndex].value}人` } return '' } }, xAxis3D: { min: -1, max: 1 }, yAxis3D: { min: -1, max: 1 }, zAxis3D: { min: -1, max: 1 }, grid3D: { show: false, boxHeight: 25, // 修改立体饼图的高度 top: '5%', left: '-15%', viewControl: { // 3d效果可以放大、旋转等, alpha: 40, // 饼图翻转的程度 beta: 30, // projection: 'perspective',//默认为透视投影'perspective',也支持设置为正交投影'orthographic' rotateSensitivity: 1, zoomSensitivity: 0, panSensitivity: 0, autoRotateSpeed: 50, //物体自传的速度 autoRotate: true, // 是否自动旋转 distance: 350 // 距离越小看到的饼图越大 } }, series } return option } // 可做为调整内环大小 0为实心圆饼图,大于0 小于1 为圆环 let option = getPie3D(optionData, 0) myChart.setOption(option) // 让图表自适应容器大小 window.addEventListener('resize', function () { myChart.resize() }) } } } </script> <style lang="less" scoped> .age_distribution { position: relative; width: 100%; height: 100%; background-image: url('../../assets/box_card.png'); background-repeat: no-repeat; background-size: 100% 100%; .title { position: absolute; top: -7px; left: 50%; transform: translateX(-50%); font-size: 17px; font-family: PingFang SC, PingFang SC; color: #ffffff; letter-spacing: 2px; } #age { z-index: 3; width: 100%; height: 100%; } .bg { z-index: 2; position: absolute; background-image: url('../../assets/bottom_img_age.png'); top: 9%; left: 10%; background-size: 100% 100%; width: 50%; height: 84%; } } </style>
效果图:
需要底座背景图自取
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。