关于higcharts3D饼图及同心圆的实现
最近一直在忙着做公司的数据可视化大屏项目,做了差不多有四五个的样子,今天偶然看见一篇写关于echarts的地图数据定时弹框的文章,索性自己开始写一篇关于highcharts3d的实现方法。
准备工作
- 安装
npm install highcharts --save
- 引入highcharts文件
import Highcharts from 'highcharts/highstock';
import Highcharts3D from 'highcharts/highcharts-3d';
Highcharts3D(Highcharts);
- 参数公共配置文件 chartConfig.js
export function get3DPieOption(){
let option = {
chart: {
type: 'pie',
events:{
load: function() {
var each = Highcharts.each,
points = this.series[0].points;
each(points, function(p, i) {
p.graphic.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side1.attr({
translateY: -p.shapeArgs.ran
});
p.graphic.side2.attr({
translateY: -p.shapeArgs.ran
});
});
}
},
options3d: {
enabled: true, // 开启3d
alpha: 55,
beta: 0
}
},
title: {
text:''
},
// 千以上的数字去掉空格
lang: {
thousandsSep: ''
},
// 隐藏版权信息
credits:{
enabled:false
},
colors:['#24BFFF', '#FCBE31', '#F74D52'],
plotOptions: {
pie: {
center: [200, 71],
size: 230,
innerSize: 180, // 设置同心圆
depth: 25,
allowPointSelect: false,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true,
point: {
events: {
legendItemClick: function (event){
return false; //return true 则表示允许切换
}
}
}
}
},
// 定时显示文本框配置, 可按照自身内容修改
tooltip: {
enabled: true,
shared: true,
backgroundColor: 'rgba(0, 33, 90, 0.8)',
borderColor: '#4289D0',
borderRadius: 0,
followPointer: true,
useHTML: true,
style: {
fontSize: 14,
color: '#D9E8FF'
},
headerFormat: '<div style="width: auto;height: 50px;padding: 5px 2px;position: relative;">',
pointFormat: '<div style="position:absolute;left: -10px; top: -10px;width:15px;height: 15px;border: 2px solid #4289D0;border-bottom:none;border-right: none;"></div>'+
'<div style="position:absolute;right: -10px; top: -10px;width:15px;height: 15px;border: 2px solid #4289D0;border-bottom:none;border-left: none;"></div>'+
'<div style="position:absolute;left: -10px; bottom: -10px;width:15px;height: 15px;border: 2px solid #4289D0;border-top:none;border-right: none;"></div>'+
'<div style="position:absolute;right: -10px; bottom: -10px;width:15px;height: 15px;border: 2px solid #4289D0;border-top:none;border-left: none;"></div>'+
'<p style="padding-bottom: 3px;letter-spacing: 2px;">{point.name}:'+
'<span style="color: #01DEFF;">{point.y}个</span></p>',
footerFormat: '</div>',
},
series: [{ type: 'pie', zIndex:1, size:'95%', // 设置饼图的大小 center:['50%','75%'], // 设置饼图的位置
allowPointSelect: false,
dataLabels: {
enabled: false,
},
name:'3D 饼图'
},{
type: 'pie',
zIndex:0,
depth: 15,
center:['50%','75%'],
name: '背景',
colors:['#215795'],
allowPointSelect: false,
dataLabels: {
enabled: false,
},
data:[
{
name:'背景',
y:1,
h:1,
sliced: true,
selected: true
}
]
}]
};
return option
}
起码
- 引入配置文件
import {get3DCircularDiagram} from '../chartConfig'
- 调用公共方法,渲染高度及参数配置
methods: {
/***
* 初始化图表
*/
initChart(){
let data = [{name: 'A', value: 30}, {name: 'B', value: 80}, {name: 'C', value: 70}]
let f= function f(a,b) { // 排序函数
return (a - b);
}
// 获取配置参数
let option = get3DPieOption();
let datas = data.map((item,index)=>{
let formatData = {
name: item.name,
y: Number(item.value),
h: 8
}
return {...formatData , sliced: true,selected: true }
})
option.series[0].data = datas;
let charts = Highcharts.chart(chartId, option);
let d = charts?.series[0]?.data;
// 实现信息弹框动态展示
if(data.length > 0) {
let index = 0, length = data.length - 1, k = null; // 播放所在下标
this.timer = setInterval(function() {
k = index === 0 ? length : index - 1;
charts?.series?.[0]?.data[k].update({
h: 8
});
charts?.series?.[0]?.data[index].update({
h: 25
});
charts?.tooltip?.refresh([d[index]]);
index++;
if(index >= data.length) {
index = 0;
}
}, 5000);
}
}
}
- 在mounted中调用wrap方法、initChart方法
mounted() {
this.initChart();
}
- 按数据大小实现饼图高度
methods: {
initChart(){
let data = [{name: 'A', value: 30}, {name: 'B', value: 80}, {name: 'C', value: 70}]
let f= function f(a,b) { // 排序函数
return (a - b);
}
// 获取配置参数
let option = get3DPieOption();
// 对值进行排序
let paixu = data.map(item=>{
return Number(item.value);
});
paixu.sort(f);
let datas = data.map((item,index)=>{
let h = paixu.indexOf(Number(item.value))+1
let formatData = {
name: item.name,
y: Number(item.value),
h: h*8 // 根据排序,设置高度
}
return {...formatData , sliced: true,selected: true }
})
option.series[0].data = datas;
Highcharts.chart(chartId, option);
},
/***
* 处理 Highcharts 3D 模型
*/
wrap(){
let H = Object.assign({}, Highcharts)
var each = H.each,
round = Math.round,
cos = Math.cos,
sin = Math.sin,
deg2rad = Math.deg2rad;
H.wrap(H.seriesTypes.pie.prototype, 'translate', function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
if (!this?.chart?.is3d()) {
return;
}
var series = this,
chart = series.chart,
options = chart.options,
seriesOptions = series.options,
depth = seriesOptions.depth || 0,
options3d = options.chart.options3d,
alpha = options3d.alpha,
beta = options3d.beta,
z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
z += depth / 2;
if (seriesOptions.grouping !== false) {
z = 0;
}
each(series.data, (point)=> {
var shapeArgs = point.shapeArgs,
angle;
point.shapeType = 'arc3d';
var ran = point.options.h;
shapeArgs.z = z;
shapeArgs.depth = depth * 0.75 + ran;
shapeArgs.alpha = alpha;
shapeArgs.beta = beta;
shapeArgs.center = series.center;
shapeArgs.ran = ran;
angle = (shapeArgs.end + shapeArgs.start) / 2;
point.slicedTranslation = {
translateX: round(cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)),
translateY: round(sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad))
};
});
});
H.wrap(H.SVGRenderer.prototype, 'arc3dPath', function(proceed){
let ret = proceed.apply(this, [].slice.call(arguments, 1));
ret.zTop = (ret.zOut +1) / 100;
return ret;
});
}
}
- 在mounted()中,在initChart()前调用wrap()方法
mounted() {
this.wrap();
this.initChart();
}
嗯,弄了一早上文档,摸鱼结束,现在开始上班了。请大佬们多多指正,谢谢大家!