项目里对echarts的适用改造
- 项目里有侧栏菜单,每次展开收缩,内容页面的图表需要重新适应大小。
- 项目有明暗主题,切换时图表需要重新渲染适应主题颜色。
- 很多图表需要有全屏放大功能。
实现方法
因为上面功能都是通用的,需要全局给echarts添加这些功能,而且还要调用方便。
- 自适应大小
// /util/echarts.js
import elementResizeDetectorMaker from "element-resize-detector";
import echarts from "echarts";
/**
* 防抖
* @param {*} fn 调用函数
* @param {*} name 定时名称 避免一个组件内重复
* @param {*} delay 延迟毫秒 默认1s
*/
export function debounce(fn, name, delay = 1000) {
if (this["timer_" + name]) clearTimeout(this["timer_" + name]);
this["timer_" + name] = null;
this["timer_" + name] = setTimeout(() => {
fn();
}, delay);
}
function autoResize() {
elementResizeDetectorMaker().listenTo(this._dom, (element) => {
debounce.call(
this,
() => {
echarts.getInstanceByDom(this._dom).resize();
},
this.id
);
});
return this;
}
echarts.init = function (...args) {
let instance = init.call(this, ...args);
let instanceProto = instance.__proto__;
...
instanceProto.autoResize = autoResize;
return instance; // 实现链式调用
}
// main.js
import echarts from "echarts";
Vue.prototype.$echarts = echarts;
// xxx.vue 调用
let myChart = this.$echarts.init(this.$refs.chart1);
myChart.setOption(option).autoResize();
加了一秒的防抖,为了使用链式调用,重新了写了echarts的init方法,将每个实例上都注入autoResize方法,并返回实例。
- 适应主题
//echarts.js
import echarts from "echarts";
function setTheme(cb) {
if (cb) {
this._theme_cb = cb;
}
if (this._theme_cb) {
this._theme_cb();
return this;
}
let colors = getColors(); //不同主题的颜色表
let option = this.getOption();
if (option.title) {
option.title.forEach((u) => {
Object.assign(u, { textStyle: { color: colors.text } });
});
}
option.xAxis &&
option.xAxis.forEach((item) => {
item.axisLabel.color = colors.text;
item.axisLine.lineStyle.color = colors.text;
});
option.yAxis &&
option.yAxis.forEach((item) => {
item.axisLabel.color = colors.text;
item.axisLine.lineStyle.color = colors.text;
});
option.legend &&
option.legend.forEach((item) => {
item.textStyle.color = colors.text;
});
option.series &&
option.series.forEach((u) => {
Object.assign(u, { label: { textStyle: { color: colors.text } } });
});
if (option.visualMap) {
option.visualMap.forEach((u) => {
Object.assign(u, { textStyle: { color: colors.text } });
});
}
option.toolbox &&
option.toolbox.forEach((u) => {
Object.assign(u, {
iconStyle: {
borderColor: colors.icon,
},
});
});
this.setOption(option);
return this;
}
echarts.init = function (...args) {
let instance = init.call(this, ...args);
let instanceProto = instance.__proto__;
...
instanceProto.setTheme = setTheme;
return instance; // 实现链式调用
}
export function redrawAllChart() {
let doms = document.querySelectorAll("div[_echarts_instance_]");
for (let i = 0; i < doms.length; i++) {
echarts.getInstanceByDom(doms[i]).setTheme();
}
}
// 设置主题页面
import { redrawAllChart } from "@/util/echarts";
setTheme() {
let theme = this.themeName == "theme-dark" ? "theme-light" : "theme-dark";
this.$store.commit("SET_THEME_NAME", theme);
redrawAllChart();
},
// xxx.vue 调用
let myChart = this.$echarts.init(this.$refs.chart1);
myChart.setOption(option).setTheme().autoResize();
- 全屏功能
//echarts.js
import echarts from "echarts";
function fullScreen() {
let opt = this.getOption();
if (!opt.toolbox) {
opt.toolbox = [{ feature: {} }];
}
opt.toolbox[0].feature.myFull = {
show: true,
title: "全屏",
icon: "path://xxxx",
onclick: function (e) {
var opts = e.getOption();
opts.toolbox[0].feature.myFull.show = false;
opts.toolbox[0].feature.myCloseFull.show = true;
var newContainer = document.createElement("div");
var newChart = document.createElement("div");
let colors = getColors().color;
newContainer.setAttribute(
"style",
"position:fixed !important;background:" +
colors +
";height:100%;width:100%;top: 0;z-index: 9999;"
);
newContainer.appendChild(newChart);
newChart.setAttribute("style", "height:100%;width:100%;");
document.body.appendChild(newContainer);
var fullchart = echarts.init(newChart);
fullchart.setOption(opts);
},
};
opt.toolbox[0].feature.myCloseFull = {
show: false,
title: "关闭",
icon: "path://xxx",
onclick: function (e) {
e.scheduler.ecInstance._dom.parentElement.remove();
e.scheduler.ecInstance.dispose();
},
};
this.setOption(opt);
return this;
}
echarts.init = function (...args) {
let instance = init.call(this, ...args);
let instanceProto = instance.__proto__;
...
instanceProto.fullScreen = fullScreen;
return instance; // 实现链式调用
}
// xxx.vue 调用
let myChart = this.$echarts.init(this.$refs.chart1);
myChart.setOption(option).setTheme().autoResize().fullScreen();
这样就实现上面的三个需求,对以前的代码改动小,而且使用方便。