我使用的是基于d3.js的dagre-d3。在我的图形呈现之后,我希望它能够缩放以适应所有的内容,并且它必须是居中的。
正如你所看到的,我可以对它的中心,但我似乎不能满足所有的内容,因为我的身高是400。
请注意,我想要一个解决方案,应该可以用于其他dagre的情况,例如,只是缩放到0.5将适合在这种情况下,但这不是我想要的。
JSFIDDLE: https://jsfiddle.net/bababalcksheep/xa9rofm5/8/
代码:
'use strict';
//
// setup Zoom from example http://bl.ocks.org/mgold/f61420a6f02adb618a70
//
var width = 960,
height = 400,
center = [width / 2, height / 2];
//
var svg = d3.select('svg'),
inner = svg.select('g');
//
var zoom = d3.behavior.zoom()
.translate([0, 0])
.scale(1)
.size([900, 400])
.scaleExtent([1, 8])
.on('zoom', zoomed);
//
svg
.call(zoom) // delete this line to disable free zooming
.call(zoom.event);
function zoomed() {
inner.attr('transform', 'translate(' + zoom.translate() + ')scale(' + zoom.scale() + ')');
}
function interpolateZoom(translate, scale) {
var self = this;
return d3.transition().duration(350).tween('zoom', function () {
var iTranslate = d3.interpolate(zoom.translate(), translate),
iScale = d3.interpolate(zoom.scale(), scale);
return function (t) {
zoom
.scale(iScale(t))
.translate(iTranslate(t));
zoomed();
};
});
}
function zoomClick() {
var clicked = d3.event.target,
direction = 1,
factor = 0.2,
target_zoom = 1,
center = [width / 2, height / 2],
extent = zoom.scaleExtent(),
translate = zoom.translate(),
translate0 = [],
l = [],
view = {
x: translate[0],
y: translate[1],
k: zoom.scale()
};
d3.event.preventDefault();
direction = (this.id === 'zoom_in') ? 1 : -1;
target_zoom = zoom.scale() * (1 + factor * direction);
if (target_zoom < extent[0] || target_zoom > extent[1]) {
return false;
}
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
interpolateZoom([view.x, view.y], view.k);
}
d3.selectAll('button').on('click', zoomClick);
//
//
//
// tcp-state-diagram EXAMPLE
//
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
// States and transitions from RFC 793
var states = ['CLOSED', 'LISTEN', 'SYN RCVD', 'SYN SENT',
'ESTAB', 'FINWAIT-1', 'CLOSE WAIT', 'FINWAIT-2',
'CLOSING', 'LAST-ACK', 'TIME WAIT'
];
// Automatically label each of the nodes
states.forEach(function (state) {
g.setNode(state, {
label: state
});
});
// Set up the edges
g.setEdge('CLOSED', 'LISTEN', {
label: 'open'
});
g.setEdge('LISTEN', 'SYN RCVD', {
label: 'rcv SYN'
});
g.setEdge('LISTEN', 'SYN SENT', {
label: 'send'
});
g.setEdge('LISTEN', 'CLOSED', {
label: 'close'
});
g.setEdge('SYN RCVD', 'FINWAIT-1', {
label: 'close'
});
g.setEdge('SYN RCVD', 'ESTAB', {
label: 'rcv ACK of SYN'
});
g.setEdge('SYN SENT', 'SYN RCVD', {
label: 'rcv SYN'
});
g.setEdge('SYN SENT', 'ESTAB', {
label: 'rcv SYN, ACK'
});
g.setEdge('SYN SENT', 'CLOSED', {
label: 'close'
});
g.setEdge('ESTAB', 'FINWAIT-1', {
label: 'close'
});
g.setEdge('ESTAB', 'CLOSE WAIT', {
label: 'rcv FIN'
});
g.setEdge('FINWAIT-1', 'FINWAIT-2', {
label: 'rcv ACK of FIN'
});
g.setEdge('FINWAIT-1', 'CLOSING', {
label: 'rcv FIN'
});
g.setEdge('CLOSE WAIT', 'LAST-ACK', {
label: 'close'
});
g.setEdge('FINWAIT-2', 'TIME WAIT', {
label: 'rcv FIN'
});
g.setEdge('CLOSING', 'TIME WAIT', {
label: 'rcv ACK of FIN'
});
g.setEdge('LAST-ACK', 'CLOSED', {
label: 'rcv ACK of FIN'
});
g.setEdge('TIME WAIT', 'CLOSED', {
label: 'timeout=2MSL'
});
// Set some general styles
g.nodes().forEach(function (v) {
var node = g.node(v);
node.rx = node.ry = 5;
});
// Add some custom colors based on state
g.node('CLOSED').style = 'fill: #f77';
g.node('ESTAB').style = 'fill: #7f7';
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// Center the graph
var initialScale = 0.75;
var _height = svg.attr('height') - g.graph().height;
var _width = svg.attr('width') - g.graph().width;
console.log(height / _height);
zoom.translate([(svg.attr('width') - g.graph().width * initialScale) / 2, 10]).scale(1).event(svg);
//svg.transition().duration(750).call(zoom.translate([0, 0]).scale(1).event);
//svg.transition().duration(500).attr('transform', 'scale(0.75) translate(0,0)');发布于 2016-04-17 22:18:51
适当的默认比例将是svg高度(或宽度)与缩放容器高度(或宽度)的较小比例。简化一点:
var padding = 20,
bBox = inner.node().getBBox(),
hRatio = height / (bBox.height + padding),
wRatio = width / (bBox.width + padding);
zoom.translate([(width - bBox.width * initialScale) / 2, padding / 2])
.scale(hRatio < wRatio ? hRatio : wRatio)
.event(svg);更新的小提琴。
发布于 2019-06-03 21:37:00
我有一些基于很多人使用的d3.v3.js的代码,然后转换为d3.v5.js (查看最新d3中的任何bug修复是否会帮助我的代码)。变焦是最难弄清楚如何中心的部分。
下面是后一个d3.v5.js的示例:https://jsfiddle.net/armyofda12mnkeys/1burht5j/21/
下面的代码用于不同版本之间的比较:
d3.v3
var g = new dagreD3.graphlib.Graph({ compound: false, multigraph: true }).setGraph({});
//I have various code here to draw the graph dynamically with setNode() setEdge()
var svg = d3.select("svg"),
inner = svg.select("g");
// Set the rankdir
g.graph().rankdir = 'TB';//'TB' (aka vertical) or 'LR' (aka horizontal)
g.graph().nodesep = 50;
// Set up zoom support
var zoom = d3.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
console.log('zoom!');
});
svg.call(zoom); //not sure what purpose of this initial zoom call is, still need the 2nd piece of code to fit upon landing on the page
// Create the renderer
var render = new dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
//set the 'fit to content graph' upon landing on the page
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);d3.v5
var g = new dagreD3.graphlib.Graph({ compound: false, multigraph: true }).setGraph({});
//I have various code here to draw the graph dynamically with setNode() setEdge()
var svg = d3.select("svg"),
inner = svg.select("g");
// Set the rankdir
g.graph().rankdir = 'TB';//'TB' (aka vertical) or 'LR' (aka horizontal)
g.graph().nodesep = 50;
var zoom = d3.zoom()
//.scaleExtent([0, 20]) //removed for now, acts funky
.on("zoom", function() {
inner.attr("transform", d3.event.transform);
//dynamically resets height (for dynamic 'scrollbar sizing') if thats wanted:
//svg.attr('height', g.graph().height * d3.event.transform.k * 1.25 ); //make a tiny bit bigger so you can see the whole thing with a little space
console.log('zoom!'+ d3.event.transform.x +','+ d3.event.transform.y +':'+ d3.event.transform.k + ', width: '+ g.graph().width + ', height: '+ g.graph().height);
});
svg.call(zoom); //not sure what purpose of this initial zoom call is, still need the 2nd piece of code to fit upon landing on the page
//... render the graph
// Create the renderer
var render = new dagreD3.render();
render(inner, g);
//...
//set the 'fit to content graph' upon landing on the page
var initialScale = 0.75;
let transform = d3.zoomIdentity
.translate( (svg.attr("width") - g.graph().width * initialScale) / 2, 20)
.scale(initialScale);
let transitionDuration = 5000;
inner //or svg, doesn't seem to matter
.transition()
.duration(transitionDuration || 0) // milliseconds
.call(zoom.transform, transform);
svg.attr('height', g.graph().height * initialScale + 40);发布于 2021-02-12 07:49:47
d3 v6
const $svg = d3.select(svg)
const $container = $svg.append("g")
// Setup d3-zoom
const zoom = d3.zoom().on("zoom", (event) => {
$container.attr("transform", event.transform)
})
$svg.call(zoom)
// Render graph
const dagre_render = new dagre.render({})
const graph = new dagre.graphlib.Graph(...)
dagre_render($container, graph)
// Zoom to fit
const { width, height } = $container.node().getBBox()
if (width && height) {
const scale = Math.min(svg.clientWidth / width, svg.clientHeight / height) * 0.95
zoom.scaleTo($svg, scale)
zoom.translateTo($svg, width / 2, height / 2)
}https://stackoverflow.com/questions/36667194
复制相似问题