项目里关于echarts的使用优化

268 阅读1分钟

项目里对echarts的适用改造

  1. 项目里有侧栏菜单,每次展开收缩,内容页面的图表需要重新适应大小。
  2. 项目有明暗主题,切换时图表需要重新渲染适应主题颜色。
  3. 很多图表需要有全屏放大功能。

实现方法

因为上面功能都是通用的,需要全局给echarts添加这些功能,而且还要调用方便。

  1. 自适应大小
// /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方法,并返回实例。

  1. 适应主题
//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();

  1. 全屏功能
//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();

这样就实现上面的三个需求,对以前的代码改动小,而且使用方便。