最近做可视化比较多,就常用的图表类型做了一下总结。
因为做可视化的图表代码量非常大,所以会把echarts图表单独抽离出来,封装成一个组件,也可以复用,所以这里我直接把封装的组件直接放在这里,是可以直接拿来用的,根据所需稍作修改即可。
这里都是用的vue3,其实和vue2差不多,在写法上稍作修改即可。
其中用到了一个 fontChart 的方法,这样是为了在window变化(改变缩放)的时候能够让字体也达到自适应,因为默认的单位是px,如果不使用的话,当我们去减小屏幕缩放的时候,这时候屏幕分辨率就会变大,但是我们的字体还是xxpx,就会让我们的字体看上去特别小,所以这里使用了这个方法,fontChart方法如下:
scr/utils/echartPxToRem.js
export function fontChart(res) {let docEl = document.documentElement,clientWidth =window.innerWidth ||document.documentElement.clientWidth ||document.body.clientWidth;if (!clientWidth) return;// 此处的3840 为设计稿的宽度,记得修改!let fontSize = clientWidth / 1920;return res * fontSize;
}
接下来正题:
第一步首先安装 highcharts
npm install highcharts --save
第二步 main.js 引入 3d相关
import highcharts from 'highcharts'
import highcharts3d from 'highcharts/highcharts-3d'highcharts3d(highcharts)
然后封装成组件
一. 3D饼图
<template><div :id="id" style="width: 100%; height: 100%"></div>
</template>
<script setup>
import highcharts from "highcharts";
import { fontChart } from "@/utils/echartPxToRem";
import { onMounted, watch, onUnmounted } from "vue";const props = defineProps({id: {type: String,required: true,},pieData: {type: Array,default: () => ([["综采", 3],["综掘", 6],["胶带运输", 4],["排水", 3],["通风", 3],["压风", 4],]),},
});watch(() => props.pieData,(newValue) => {initOption();},{deep: true,}
);onMounted(() => {initOption();window.addEventListener("resize", initOption);
});onUnmounted(() => {window.removeEventListener("resize", initOption);
});
// 初始化echarts
const initOption = () => {let option = {chart: {backgroundColor: "none",type: "pie", //饼图margin: [0, 0, 0, 100],options3d: {enabled: true, //使用3d功能alpha: 18, //延y轴向内的倾斜角度beta: 0,},},title: {text: "", //图表的标题文字},plotOptions: {pie: {allowPointSelect: true, //每个扇块能否选中cursor: "pointer", //鼠标指针depth: fontChart(105), //饼图的厚度showInLegend: true, // 是否显示图例// center: ['30%', '60%'],size: "78%",dataLabels: {enabled: true, //是否显示饼图的线形tipdistance: -fontChart(35),align: "center",// position:'center',format: "<b>{point.y}</b>",style: {fontSize: fontChart(13),},},events: {//点击事件click: () => {},},},},colors: ["#59678c", "#1760bc", "#1890ff", "#06c8cd", "#03ac32", "#acff02"],legend: {align: "left", //水平方向位置verticalAlign: "top", //垂直方向位置layout: "vertical",x: fontChart(20),y: fontChart(40),symbolWidth: fontChart(10),symbolHeight: fontChart(10),symbolRadius: 0,itemMarginBottom: fontChart(4),itemStyle: {color: "#f4f4f6",fontSize: fontChart(14),},},credits: {enabled: false, // 禁用版权信息},series: [{type: "pie",name: "", //统一的前置词,非必须data: props.pieData,},],};highcharts.chart(props.id, option);
};
</script>
二. 3D不同高度环形图
Vue2写法
<template><div :id="id" style="height: 100%; width: 100%"></div>
</template>
<script>
import highcharts from "highcharts";
import { fontChart } from "@/utils/echartPxToRem";
export default {props: {id: {type: String,required: true,},dataList: {type: Array,default: () => ([{name: "红草莓",y: 10254,h: 0,bfb: 0},{name: "白草莓",y: 6894,h: 0,bfb: 0},{name: "红颜草莓",y: 7667,h: 0,bfb: 0},{name: "甜宝草莓",y: 4287,h: 0,bfb: 0},{name: "红颜草莓",y: 8687,h: 0,bfb: 0},{name: "甜宝草莓",y: 16112,h: 0,bfb: 0}])}},watch: {dataList() {this.$nextTick(() => {this.initOption();});},},mounted() {// this.$nextTick(() => {this.initOption();// });window.addEventListener("resize", this.initOption);},destroyed() {window.removeEventListener("resize", this.initOption);},methods: {initOption() {let quantity = 0; // 总数this.dataList.forEach((item) => {quantity += item.y;});this.dataList.forEach((item) => {item.bfb = parseInt((item.y / quantity) * 100);item.h = item.bfb * 1.5 >= 70 ? 70 : item.bfb * 1.5// item.h = parseInt(0.86 * item.bfb); // 最高高度60,根据比例渲染高度// console.log(this.dataList, "dataList----->>>");});// 修改3d饼图绘制过程var each = highcharts.each,round = Math.round,cos = Math.cos,sin = Math.sin,deg2rad = Math.deg2rad;highcharts.wrap(highcharts.seriesTypes.pie.prototype,"translate",function (proceed) {proceed.apply(this, [].slice.call(arguments, 1));// Do not do this if the chart is not 3Dif (!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, function (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)),};});});(function (H) {H.wrap(highcharts.SVGRenderer.prototype,"arc3dPath",function (proceed) {// Run original proceed methodvar ret = proceed.apply(this, [].slice.call(arguments, 1));ret.zTop = (ret.zOut + 0.5) / 100;return ret;});})(highcharts);highcharts.chart(this.id, {chart: {animation: false,backgroundColor: "none",type: "pie", //饼图margin: [0, 0, 0, 0],options3d: {enabled: true, //使用3d功能alpha: 58, //延y轴向内的倾斜角度beta: 0,},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,});});},},},legend: {enabled: true, // 关闭图例align: "right", //水平方向位置verticalAlign: "top", //垂直方向位置layout: "vertical",x: fontChart(-20),y: fontChart(30),symbolWidth: fontChart(10),symbolHeight: fontChart(10),symbolRadius: "50%", // 修改成圆itemMarginBottom: fontChart(8),useHTML: true,//labelFormat: '{name} {y}',labelFormatter: function () {return ('<div style="width: .3125rem;display: inline-block">' +this.name +': </div><div style="color: #00d7da;display: inline-block">' +this.y +"</div>");},itemStyle: {color: "#f4f4f6",fontSize: fontChart(12),},},title: {// enabled: false,text: "",},subtitle: {text: "",},plotOptions: {pie: {allowPointSelect: false, // 禁用点击cursor: "pointer",depth: fontChart(15),showInLegend: true,size: "75%", // 外圈直径大小innerSize: fontChart(95), // 内圈直径大小center: ["30%", "50%"],colors: ["rgb(235,147,39)","rgb(234,219,54)","rgb(12,214,137)","rgb(25,234,219)","rgb(13,145,239)","rgb(167,67,234)",],dataLabels: {useHTML: true,enabled: true, //是否显示饼图的线形tipdistance: 5,borderColor: '#007acc',align: "center",// verticalAlign: 'top',position: "right",format: "{point.bfb}%",// formatter: (point,b) => {// console.log(point,'ponit-->>')// console.log(b,'ponit-->>')// },color: "#ffffff",style: {textOutline: "none",fontSize: fontChart(13),},},},},credits: {enabled: false, // 禁用版权信息},series: [{type: "pie",name: "数量",data: this.dataList,},],});},},
};
</script>
Vue3写法
<template><div :id="id" style="width: 100%; height: 100%"></div>
</template>
<script setup>
import highcharts from "highcharts";
import { fontChart } from "@/utils/echartPxToRem";
import { onMounted, watch, onUnmounted } from "vue";const props = defineProps({id: {type: String,required: true,},dataList: {type: Array,default: () => ([{name: "红草莓",y: 15687,h: 16,bfb: 29,},{name: "白草莓",y: 15687,h: 12,bfb: 8,},{name: "红颜草莓",y: 15687,h: 5,bfb: 11,},{name: "甜宝草莓",y: 15687,h: 9,bfb: 11,},{name: "红颜草莓",y: 15687,h: 8,bfb: 13,},{name: "甜宝草莓",y: 15687,h: 36,bfb: 18,},]),},
});watch(() => props.dataList,(newValue) => {initOption();},{deep: true,}
);onMounted(() => {initOption();window.addEventListener('resize', initOption)
});onUnmounted(() => {window.removeEventListener("resize", initOption);
});
// 初始化echarts
const initOption = () => {let quantity = 0; // 总数props.dataList.forEach((item) => {quantity += item.y;});props.dataList.forEach((item) => {item.bfb = parseInt((item.y / quantity) * 100);item.h = item.bfb * 1.5 >= 70 ? 70 : item.bfb * 1.5// item.h = parseInt(0.86 * item.bfb); // 最高高度60,根据比例渲染高度// console.log(props.dataList, "dataList----->>>");});// 修改3d饼图绘制过程var each = highcharts.each,round = Math.round,cos = Math.cos,sin = Math.sin,deg2rad = Math.deg2rad;highcharts.wrap(highcharts.seriesTypes.pie.prototype,"translate",function (proceed) {proceed.apply(this, [].slice.call(arguments, 1));// Do not do this if the chart is not 3Dif (!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, function (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)),};});});(function (H) {H.wrap(highcharts.SVGRenderer.prototype, "arc3dPath", function (proceed) {// Run original proceed methodvar ret = proceed.apply(this, [].slice.call(arguments, 1));ret.zTop = (ret.zOut + 0.5) / 100;return ret;});})(highcharts);highcharts.chart(props.id, {chart: {animation: false,backgroundColor: "none",type: "pie", //饼图margin: [0, 0, 0, 0],options3d: {enabled: true, //使用3d功能alpha: 58, //延y轴向内的倾斜角度beta: 0,},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,});});},},},legend: {enabled: true, // 关闭图例align: "right", //水平方向位置verticalAlign: "top", //垂直方向位置layout: "vertical",x: fontChart(0),y: fontChart(30),symbolWidth: fontChart(10),symbolHeight: fontChart(10),symbolRadius: "50%", // 修改成圆itemMarginBottom: fontChart(8),labelFormat: "{name} {y}",itemStyle: {color: "#f4f4f6",fontSize: fontChart(12),},},title: {// enabled: false,text: "",},subtitle: {text: "",},plotOptions: {pie: {allowPointSelect: false, // 禁用点击cursor: "pointer",depth: fontChart(45),showInLegend: true,size: "65%", // 外圈直径大小innerSize: fontChart(95), // 内圈直径大小center: ["30%", "50%"],colors: ["rgba(157, 88, 32, .9)","rgba(169, 199, 62, .9)","rgba(11, 146, 89, .9)","rgba(16, 138, 174, .9)","rgba(0, 77, 161, .9)","rgba(60, 32, 173, .9)",],dataLabels: {enabled: true, //是否显示饼图的线形tipdistance: fontChart(0),align: "center",position: "center",format: "{point.bfb}%",// formatter: (point,b) => {// console.log(point,'ponit-->>')// console.log(b,'ponit-->>')// },style: {fontSize: fontChart(13),},},},},credits: {enabled: false, // 禁用版权信息},series: [{type: "pie",name: "Browser share",data: props.dataList,},],});
};
</script>