What is the best way to scale and center a graph using d3-graphviz? I was hopeful that I could use scale(0.5)
but this leaves the resulting graph uncentered.
I could probably go in with an .attributer()
and manually adjust the <svg>
and <g>
elements to get what I'm looking for, but I figured there was probably a better way?
d3.select("#graph")
.graphviz()
.width(300)
.height(300)
.fit(true)
.scale(.5)
.renderDot('digraph {a -> b}');
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"></script>
<script src="https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.js"></script>
<div id="graph" style="width: 300px; height: 300px; border: 1px solid black"></div>
Based on magjac's comment, I skipped .fit()
, .scale()
, .width()
, and .height()
and did it all in the attributer. This allows the solution to work even for larger graphs.
A few things to note:
<svg>
to 100%
allows us to skip .width()
and .height()
and have the <svg>
fill its container div.scale
variable that can be set (0-1) to determine the scale of the graphconst scale = 0.8;
function attributer(datum, index, nodes) {
var selection = d3.select(this);
if (datum.tag == "svg") {
datum.attributes = {
...datum.attributes,
width: '100%',
height: '100%',
};
// svg is constructed by hpcc-js/wasm, which uses pt instead of px, so need to convert
const px2pt = 3 / 4;
// get graph dimensions in px. These can be grabbed from the viewBox of the svg
// that hpcc-js/wasm generates
const graphWidth = datum.attributes.viewBox.split(' ')[2] / px2pt;
const graphHeight = datum.attributes.viewBox.split(' ')[3] / px2pt;
// new viewBox width and height
const w = graphWidth / scale;
const h = graphHeight / scale;
// new viewBox origin to keep the graph centered
const x = -(w - graphWidth) / 2;
const y = -(h - graphHeight) / 2;
const viewBox = `${x * px2pt} ${y * px2pt} ${w * px2pt} ${h * px2pt}`;
selection.attr('viewBox', viewBox);
datum.attributes.viewBox = viewBox;
}
}
d3.select("#graph").graphviz()
.attributer(attributer)
.renderDot('digraph {a -> b -> c ->d -> e}');
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"></script>
<script src="https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.js"></script>
<div id="graph" style="width: 300px; height: 300px; border: 1px solid black"></div>