I am building a d3js chart that plots some dots on a gradient scale of agree to disagree. I need it to be able to zoom and pan and I have all of that working except for a rectangle holding a linearGradient. The gradient zooms just as I need it, but it scales up both horizontally AND vertically, expanding past the original 20px height:
Or shrinking excessively:
I tried to use a clip path which is clearly not working, it seems that the clip path scales with the gradient. How can I clamp the rectangle to the axis and keep it the same size?
Here is my block
Thank you!!
There are two primary challenges from what I can see:
Let's drop the clip path, that'll make things a bit easier. Secondly, let's not scale the rectangle at all when we zoom (we can keep the translate that is applied though).
Now that I've destroyed what we had, let's build it back up.
Instead of scaling the rectangle with transform(scale())
let's modify its width directly. If d3.event.transform.k
is the factor at which we were scaling (both x and y), let's just modify the width of the rectangle. Instead of:
gradientScale
.attr("transform","translate("+d3.event.transform.x+","+(height- spacer*3)+")scale("+d3.event.transform.k+")");
Let's use:
gradientScale
.attr("transform", "translate( " +d3.event.transform.x+ " , " + (height - spacer*3) + ")")
.attr("width", width * d3.event.transform.k);
By removing the scaling, the above won't warp any coordinates, which won't lead to stretching of the y axis. It doesn't modify any y coordiantes, so the bar stays where it is height wise with the same height.
It does modify the width - by the same amount we were scaling it before (the rectangle's width at k = 1 is width
). This achieves the stretching of the scale as we zoom in. The x translate factor is unchanged.
Here's a bl.ock of the modified code.
My initial thought before looking closely was to try a completely different approach. So, for comparison, here's a completely different approach modifying the axis itself.