\

C3.jsのloadメソッドを中途半端なタイミングで呼ぶとアニメーションが止まるので避ける。

先日つくった :link: 自殺者数チャートがどうも使いづらい+比較しづらいと思っており、そんな時にC3.jsを見つけてアニメーション良いですねなどと言いながら作りなおしているときに気づきました。

消えるべき棒グラフが残留している図

FireShot Capture 62 - 自殺を知る、自殺を考える __ 自殺者数チャート_ - http___localhost_3001_v2_chart.png

対応

Reactpropsで降ってくるのをポンポンloadしてアニメーション中に再描画しているのが原因でしたのでこれをどうにかします。

Promiseでアニメーション中のあらたなloadを避ける

private promice = Promise.resolve();
private chart; // C3.jsでgenerateされる

writeChart(){
  ... // 値の準備など

  this.promice = this.promice.then((v)=> {
    return new Promise((resolve, _)=> {
      this.chart.load({columns, types, unload});
      setTimeout(()=> resolve(), 500);
    });
  });
}

その他

完全に同値の場合再描画を避けるなどしました。

これは同じデータでもloadを呼ぶと一見アニメーションが起こっていないように見えても、内部でなにかが起こっているからです(その分遅延が必要になる)。

発生に関するあれこれ

中途半端なタイミングとは

大体、0.2秒ぐらいのタイミングでloadを使用して値を書き換えると起こります。

症状としては、上の図のような残留や、同カテゴリ内の棒グラフ間に隙間ができるなどです。

これはアニメーション「中」というのが重要で、ローカル上でapiを叩いている場合など間隙なくloadが連続して呼ばれる場合などにはわかりづらい現象です。

これはまったく同じデータがloadされ、一見アニメーションが起こっていない場合でも問題がある再描画となります。

(おそらくですが、最初に発行されたアニメーションの停止命令が、後から発行されたアニメーションも全てとめてしまうのでしょう)

doneパラメーターが使えなくて残念だった

:link: C3.js | D3-based reusable chart library

done will be called after data loaded, but it's not after rendering. It's because rendering will finish after some transition and there is some time lag between loading and rendering.