D3には強制指向レイアウトがあります here 。このグラフにズームを追加する方法はありますか?現在、マウスホイールイベントをキャプチャできましたが、再描画関数自体の記述方法は実際にはわかりません。助言がありますか?
var vis = d3.select("#graph")
.append("svg:svg")
.call(d3.behavior.zoom().on("zoom", redraw)) // <-- redraw function
.attr("width", w)
.attr("height", h);
14/6/14更新
D3 v.3の変更については Mike Bostockの回答はこちら および 関連例 も参照してください。これはおそらく以下の答えに取って代わります。
2014年2月18日更新
SVG全体をパンおよびズームする場合は、@ ahaarnosの答えが望ましいと思います。以下の私の答えのネストされたg
要素は、同じSVGに非ズーム要素がある場合にのみ本当に必要です(元の質問の場合はそうではありません)。 dog
要素に動作を適用する場合、rect
がポインターイベントを確実に受信するには、背景g
または同様の要素が必要です。
元の回答
zoom-pan-transform の例に基づいてこれを機能させました-私のjsFiddleはここにあります: http://jsfiddle.net/nrabinowitz/QMKm3/
それは私が思っていたよりも少し複雑でした-いくつかのg
要素を入れ子にして、SVGのpointer-events
属性をall
に追加してから、背景の四角形を追加してポインターイベントを受け取ります(そうでない場合は、ポインターがノードまたはリンク上にある場合にのみ機能します)。 redraw
関数は比較的単純で、最も内側のg
に変換を設定するだけです。
var vis = d3.select("#chart")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("pointer-events", "all")
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append('svg:g');
vis.append('svg:rect')
.attr('width', w)
.attr('height', h)
.attr('fill', 'white');
function redraw() {
console.log("here", d3.event.translate, d3.event.scale);
vis.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
これにより、SVG全体が効果的にスケーリングされるため、画像を拡大するようにストローク幅もスケーリングされます。
同様の手法を示す別の 例 があります。
ネストされた<g>
's?
以下のこのコードは、私にとってはうまくいきました(1つの<g>
、ランダムな大きな白い<rect>
:
var svg = d3.select("body")
.append("svg")
.attr({
"width": "100%",
"height": "100%"
})
.attr("viewBox", "0 0 " + width + " " + height )
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("pointer-events", "all")
.call(d3.behavior.zoom().on("zoom", redraw));
var vis = svg
.append('svg:g');
function redraw() {
vis.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
Svgのすべての要素がvis
要素に追加されます。
提供された回答はD3 v2で機能しますが、v3では機能しません。私は回答をきれいなソリューションに統合し、ここに提供された答えを使用してv3の問題を解決しました: なぜv3がそうでないときにズームを実装するときにd3.js v3が私のフォースグラフを壊すのですか?
まずメインコード。これは@ahaarnosの回答のクリーンアップバージョンです。
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().on("zoom", redraw))
.append('g');
function redraw() {
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
これでパンとズームができましたが、パン機能がドラッグ機能をオーバーライドするため、ノードをドラッグできません。したがって、これを行う必要があります。
var drag = force.stop().drag()
.on("dragstart", function(d) {
d3.event.sourceEvent.stopPropagation(); // to prevent pan functionality from
//overriding node drag functionality.
// put any other 'dragstart' actions here
});
このクリーナーズーム実装を使用するために修正された@nrabinowitzのフィドルがありますが、D3v3がノードドラッグを破壊する方法を示します。 http://jsfiddle.net/QMKm3/718/
そして、D3v3で動作するように修正された同じフィドルがあります: http://jsfiddle.net/QMKm3/719/
2番目の「svg:g」を追加せずにグラフを機能させました。
[...].attr("pointer-events", "all")
.attr("width", width2)
.attr("height", height2)
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw));
残りは同じです。
ノードサイズを変更せずにレイアウトをズームおよびパンする場合は、以下を試してください。震えることなくノードをドラッグすることもできます。このコードは、元の強制レイアウトの例に基づいています。ノードとリンクのデータについては、元のサンプルデータを参照してください。 http://bl.ocks.org/mbostock/4062045
Plzは、変数xScaleおよびyScale、関数dragstarted()、dragged()、およびdragended()に注意してください。関数tick()も変更されました。
結果は http://steelblue.tistory.com/9 で確認できます。サイトの言語は韓国語です。ただし、ページの3番目の例で結果を簡単に見つけることができます。
var graph = {
"nodes": [
{ "name": "Myriel", "group": 1 },
{ "name": "Napoleon", "group": 1 },
// ......
{ "name": "Mme.Hucheloup", "group": 8 }
],
"links": [
{ "source": 1, "target": 0, "value": 1 },
{ "source": 2, "target": 0, "value": 8 },
// .......
{ "source": 76, "target": 58, "value": 1 }
]
};
var width = 640,
height = 400;
var color = d3.scale.category20();
var xScale = d3.scale.linear()
.domain([0, width])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([0, height])
.range([0, height]);
var zoomer = d3.behavior.zoom().x(xScale).y(yScale).scaleExtent([0.1, 8]).on("zoom", zoom);
function zoom() {
tick();
};
var drag = d3.behavior.drag()
.Origin(function (d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d.fixed |= 2;
}
function dragged(d) {
var mouse = d3.mouse(svg.node());
d.x = xScale.invert(mouse[0]);
d.y = yScale.invert(mouse[1]);
d.px = d.x;
d.py = d.y;
force.resume();
}
function dragended(d) {
d.fixed &= ~6; }
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.call(zoomer);
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function (d) { return Math.sqrt(d.value); });
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function (d) { return color(d.group); })
.call(drag);
node.append("title")
.text(function (d) { return d.name; });
force.on("tick",tick);
function tick(){
link.attr("x1", function (d) { return xScale(d.source.x); })
.attr("y1", function (d) { return yScale(d.source.y); })
.attr("x2", function (d) { return xScale(d.target.x); })
.attr("y2", function (d) { return yScale(d.target.y); });
node.attr("transform", function (d) {
return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")";
});
};
ズームオプションを備えたD3強制有向グラフのソリューションが得られました。
var m = [40, 240, 40, 240],
width = 960,
height = 700,
root;
var svg = d3.select("body").append("svg")
.attr("class", "svg_container")
.attr("width", width)
.attr("height", height)
.style("overflow", "scroll")
.style("background-color", "#EEEEEE")
.append("svg:g")
.attr("class", "drawarea")
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
//applying zoom in&out for svg
d3.select("svg")
.call(d3.behavior.zoom()
.scaleExtent([0.5, 5])
.on("zoom", zoom));
//zooming
function zoom() { //zoom in&out function
var scale = d3.event.scale,
translation = d3.event.translate,
tbound = -height * scale,
bbound = height * scale,
lbound = (-width + m[1]) * scale,
rbound = (width - m[3]) * scale;
// limit translation to thresholds
translation = [
Math.max(Math.min(translation[0], rbound), lbound),
Math.max(Math.min(translation[1], bbound), tbound)
];
d3.select(".drawarea")
.attr("transform", "translate(" + translation + ")" +
" scale(" + scale + ")");
}