D3.js v4/v5 zoom 使い方
D3のマウス/タッチイベントに対応するzoomの使い方を紹介します。
サンプルデモ
グラフ上でドラッグ/スワイプ、マウスホイール/ピンチインしてください。下のresetボタンで初期位置に戻ります。
サンプルプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>D3 v5 zoom</title> </head> <body> <button id='resetButton'>reset</button> <script src="https://d3js.org/d3.v5.min.js"></script> <script> var width = 800; / var height = 600; // グラフの高さ var svg = d3.select("body").append("svg").attr("width", width).attr("height", height); var dataset = []; for(var i = 0; i < 300; i++) { var r = 0.5 * d3.min([height, width]) * Math.random(); var t = 2 * Math.PI * Math.random(); dataset.push({ "x": width / 2 + r * Math.cos(t), "y": height / 2 + r * Math.sin(t) }); } // 軸の設定 var x = d3.scaleLinear().domain([0, width]).range([0, width]); var y = d3.scaleLinear().domain([0, height]).range([0, height]); var xAxis = d3.axisBottom(x) .ticks(width / height * 10) // .tickSize(height) .tickPadding(8 - height); var yAxis = d3.axisRight(y) .ticks(10) .tickSize(width) .tickPadding(8 - width); var gX = svg.append("g").call(xAxis); var gY = svg.append("g").call(yAxis); var view = svg.selectAll("circle") .data(dataset) .enter() .append("circle") .attr("class", "view") .attr("cx", function(d) { return d.x }) .attr("cy", function(d) { return d.y }) .attr("r", 5) .attr("fill", "steelblue") .attr("stroke", "black"); d3.select("#resetButton") .on("click", resetted); var zoom = d3.zoom() .scaleExtent([1, 40]) .translateExtent([ [-100, -100], [width + 90, height + 100] ]) .on("zoom", zoomed); svg.call(zoom); function zoomed() { view.attr("transform", d3.event.transform); gX.call(xAxis.scale(d3.event.transform.rescaleX(x))); gY.call(yAxis.scale(d3.event.transform.rescaleY(y))); } function resetted() { svg.transition() .duration(750) .call(zoom.transform, d3.zoomIdentity); } </script> </body> </html> |
解説
散布図の作り方はこちらを参照ください。ハイライト部分のzoomの使い方を解説します。
zoom設定時にはまず、d3.zoom()でzoomイベントのプロトタイプを呼び出し、callメソッドでzoomイベントを登録するsvg要素を設定します。今回はsvg要素を設定していますが、d3.select,d3.selectAllで選択した要素に登録することができます。
1 2 3 4 5 6 7 8 9 |
var zoom = d3.zoom() .scaleExtent([1, 40]) .translateExtent([ [-100, -100], [width + 90, height + 100] ]) .on("zoom", zoomed); svg.call(zoom); |
d3.zoom()には次のメソッドが用意されています。
zoom .scaleExtent() | 拡大縮小率の最小最大値を設定します。[k0, k1]のような2変数の配列で設定します。デフォルトは [0, ∞]です。 |
zoom .translateExtent() | 移動可能範囲を設定します。[[x0, y0], [x1, y1]]のような二次元配列で設定します。x0,y0は左上からの座標、x1,x2は右下からの座標を設定します。デフォルトは [[-∞, -∞], [+∞, +∞]]です。 |
zoom .on(typenames, listener) | イベントを登録します。typenamesには次の3種類を設定可能です。 start - zoom開始時 zoom - zoom時 end - zoom終了時 listenerにはイベント時に呼び出す関数を登録します。listenerをnullとすると登録していたイベントが解除されます。 |
onメソッドでは、イベントリスナー(イベント時に呼び出されるか関数)を登録します。
1 2 3 4 5 |
function zoomed() { view.attr("transform", d3.event.transform); gX.call(xAxis.scale(d3.event.transform.rescaleX(x))); gY.call(yAxis.scale(d3.event.transform.rescaleY(y))); } |
zoomのイベントリスナーが呼び出された際、d3.eventは現在のzoomイベントに設定され、次のフィールドが設定されます。
d3.event.target | 関連するD3のzoom behaviorが設定されます。 |
d3.event.type | "start"、"zoom"、"end"のどれかが設定されます。 |
d3.event.transform | 現在のズーム倍率、移動量が設定されます。 |
d3.event.sourceEvent | mousemoveやtouchmoveなど、元となるの入力イベントが設定されます。 |
イベントリスナーはd3.event.transformを使って設定します。d3.event.transformをattrメソッドを使ってSVG要素の"transform"属性に割り当てると現在の倍率に変換されます。スケールにはtransformに設定されている次のメソッドを使って変更することができます。
transform .rescaleX(scale) | 入力したscaleのdomain範囲を現在のzoom値(x方向)に合わせて変更します。 |
transform .rescaleY(scale) | 入力したscaleのdomain範囲を現在のzoom値(y方向)に合わせて変更します。 |
最後に、リセットボタンを押したした際に元の位置と倍率に戻す関数を設定します。d3.zoomIdentityには、倍率0,移動量0のtransform属性が登録されており、
1 |
svg.call(zoom.transform, d3.zoomIdentity); |
のようにcallメソッドを使って呼び出し、現在のtranform値に設定すると初期状態に戻すことができます。
まとめ
マウス操作だけでなく、タッチイベント、ピンチイン、ピンチアウトにも対応しています。