d3关注点击节点 [英] d3 focus on node on click
问题描述
我试图实现一个强制布局,其中点击一个节点将启用聚焦在节点周围的区域。我看了几个例子,但我得到一个错误,说 link.bounds没有定义
。我认为边界没有为力布局定义,并适用于这个例子从我采取的聚焦功能 http://bl.ocks.org/mbostock/9656675
的值应该为var dx,dy,x
和 y
?
<!DOCTYPE html>
< meta charset =utf-8>
< body>
< script src =https://d3js.org/d3.v3.min.js>< / script>
< script>
var width = 960,
height = 500,
active = d3.select(null);
var zoom = d3.behavior.zoom()
.translate([0,0])
.scale(1)
.scaleExtent([ 8])
.on(zoom,zoomed);
var force = d3.layout.force()
.size([width,height])
.charge(-400)
.linkDistance
.on(tick,tick);
var drag = force.drag()
.on(dragstart,dragstart);
var svg = d3.select(body)append(svg)
.attr(width,width)
.attr height)
.on(click,reset);
var link = svg.selectAll(。link),
node = svg.selectAll(。node);
var g = svg.append(g);
d3.json(miserables.json,function(error,graph){
if(error)throw error;
force
。节点(graph.nodes)
.links(graph.links)
.start();
link = link.data(graph.links)
.enter ().append(line)
.attr(class,link);
node = node.data(graph.nodes)
.enter ).append(circle)
.attr(class,node)
.attr(r,12)
.on b $ b .call(drag);
});
function tick(){
link.attr(x1,function(d){return d.source.x;})
.attr(y1,函数(d){return d.source.y;})
.attr(x2,function(d){return d.target.x;})
.attr(y2 function(d){return d.target.y;});
node.attr(cx,function(d){return d.x;})
.attr(cy,function(d){return d.y;});
}
函数点击(d){
if(active.node()=== this)return reset();
active.classed(active,false);
active = d3.select(this).classed(active,true);
var bounds = link.bounds(d),
dx = bounds [1] [0] - bounds [0] [0],
dy = bounds [1] [1] - bounds [0] [1],
x =(bounds [0] [0] + bounds [1] [0] + bounds [1] [1])/ 2,
scale = Math.max(1,Math.min(8,0.9 / Math.max(dx / width,dy / height))),
translate = [width / 2-scale * x,height / 2-scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
function reset(){
active.classed(active,false);
active = d3.select(null);
svg.transition()
.duration(750)
.call(zoom.translate([0,0])。scale(1).event);
}
函数dragstart(d){
d3.select(this).classed(fixed,d.fixed = true);
}
function zoomed(){
g.style(stroke-width,1.5 / d3.event.scale +px);
g.attr(transform,translate(+ d3.event.translate +)scale(+ d3.event.scale +));
}
< / script>
通过用所点击的节点的 bbox
重写函数来布局:
function clicked(d){
if(active.node()=== this)return reset();
active.classed(active,false);
active = d3.select(this).classed(active,true);
var bbox = active.node()。getBBox(),
bounds = [[bbox.x,bbox.y],[bbox.x + bbox.width,bbox.y + bbox.height]]; // < - 从getBBox的边界
var dx = bounds [1] [0] - bounds [0] [0],
dy = bounds [1] [1] - bounds [0] [1],
x =(bounds [0] [0] + bounds [1] [0])/ 2,
y =(bounds [0] [1] + bounds [ 1] [1])/ 2,
scale = Math.max(1,Math.min(8,0.9 / Math.max(dx / width,dy / height))),
translate = [width / 2-scale * x,height / 2-scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
运行代码: p>
<!DOCTYPE html>< meta charset =utf-8> ;< body>< script src =https://d3js.org/d3.v3.min.js>< / script>< script> var width = 960,height = 500,active = d3 .select(null); var zoom = d3.behavior.zoom().scaleExtent([1,8]).on(zoom,zoomed); var force = d3.layout.force().size([width,height]).charge(-400).linkDistance(40).on(tick,tick); var drag = force.drag (dragstart,dragstart); var svg = d3.select(body)append(svg).attr(width,width)重新启动); var g = svg.append(g); var link = g.selectAll(。link),node = g.selectAll(。node); svg .call /删除此行禁用自由缩放.call(zoom.event); d3.json(https://rawgit.com/d3/d3-plugins/master/graph/data/miserables.json,function(error,图形){if(error)throw error; force .nodes(graph.nodes).links(graph.links).start(); link = link.data(graph.links).enter ).attr(class,links).style(stroke,#999); node = node.data(graph.nodes).enter class,node).attr(r,12).on(click,clicked)//.call(drag);});function tick(){link.attr (d){return d.source.x; } .attr(y1,function(d){return d.source.y;}).attr(x2,function(d){return d.target.x;}).attr(y2 ,function(d){return d.target.y;}); node.attr(cx,function(d){return dx;}).attr(cy,function(d){return dy;});} function clicked(d){if(active.node === this)return reset(); active.classed(active,false); active = d3.select(this).classed(active,true); var bbox = active.node()。getBBox(),bounds = [[bbox.x,bbox.y],[bbox.x + bbox.width,bbox.y + bbox.height]]; var dx = bounds [1] [0] - bounds [0] [0],dy = bounds [1] [1] - bounds [0] [1] 1] [0])/ 2,y =(bounds [0] [1] + bounds [1] [1])/ 2,scale = Math.max(1,Math.min (dx / width,dy / height))),translate = [width / 2- scale * x,height / 2-scale * y]; svg.transition().duration(750).call(zoom.translate(translate).scale(scale).event);} function reset(){active.classed(active,false); active = d3.select(null); svg.transition().duration(750).call(zoom.translate([0,0])。scale(1).event);} function dragstart(d){d3.select(this).classed ,d.fixed = true);} function zoomed(){console.log(d3.event)g.style(stroke-width,1.5 / d3.event.scale +px); g.attr(transform,translate(+ d3.event.translate +)scale(+ d3.event.scale +));}< / script>
I am trying to implement a force layout where clicking on a node will enable focusing on the area around the node. I have looked at a few examples but I am getting an error which says link.bounds is not defined
. I think the bounds are not defined for force layout and are applicable for this example from where I have taken the focusing functions http://bl.ocks.org/mbostock/9656675
What should be the values for var dx, dy, x
and y
?
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
active = d3.select(null);
var zoom = d3.behavior.zoom()
.translate([0, 0])
.scale(1)
.scaleExtent([1, 8])
.on("zoom", zoomed);
var force = d3.layout.force()
.size([width, height])
.charge(-400)
.linkDistance(40)
.on("tick", tick);
var drag = force.drag()
.on("dragstart", dragstart);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.on("click", reset);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
var g = svg.append("g");
d3.json("miserables.json", function(error, graph) {
if (error) throw error;
force
.nodes(graph.nodes)
.links(graph.links)
.start();
link = link.data(graph.links)
.enter().append("line")
.attr("class", "link");
node = node.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 12)
.on("click", clicked)
.call(drag);
});
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function clicked(d){
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bounds = link.bounds(d),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
function reset() {
active.classed("active", false);
active = d3.select(null);
svg.transition()
.duration(750)
.call(zoom.translate([0, 0]).scale(1).event);
}
function dragstart(d) {
d3.select(this).classed("fixed", d.fixed = true);
}
function zoomed() {
g.style("stroke-width", 1.5 / d3.event.scale + "px");
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
</script>
You can re-create the zoom effect on a force layout by re-writing the function with the bbox
of the clicked node:
function clicked(d){
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bbox = active.node().getBBox(),
bounds = [[bbox.x, bbox.y],[bbox.x + bbox.width, bbox.y + bbox.height]]; //<-- the bounds from getBBox
var dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
Running code:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500,
active = d3.select(null);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);
var force = d3.layout.force()
.size([width, height])
.charge(-400)
.linkDistance(40)
.on("tick", tick);
var drag = force.drag()
.on("dragstart", dragstart);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
// .on("click", reset);
var g = svg.append("g");
var link = g.selectAll(".link"),
node = g.selectAll(".node");
svg
.call(zoom) // delete this line to disable free zooming
.call(zoom.event);
d3.json("https://rawgit.com/d3/d3-plugins/master/graph/data/miserables.json", function(error, graph) {
if (error) throw error;
force
.nodes(graph.nodes)
.links(graph.links)
.start();
link = link.data(graph.links)
.enter().append("line")
.attr("class", "links")
.style("stroke", "#999");
node = node.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 12)
.on("click", clicked)
//.call(drag);
});
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function clicked(d){
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bbox = active.node().getBBox(),
bounds = [[bbox.x, bbox.y],[bbox.x + bbox.width, bbox.y + bbox.height]];
var dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
translate = [width / 2 - scale * x, height / 2 - scale * y];
svg.transition()
.duration(750)
.call(zoom.translate(translate).scale(scale).event);
}
function reset() {
active.classed("active", false);
active = d3.select(null);
svg.transition()
.duration(750)
.call(zoom.translate([0, 0]).scale(1).event);
}
function dragstart(d) {
d3.select(this).classed("fixed", d.fixed = true);
}
function zoomed() {
console.log(d3.event)
g.style("stroke-width", 1.5 / d3.event.scale + "px");
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
</script>
这篇关于d3关注点击节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!