Keeping text size sticky while making an SVG responsive with viewBox
.
viewBox
to its original width and height, and its width to 100%, so it fills its container.transform
to scale up the text by the inverse. For example, if the new width is 2/3 of the original, make the text 3/2 scale.Instead of keeping the text size fixed, you could constrain it to some other range so that it shrinks but more slowly than the rest of the SVG. For example:
var textScaleFactor = d3.scale.linear()
.domain([300,600]) // expected limits of SVG width
.range([1.5,1]); // when SVG is 1/2 width, text will be 2/3 size
See also: Hannah Fairfield's connected scatterplot on gas prices
xxxxxxxxxx
<meta charset="utf-8">
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.14/d3.min.js"></script>
<script>
var width = 960,
height = 440;
var container = d3.select("body").append("div")
.style("width",width);
d3.text("gas.svg",function(err,raw){
container.html(raw);
var svg = d3.select("svg")
.attr("width","100%")
.attr("height",height)
.attr("preserveAspectRatio", "xMidYMid meet")
.attr("viewBox", "0 0 " + width + " " + height);
var text = svg.selectAll("text");
var grid = svg.selectAll("line");
simulateResize();
// Simulate a window resize
// In real life you would skip this and use e.g.:
// window.onresize = resized;
function simulateResize(expand) {
container.transition()
.duration(4000)
.style("width",(expand ? width : width / 1.5) + "px")
.tween("simulate",function(){
return resized;
})
.each("end",function(){
simulateResize(!expand);
});
}
function resized() {
var scale = width / container.node().getBoundingClientRect().width;
// Update SVG height to maintain aspect ratio
svg.attr("height",height / scale);
// Fix grid size at 1px too
grid.style("stroke-width",scale + "px");
// Increase text scale proportional to overall scale reduction
// e.g. 3/4 of the original width -> scale text by 4/3
text.attr("transform","scale(" + scale + " " + scale + ")");
}
});
</script>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.14/d3.min.js