组件目录
|-- components
|-- WangEcharts
|-- index.vue // echarts组件 用于echarts初始化 并通过监听props触发echarts的setOption
|-- config // 实现echarts组件按需引用
|-- index.ts
|-- options
|-- commonConfig.js // echarts 通用配置(grid/xAxis/yAxis/tooltip等 可根据设计的UI进行相应配置)
|-- utils.js // options生成代码中用到的方法 如deepMerge
|-- line // 集合所有的折线图配置
|-- baseLine.js // 基础折线图options
|-- index.js // 导出所有的折线图配置
|-- echartsOptionModules.js // 集合所有echarts图表的options
使用流程
- 在main.ts中引入echartsOptionModules.js,并通过
app.config.globalProperties.***
声明定义一个应用级的全局方法;
// eChartFn
import eChartFn from "@/components/WangEcharts/echartsOptionModules.js";
app.config.globalProperties.$eChartFn = eChartFn;
- 在需要使用的WangEcharts的Vue文件中,先引入WangEcharts组件,接口调用获取echarts数据后,通过proxy.$eChartFn调用挂载的全局方法,传入echartData以及其他自定义配置如tooltip(自定义配置会合并或替换之前已有的配置),得到option,通过props的方式传递给WangEcharts组件。
<template>
<div class="card content-box">
<WangEcharts :option="singleSiteYq" />
</div>
</template>
<script setup lang="ts" name="lineChart">
import { ref, getCurrentInstance } from "vue";
import WangEcharts from "@/components/WangEcharts/index.vue"; // 引入WangEcharts组件
// proxy相当于 vue2的this,从getCurrentInstance 实例中获取,proxy对象
const { proxy } = getCurrentInstance();
const singleSiteYq = ref({});
const baselineInstance = proxy.$eChartFn.baseLine({ // proxy.$eChartFn调用挂载的全局方法
echartData: [ // 通过接口调用等方式获取的echarts数据
{
name: "2023-11-10",
value: 1.2
},
{
name: "2023-11-11",
value: 0.2
},
{
name: "2023-11-12",
value: 2.4
},
{
name: "2023-11-13",
value: 1.2
}
],
tooltip: { // 其他自定义配置
formatter: function (params) {
return `<div class="formatter">${params.name}降雨量${params.value}mm</div>`;
}
},
showBack: true
});
singleSiteYq.value = baselineInstance.option; // 得到option
</script>
注意事项
- WangEcharts通过utils.js 的deepMerge实现自定义配置的合并或替换,即配置已存在则用传入的新的配置进行替换,配置不存在则合并至options,这个合并流程是深度的。
传入的自定义配置的结构要符合echarts option的结构标准
。
/**
* 深度合并代码,思路来自 zepto.js 源代码
* 切记不要对象递归引用,否则会陷入递归跳不出来,导致堆栈溢出
* 作用是会合并 target 和 other 对应位置的值,冲突的会保留 other 的值
*/
export const deepMerge = (target, other) => {
const isObject = source => Object.prototype.toString.call(source) === "[object Object]";
const isArray = source => Object.prototype.toString.call(source) === "[object Array]";
if (isObject(target) && isObject(other)) {
for (let [key, val] of Object.entries(other)) {
if (!target[key]) {
target[key] = val;
} else {
if (isObject(target[key])) {
target[key] = deepMerge(target[key], val);
} else {
target[key] = val;
}
}
}
} else if (isArray(target) && isArray(other)) {
for (let [key, val] of Object.entries(other)) {
if (target[key]) {
target[key] = deepMerge(target[key], val);
} else {
target.push(val);
}
}
}
return target;
};
- WangEcharts可以监听echarts图表的点击事件,比如点击返回按钮返回至上一级,主要是通过
protoman.min.js
实现相关监听。相关流程包括:
- 在index.html中引入
protoman.min.js
<script src="/js/protoman.min.js"></script>
- 在需要抛出事件的代码模块先进行初始化
const protoevt = new protoman.sm.Evented();
for (const attr in protoevt) {
this[attr] = protoevt[attr];
}
- 监听点击事件,并将事件抛出来
//展示返回按钮
if (obj.showBack) {
this.option.toolbox = commonCongif.toolbox;
this.option.toolbox.feature.myTool1.onclick = function () {
this.trigger("goBack");
}.bind(this);
}
- 在引入WangEcharts的Vue文件中进行事件监听
baselineInstance.on("goBack", () => {
alert("clicked goBack");
});
-
在某个图表的配置js文件中,如果需要通过Object.assign对通用配置commonConfig.js里面的配置进行合并时,
Object.assign方法中的目标对象一定要是空对象,而不是commonConfig.js里面的配置对象
,不然会导致commonConfig.js里面的配置对象被修改,影响其他使用commonConfig.js的图表的配置option。这是因为在 ES6 中,模块系统的导入与导出采用的是引用导出与导入(非简单数据类型),也就是说,如果在一个模块中定义了一个对象并导出,在其他模块中导入使用时,导入的其实是一个变量引用,如果修改了对象中的属性,会影响到其他模块的使用
。
例如在能源一体化首页中,由于之前我将Object.assign方法中的目标对象设置为commonConfig.js里面的配置对象,在打开一个y轴设置了min/max/interval配置的图表后,再打开另一个图表,会导致该图标的y轴数据会变的跟上一个图表一致。 -
如果将echarts设置中的notMerge设置为false,会导致当前生成的series合并之前的series,导致数据污染问题。 例如在能源一体化首页中左下的用电组成堆叠柱状图中,由于之前将notMerge设置为false,导致在进行昨日/本月切换时,本月的数据中有尖电数据,而昨日的数据中没有尖电数据,图表中却展示了本月的数据中的尖电数据。
在el-dialog中使用WangEcharts,关闭el-dialog时需要将chartOption设置为{}
,不然下次打开el-dialog时,新的echarts图表的option会与上一次生成的option合并,导致echarts图表展示错误。
数据动态更新
实现WangEcharts数据动态更新的步骤包括:
- WangEcharts/index.vue文件中,setOption 方法中传入notMerge: false 和 lazyUpdate: true 选项,以确保动画能够正常播放
const draw = () => {
if (chartInstance.value) {
// setOption 方法中传入notMerge: false 和 lazyUpdate: true 选项,以确保动画能够正常播放
chartInstance.value.setOption(props.option, { notMerge: false }, { lazyUpdate: true });
}
};
- WangEcharts/options目录下的js中echarts option的series中设置动画时长以及动画缓动效果或者
在使用WangEcharts的Vue文件中传入自定义配置生成option时带入以下动画配置
animationDurationUpdate: 300, // 更新动画时长为 1s
nimationEasingUpdate: "quinticOutIn" // 更新动画缓动效果为'quinticInout
- 在使用WangEcharts的Vue文件中通过定时器实时修改x轴以及y轴的数据
// 实时修改数据
let dataIndex = 0;
setInterval(() => {
dataIndex++;
if (dataIndex + 6 === data.length) dataIndex = 0;
const echartsData = data.slice(dataIndex, 6 + dataIndex);
singleSiteYq.value = {
xAxis: {
data: echartsData.map(item => item.name)
},
series: [
{
data: echartsData.map(item => item.value)
}
]
};
}, 4000);
echarts配置总结
- 可通过
textStyle
对图表的字体、字体大小、字体颜色等进行全局配置
,在xAxis、yAxis等配置项中无相关配置的情况下,textStyle中的配置会生效。这样一是可以缩减代码量,二是统一配置方便调整。 - grid中的containLabel设置为true,会导致y轴label变动(数值变化或者切换展示/隐藏)以及y轴整体展示/隐藏时,x轴以及y轴的位置发生变化。因为
containLabel 为 true 的时候:grid.left grid.right grid.top grid.bottom grid.width grid.height 决定的是包括了坐标轴标签在内的所有内容所形成的矩形的位置。
在能源一体化首页电力趋势分析图表中,默认不展示后六条数据对应的y轴,如果containLabel设置为true,会导致y轴展示后,图表展示区域变化,进而与上面的自定义legend不对齐,所以这种情况下,containLabel虚设置为false。