Skip to content
索引

[问题解决]Echarts:There is a chart instance already initialized on the dom

产生原因

使用Echarts的时候,多次加载会出现There is a chart instance already initialized on the dom.的警告,表示DOM上已经初始化了一个图表实例

js
<template>
  <div class="echarts-style">
    <div ref="chart" class="bar-chart"></div>
  </div>
</template>

<script>
import * as echarts from "echarts"
export default {
  data() {
    return {
      chartPie: null,
    }
  },
  mounted() {
    this.drawChart()
  },
  props: {
    queryParm: Object,
  },
  watch: {
    queryParm: {
      handler() {
        this.drawChart()
      },
      deep: true,
    },
  },
  methods: {
    drawChart() {
      // 如果不存在,就进行初始化
      const already = echarts.getInstanceByDom(this.$refs.chart)
      if (!already) {
        this.chartPie = echarts.init(this.$refs.chart)
      }
      this.chartPie.setOption({
        ...
      })
      if (!already) {
        window.addEventListener("resize", () => {
          this.chartPie.resize()
        })
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.echarts-style {
  width: 100%;
  height: 300px;

  .bar-chart {
    width: 100%;
    height: 100%;
  }
}
</style>
<template>
  <div class="echarts-style">
    <div ref="chart" class="bar-chart"></div>
  </div>
</template>

<script>
import * as echarts from "echarts"
export default {
  data() {
    return {
      chartPie: null,
    }
  },
  mounted() {
    this.drawChart()
  },
  props: {
    queryParm: Object,
  },
  watch: {
    queryParm: {
      handler() {
        this.drawChart()
      },
      deep: true,
    },
  },
  methods: {
    drawChart() {
      // 如果不存在,就进行初始化
      const already = echarts.getInstanceByDom(this.$refs.chart)
      if (!already) {
        this.chartPie = echarts.init(this.$refs.chart)
      }
      this.chartPie.setOption({
        ...
      })
      if (!already) {
        window.addEventListener("resize", () => {
          this.chartPie.resize()
        })
      }
    },
  },
}
</script>

<style lang="scss" scoped>
.echarts-style {
  width: 100%;
  height: 300px;

  .bar-chart {
    width: 100%;
    height: 100%;
  }
}
</style>

设置x轴间隔

js
 xAxis: {
    type: "category",
    data: [],
    boundaryGap: false, // 留白
    splitLine: {
      show: true
    },
    axisLabel: {
      showMaxLabel: true, // 显示最大的文本
      interval: 59  // 间隔多少显示x轴文本
    }
  },
 xAxis: {
    type: "category",
    data: [],
    boundaryGap: false, // 留白
    splitLine: {
      show: true
    },
    axisLabel: {
      showMaxLabel: true, // 显示最大的文本
      interval: 59  // 间隔多少显示x轴文本
    }
  },

或者设置成函数的形式

js
 axisLabel: {
  interval: (index, value) => {
    return index % 60 === 0 || value === "23:59";
  },
  rotate: 20
}
 axisLabel: {
  interval: (index, value) => {
    return index % 60 === 0 || value === "23:59";
  },
  rotate: 20
}

设置x轴文字倾斜

js
axisLabel: {
  rotate: 8,
},
axisLabel: {
  rotate: 8,
},

主动置灰单个折线

js
this.chartLine.on("legendselectchanged", () => {
  this.options.legend.selected[""] = false
  this.chartLine.setOption(this.options)
})
this.chartLine.on("legendselectchanged", () => {
  this.options.legend.selected[""] = false
  this.chartLine.setOption(this.options)
})

去除x轴坐标线

json
option = {
  xAxis: {
    type: 'value',
    axisTick: {
        show: false
      },
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line'
    }
  ]
}
option = {
  xAxis: {
    type: 'value',
    axisTick: {
        show: false
      },
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line'
    }
  ]
}

x轴或y轴显示全部坐标

json
axisLabel:{
  interval:0
 },
axisLabel:{
  interval:0
 },

设置x轴百分比

js
 yAxis: {
          type: "value",
          axisLabel: {
            show: true,
            interval: "auto",
            formatter: "{value} %",
          },
          max: 100,
          min: 0,
        },
 yAxis: {
          type: "value",
          axisLabel: {
            show: true,
            interval: "auto",
            formatter: "{value} %",
          },
          max: 100,
          min: 0,
        },

前端js生成24小时x轴

js
    // 生成指定分钟为间隔的时间数组
    createTimeArr(step = 5) {
      let date = new Date()
      date.setHours(0) // 时分从0开始
      date.setSeconds(0)
      date.setUTCMinutes(5) // 秒从05开始
      const timeArr = []
      const slotNum = (24 * 60) / step // 算出多少个间隔
      for (let f = 0; f < slotNum; f++) {
        const time = new Date(Number(date.getTime()) + Number(step * 60 * 1000 * f)) // 获取:零点的时间 + 每次递增的时间
        let hour = "",
          sec = ""
        time.getHours() < 10 ? (hour = "0" + time.getHours()) : (hour = time.getHours()) // 获取小时
        time.getMinutes() < 10 ? (sec = "0" + time.getMinutes()) : (sec = time.getMinutes()) // 获取分钟
        if (hour === "00" && sec === "00") {
          hour = "24"
        }
        timeArr.push(hour + ":" + sec)
      }
      return timeArr
    },
    // 生成指定分钟为间隔的时间数组
    createTimeArr(step = 5) {
      let date = new Date()
      date.setHours(0) // 时分从0开始
      date.setSeconds(0)
      date.setUTCMinutes(5) // 秒从05开始
      const timeArr = []
      const slotNum = (24 * 60) / step // 算出多少个间隔
      for (let f = 0; f < slotNum; f++) {
        const time = new Date(Number(date.getTime()) + Number(step * 60 * 1000 * f)) // 获取:零点的时间 + 每次递增的时间
        let hour = "",
          sec = ""
        time.getHours() < 10 ? (hour = "0" + time.getHours()) : (hour = time.getHours()) // 获取小时
        time.getMinutes() < 10 ? (sec = "0" + time.getMinutes()) : (sec = time.getMinutes()) // 获取分钟
        if (hour === "00" && sec === "00") {
          hour = "24"
        }
        timeArr.push(hour + ":" + sec)
      }
      return timeArr
    },

设置平均线

js
option = {
  tooltip: {},
  legend: {},
  xAxis: {
    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  },
  yAxis: {},
  series: [{
    name: "Sale",
    type: "bar",
    data: [5, 20, 36, 10, 10, 20, 4],
    markPoint: {
      data: [{
        type: "max"
      }]
    },
    markLine: {
      data: [{
        type: "average"
      }],
      silent: false
    }
  }]
}
option = {
  tooltip: {},
  legend: {},
  xAxis: {
    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  },
  yAxis: {},
  series: [{
    name: "Sale",
    type: "bar",
    data: [5, 20, 36, 10, 10, 20, 4],
    markPoint: {
      data: [{
        type: "max"
      }]
    },
    markLine: {
      data: [{
        type: "average"
      }],
      silent: false
    }
  }]
}

图例每项之间的间隔

js
legend.itemGap = 10
legend.itemGap = 10

富文本样式formatter+rich

js
 label: {
              formatter: params => {
                let data = params.data
                if (parseFloat(data) === this.highValue) {
                  return `{a|${data}}`
                }
                return `{b|${data}}`
              },
              rich: {
                a: {
                  color: "#e4952a",
                  fontWeight: "bold"
                },
                b: {
                  color: "#33e1ae",
                  fontWeight: "bold"
                }
              }
            },
 label: {
              formatter: params => {
                let data = params.data
                if (parseFloat(data) === this.highValue) {
                  return `{a|${data}}`
                }
                return `{b|${data}}`
              },
              rich: {
                a: {
                  color: "#e4952a",
                  fontWeight: "bold"
                },
                b: {
                  color: "#33e1ae",
                  fontWeight: "bold"
                }
              }
            },

Echarts百万级数据时的渲染优化

https://juejin.cn/post/7031582890760601607

减少数据量

从业务的角度出发:拆分图表的数据,比如年月日数据,换成按钮切换显示

Web Worker

缺点是丧失交互功能

懒加载

只渲染可视区域内的图表

降采样

echarts官方配置项,有一个sampling可用,是降采样,也就是渲染的时候不把每一个点渲染出来

折线图在数据量远大于像素点时候的降采样策略,开启后可以有效的优化图表的绘制效率,默认关闭,也就是全部绘制不过滤数据点。

可选:

  • 'lttb' 采用 Largest-Triangle-Three-Bucket 算法,可以最大程度保证采样后线条的趋势,形状和极值
  • 'average' 取过滤点的平均值
  • 'max' 取过滤点的最大值
  • 'min' 取过滤点的最小值
  • 'sum' 取过滤点的和

数据为0时不显示

js
series: [
  {
    label: {
      show: true,
      position: "top",
      color: "#000000",
      formatter: function (params) {
        if (params.value > 0) {
          return params.value
        } else {
          return " "
        }
      }
    },
    data: []
  }
]
series: [
  {
    label: {
      show: true,
      position: "top",
      color: "#000000",
      formatter: function (params) {
        if (params.value > 0) {
          return params.value
        } else {
          return " "
        }
      }
    },
    data: []
  }
]

Released under the MIT License.