資料過渡

Apache EChartsTM 會在新增、更新、刪除資料時在位置、縮放、形狀上應用過渡動畫。這讓圖表的變化更平滑,也能更好地展現資料之間的關係。通常開發者不需要擔心如何使用這些動畫,只需要透過 setOption 更新資料,ECharts 就會自動找出上一份資料和新資料的差異,並自動應用最合適的過渡動畫。

例如,下例展示了定時更新餅圖資料時的過渡動畫。

function makeRandomData() {
  return [
    {
      value: Math.random(),
      name: 'A'
    },
    {
      value: Math.random(),
      name: 'B'
    },
    {
      value: Math.random(),
      name: 'C'
    }
  ];
}
option = {
  series: [
    {
      type: 'pie',
      radius: [0, '50%'],
      data: makeRandomData()
    }
  ]
};

setInterval(() => {
  myChart.setOption({
    series: {
      data: makeRandomData()
    }
  });
}, 2000);
線上示例

動畫的配置

因為新增資料和更新資料通常需要不同的動畫,比如我們可能希望資料更新的動畫時間更短,所以 ECharts 區分了這兩種動畫的配置。

  • 對於新增的資料,我們會應用入場動畫,分別使用 animationDurationanimationEasinganimationDelay 配置動畫的時長、緩動函式和延遲。
  • 對於更新的資料,我們會應用更新動畫,分別使用 animationDurationUpdateanimationEasingUpdateanimationDelayUpdate 配置動畫的時長、緩動函式和延遲。

可以看到,更新動畫的配置項就是入場動畫的配置項加上了 Update 字尾。

在 ECharts 中每次使用 setOption,資料都會和上次更新的資料進行 diff,並根據 diff 結果對資料執行三種狀態:新增、更新和刪除。這個 diff 是基於資料的 name 進行的,比如上次更新有三個 name 分別是 'A''B''C',新的更新變成了 'B''C''D',那麼資料 'B''C' 將被更新,資料 'A' 將被刪除,資料 'D' 將被新增。如果是第一次 setOption,因為沒有舊資料,所有資料都將是新增。根據這三種狀態,ECharts 會分別應用入場動畫、更新動畫和離場動畫。

所有這些配置都可以在 option 的頂層為所有系列和元件設定,也可以為每個系列單獨設定。

如果我們想關閉動畫,我們只需要把 option.animation 設定為 false

動畫時長

animationDurationanimationDurationUpdate 用於設定動畫的時長,單位是毫秒(ms)。設定一個更長的動畫時長可以讓使用者更清楚地看到過渡動畫的效果,但是我們也要注意時間過長可能會讓使用者在等待動畫結束時失去耐心。

設定為 0 會關閉動畫,當我們只想關閉入場動畫或更新動畫時,可以透過單獨將對應的配置項設定為 0 來實現。

動畫緩動

animationEasinganimationEasingUpdate 配置項用於設定動畫的緩動函式,緩動函式是一個輸入動畫時間並輸出動畫進度的函式。

(t: number) => number;

ECharts 內建了常見的動畫緩動函式,如 'cubicIn''cubicOut',可以直接使用。

內建緩動函式。

動畫延遲

animationDelayanimationDelayUpdate 用於設定動畫延遲開始的時間,通常我們會使用一個回撥函式為不同的資料設定不同的延遲,以實現交錯動畫的效果。

var xAxisData = [];
var data1 = [];
var data2 = [];
for (var i = 0; i < 100; i++) {
  xAxisData.push('A' + i);
  data1.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5);
  data2.push((Math.cos(i / 5) * (i / 5 - 10) + i / 6) * 5);
}
option = {
  legend: {
    data: ['bar', 'bar2']
  },
  xAxis: {
    data: xAxisData,
    splitLine: {
      show: false
    }
  },
  yAxis: {},
  series: [
    {
      name: 'bar',
      type: 'bar',
      data: data1,
      emphasis: {
        focus: 'series'
      },
      animationDelay: function(idx) {
        return idx * 10;
      }
    },
    {
      name: 'bar2',
      type: 'bar',
      data: data2,
      emphasis: {
        focus: 'series'
      },
      animationDelay: function(idx) {
        return idx * 10 + 100;
      }
    }
  ],
  animationEasing: 'elasticOut',
  animationDelayUpdate: function(idx) {
    return idx * 5;
  }
};
線上示例

動畫的效能最佳化

當資料量特別大時,執行動畫可能會有效能問題,所以我們可以設定 animation: false 來關閉動畫。

對於資料量動態變化的圖表,我們推薦使用 animationThreshold 配置,它允許 ECharts 在畫布中的圖形數量超過這個閾值時自動關閉動畫,以提高繪圖效能。這通常是一個經驗值,ECharts 通常能夠即時渲染數千個圖形(我們的預設值也設定為2000),但如果你的圖表很複雜,或者你的使用者環境比較惡劣,頁面上同時還有很多其他複雜的程式碼在執行,那麼可能需要適當調低這個值,以保證整個應用的流暢性。

監聽動畫結束

有時我們想獲取當前渲染的結果,如果不使用動畫,ECharts 會在 setOption 後直接進行渲染,我們可以使用 getDataURL 方法同步獲取渲染結果。

const chart = echarts.init(dom);
chart.setOption({
  animation: false
  //...
});
// can be executed directly and synchronously
const dataUrl = chart.getDataURL();

但如果圖表有動畫,馬上執行 getDataURL 會得到動畫開始時的畫面,而不是最終的結果。所以我們需要知道動畫什麼時候結束,然後再執行 getDataURL 來獲取結果。

如果你確定動畫的時長,一個更簡單粗暴的方法是根據動畫時長用 setTimeout 延遲執行。

chart.setOption({
  animationDuration: 1000
  //...
});
setTimeout(() => {
  const dataUrl = chart.getDataURL();
}, 1000);

另外,我們可以使用 ECharts 提供的 rendered 事件來判斷 ECharts 已經完成了動畫並停止渲染。

chart.setOption({
  animationDuration: 1000
  //...
});

function onRendered() {
  const dataUrl = chart.getDataURL();
  // ...
  // This event will also be triggered if there is a subsequent interaction and the interaction is redrawn, so it needs to be removed when you're done using it
  chart.off('rendered', onRendered);
}
chart.on('rendered', onRendered);

貢獻者 在 GitHub 上編輯此頁

pissang