Saber2pr's Blog

图表实例初始化和更新逻辑

  1. 初始化实例:
let chart = null
chart = echarts.init(element) // echarts初始化后会将chart实例id记录到dom节点attribute上
chart = echarts.init(element) // 重复init时,会判断dom节点是否已初始化过echarts

echart init 方法实现(简化):

let idBase: number = +new Date() - 0 // chart id生成
const DOM_ATTRIBUTE_KEY = '_echarts_instance_' // chart id记录到dom上时的key
const instances: { [id: string]: ECharts } = {} // 存放chart的map

export function init(dom: HTMLElement): EChartsType {
  const existInstance = instances[dom.getAttribute(DOM_ATTRIBUTE_KEY)]
  if (existInstance) {
    return existInstance // 如果已有初始化实例,直接返回
  }

  const chart = new ECharts(dom)
  chart.id = 'ec_' + idBase++
  instances[chart.id] = chart // chart实例存入instances保存
  dom.setAttribute(DOM_ATTRIBUTE_KEY, chart.id) // 将chart实例id记录到dom上

  return chart
}
  1. setOption 更新
chart.setOption({
  series: [
    {
      data: [150, 230, 224],
    },
  ],
})
// 更新
chart.setOption({
  series: [
    {
      data: [150, 230, 224, 218, 135, 147, 260],
    },
  ],
})

setOption 实现(简化):

function setOption<Opt extends ECBasicOption>(option: Opt): void {
  if (this._disposed) {
    return
  }
  if (!this._model) {
    this._model = new GlobalModel()
  }
  this._model.setOption(clone(option))
}

这里的 clone 函数是一个深拷贝实现(简化):

export function clone<T extends any>(source: T): T {
  if (source == null || typeof source !== 'object') {
    return source
  }

  let result = {} as any
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      result[key] = clone(source[key])
    }
  }

  return result
}

这里 source.hasOwnProperty 容易发生错误:

echarts 之 zrender 的 clone 函数问题