Reputation: 2299
I am making a graph in D3, and I am trying to scale the Y axis of the graph on window resize, without scaling the size of the elements within it. (And I don't want to have to redraw the graph).
To say this another way, I want to be able to use SVG to scale the distance between objects, without changing the size of the objects.
Reading the last part of this article and seems to suggest I can, but I can't seem to get the details right.
Here is an simplified codepen of what I am trying to do: https://codepen.io/thesuperuser/pen/BmdNwz/
<symbol id="circle" width="20" height="20" preserveAspectRatio="none">
<circle cx="10" cy="10" r=10></circle>
</symbol>
and then I use this symbol, and try and preserve the size of the symbol with d3
let svg2 = d3.select('svg.scaled')
svg2.selectAll('use')
.data(data)
.enter()
.append('use')
.attrs({
class: 'circle',
href: '#circle2',
x: d => scale(d),
y: '50%',
height: dotR*2,
width: dotR*2,
})
This seems to just duplicate the behavior in the first example, which scales both size and distance the way you would expect viewBox
and preserveAspectRatio
to behave.
Upvotes: 1
Views: 1097
Reputation: 21811
If you set a viewBox for the svg element, it will scale that viewBox including all content to fit the viewport. What you want is the opposite: a svg element where content positioning can vary, but nothing gets scaled. The key to this is relative (percentage) units.
Here is a working pattern:
<svg width="100%" height="200">
<symbol viewBox="0 0 20 20" preserveAspectRatio="xMidYMid meet">
<circle id="circle" cx="10" cy="10" r="10" />
</symbol>
<use xlink:href="#circle" x="5%" y="50%" width="10%" height="20" />
<use xlink:href="#circle" x="15%" y="50%" width="10%" height="20" />
...
</svg>
This way, when the width of the SVG changes, the viewports of the use elements change their width, but not their height. The circles rendered inside them fit the constant height (as long as the viewports are wider than high). preserveAspectRatio="xMid..."
and the viewport x
and width
result in the circle being centered at 10%, 20%, ... Change these to position the circles as needed.
Here's a codepen to demonstrate with d3.
Upvotes: 1