D3 v6 が2020年8月26日にリリースされました。D3 v6 では selection.on
によるイベント処理の方法が変わりました。この記事では公式の移行ガイドに載っていないアロー関数使用時に限った移行の方法を記していきます。
移行ガイドというタイトルですが、実質的には以前書いたD3.jsでアロー関数を使う時の注意点 の v6 版です。
- Adopt ES2015, including support for iterables and collections (Map and Set).
- Remove d3.event; selection.on now passes events directly to listeners.
- Remove d3.mouse, d3.touch, d3.touches, d3.clientPoint; add d3.pointer and d3.pointers.
- Remove d3.nest; add d3.group and d3.rollup.
- Remove d3-collection; see d3-array.
- Remove d3-voronoi; add d3-delaunay.
- Remove support for Bower.
D3 v6 の変更内容は大まかに言うと使う場面が少ない機能の削除という印象です。したがって、ほとんどの人はこれから記すイベント処理の部分だけを書き換えればすんなりと移行できるはずです。詳しくは公式の移行ガイド を参照してください。
v6 イベント処理の変更
D3 では selection.on
で DOM にイベントを実装できます。データをバインドした D3 版 addEventListener
です。これは、マウスオーバーで色を変更、クリックで選択、などインタラクティブな動作を実装したい場面で使います。
今までの書き方 (無名関数式版)
selection.on('click', function(d, i, nodes) {
d3.select(this)
.style('fill', 'red');
});
selection.on
の第一引数はイベントのタイプ、第二引数にリスナを取ります。ここまでは v6 も同様です。
第二引数のリスナは、v5 以前は selection.attr
、selection.style
と同様に、datum (d
), index (i
), nodes
を引数にとっていました。
v6 の書き方 (無名関数式版)
selection.on('click', function(event, d) {
d3.select(this)
.style('fill', 'red');
});
リスナの引数が イベントオブジェクト event
と datum (d
) に変わりました。この変更により selection.attr
, selection.style
との統一感はなくなりましたが、代わりに イベントオブジェクトを利用できるようになりました。 d
が第一引数から第二引数に変わったので、v5 以前のコードでリスナ内でデータを利用している場合はここを書き換えなければなりません。
さて、D3 の公式ガイドでは、リスナには function で始まる無名関数式を使い DOM の選択には this
を使用しています。自分としては、無名関数には極力アロー関数式を使いたい、this
は使いたくないと思っているため、以前 D3.jsでアロー関数を使う時の注意点 という記事を書きました。v6 の移行ガイドには、アロー関数を使った方法は載っていないので、アロー関数を使う場合の移行方法をメモしておきます。
アロー関数式を使う移行方法
今までの書き方 (アロー関数版)
selection.on('click', (d, i, nodes) => {
d3.select(nodes[i])
.style('fill', 'red');
});
無名関数式とアロー関数式では this
の内容が異なります。したがって、アロー関数を使うと D3 公式が紹介している this
を使ったコードは動きません。無名関数式で this
で書いていた場所は v5 以前のコードでは nodes[i]
で書くことができました。
では、i
と nodes
が消えた v6 のリスナではどのように書き換えればよいでしょうか。
v6 の書き方 (アロー関数版)
selection.on('click', (event, d) => {
d3.select(event.currentTarget)
.style('fill', 'red');
// const nodes = selection.nodes();
// const i = nodes.indexOf(event.currentTarget);
});
event.currentTarget
で this
と同じように自身の DOM を選択することができます。
v5 以前のリスナで引数に取られていた nodes
は selection.nodes()
、 i
は nodes.indexOf(event.currentTarget)
で取得できます。
参考
Thanks. No immediate plans there, but you can use event.currentTarget for event listeners.
— Mike Bostock (@mbostock) August 27, 2020