赞
踩
安装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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。