d3.js 加载后强制布局自动缩放/缩放 [英] d3.js force layout auto zoom/scale after loading
问题描述
我正在使用:
var root =//任何具有单个节点的 svg.select(...),如 #id 的容器组函数 lapsedZoomFit(ticks, transitionDuration) {for (var i = ticks || 100; i > 0; --i) force.tick();强制停止();zoomFit(transitionDuration);}功能 zoomFit(transitionDuration) {var bounds = root.node().getBBox();var parent = root.node().parentElement;var fullWidth = parent.clientWidth ||parent.parentNode.clientWidth,fullHeight = parent.clientHeight ||parent.parentNode.clientHeight;var width = bounds.width,高度 = bounds.height;var midX = bounds.x + width/2,midY = bounds.y + height/2;if (width == 0 || height == 0) 返回;//没有合适的var scale = 0.85/Math.max(width/fullWidth, height/fullHeight);var translate = [fullWidth/2 - scale * midX, fullHeight/2 - scale * midY];console.trace("zoomFit", translate, scale);根.过渡().duration(transitionDuration || 0)//毫秒.call(zoom.translate(translate).scale(scale).event);}
以上适用于 D3 v3.缩放在 D3 v4 和 v5 中发生了变化,因此您必须对最后一部分(console.trace
下方的代码)进行一些小的更改:
var transform = d3.zoomIdentity.translate(translate[0], translate[1]).规模(规模);根.过渡().duration(transitionDuration || 0)//毫秒.call(zoom.transform, 变换);
I'm using this nice force layout from Flowingdata.com to create a network diagram.
My diagram currently shows between 5 and 750 nodes with their relations. It works great with some custom changes to fit my needs. However one thing I can't get to work. I have a viewBox
with preserveAspectRatio
to auto fit the container it is in. But depending on the amount of nodes there are always some nodes around the edges (mainly top and buttom) that get cut off. And if there are very little nodes, it shows them in the middle with huge empty space around it (it's a big container it's in).
Is there any way to auto zoom or scale the layout to auto fit? So that a big layout gets somewhat zoomed out and a small layout zoomed in. I have a zoom event setup so scrolling and panning works like a charm. But can it automatically do that to fit the contents?
The d3.js startup code:
vis = d3.select(selection)
.append("svg")
.attr("viewBox", "0 0 " + width + " " + height )
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("pointer-events", "all")
.call(d3.behavior.zoom().scaleExtent([.1, 3])
.on("zoom", redraw)).append('g');
All the other answers to date require access to data, and iterates through it so the complexity is at least O(nodes)
. I kept looking and found a way that is solely based on already rendered visual size, getBBox()
which is hopefully O(1)
. It doesn't matter what's in it or how it's laid out, just its size and the parent container's size. I managed to whip up this based on http://bl.ocks.org/mbostock/9656675:
var root = // any svg.select(...) that has a single node like a container group by #id
function lapsedZoomFit(ticks, transitionDuration) {
for (var i = ticks || 100; i > 0; --i) force.tick();
force.stop();
zoomFit(transitionDuration);
}
function zoomFit(transitionDuration) {
var bounds = root.node().getBBox();
var parent = root.node().parentElement;
var fullWidth = parent.clientWidth || parent.parentNode.clientWidth,
fullHeight = parent.clientHeight || parent.parentNode.clientHeight;
var width = bounds.width,
height = bounds.height;
var midX = bounds.x + width / 2,
midY = bounds.y + height / 2;
if (width == 0 || height == 0) return; // nothing to fit
var scale = 0.85 / Math.max(width / fullWidth, height / fullHeight);
var translate = [fullWidth / 2 - scale * midX, fullHeight / 2 - scale * midY];
console.trace("zoomFit", translate, scale);
root
.transition()
.duration(transitionDuration || 0) // milliseconds
.call(zoom.translate(translate).scale(scale).event);
}
EDIT: The above works in D3 v3. Zoom is changed in D3 v4 and v5, so you have to make some minor changes to the last portion (the code below console.trace
):
var transform = d3.zoomIdentity
.translate(translate[0], translate[1])
.scale(scale);
root
.transition()
.duration(transitionDuration || 0) // milliseconds
.call(zoom.transform, transform);
这篇关于d3.js 加载后强制布局自动缩放/缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!