We use the zoom behavior to do this.
Basically, what we do is that we wait for the graph to change (.on('transitionEnd')
) and then recenter the graph and set the zoom level to 1.
For this, we grab our graph's SVG element and read its viewBox
property.
This property is close to the size of our graph.
Then, we get the zoom behavior of our graph (the same that is used for zooming and panning with the mouse) and use its transform
function.
The transform
function can be used to set the zoom level as well as the translation, i.e., the panning of our graph, by passing a transform object.
d3.zoomIdentity
gives us a new transform object with scale = 1, x = 0, y = 0
, and by calling translate
on it we can specify an x
and y
value to translate to. By default, d3-graphviz has on a plain graph, according to my small-scale empirical study, an x
-translate of 4
and a y
-translate that corresponds to the viewbox height - 4
.
This leads to the following code (which also uses a transition
to make the zoom transform smooth):
// you can also use 'renderEnd' if you do not use animations
graphVisualization.on('transitionEnd', () => {
// Some zoom examples: https://observablehq.com/@d3/programmatic-zoom
const svg = d3.select('#graph-wrapper svg')
const viewBox = svg.attr('viewBox').split(' ')
// const graphWidth = +viewBox[2]
const graphHeight = +viewBox[3]
const transform = graphVisualization.zoomBehavior()?.transform
// Define scale and translate
// Resetting zoom to 1
// +4 and -4 are used since they seem to be the default d3-graphviz offsets
svg.transition('translateTransition').call(transform, d3.zoomIdentity.translate(4, graphHeight - 4))
})