Reputation: 53
I am trying to use an svg-clippath with d3.js and the zoom behaviour. The following code creates a rectangle, which will then be clipped by a rectangualar clipping region.
<svg class="chart"></svg>
<script>
var width = 800;
var height = 600;
var svg = d3.select(".chart")
.attr("width", width)
.attr("height", height)
.append("g");
var clip = svg.append("defs")
.append("clipPath")
.attr("id","clip")
.append("rect")
.attr("width",200)
.attr("height",200)
.attr("x",100)
.attr("y",100);
var zoom = d3.behavior.zoom().
on("zoom",zoomed);
function zoomed(){
container.attr("transform", "translate(" + d3.event.translate
+")scale(" + d3.event.scale + ")");
container.attr("clip-path","url(#clip)");
}
svg.call(zoom);
var container = svg.append("g")
.attr("clip-path","url(#clip)");
var rect = container.append("rect")
//.attr("clip-path","url(#clip)")
.attr("class","bar")
.attr("x",150)
.attr("y",150)
.attr("width",350)
.attr("height",350);
</script>
What I want is for the clipping to be applied again after zooming / moving (so that I cannot move the rectangle outh of the clipping region, which right now i can do without any problems.) How do I do that?
I am assuming that the current behaviour is caused by the fact that the clipping is applied before the transformation.
Upvotes: 5
Views: 3374
Reputation: 456
I had the same problem and spent the last couple of hours trying to figure out a solution. Apparently, the clip-path operates on the object prior to transformation. So I tried to reverse-transform the clip object when performing the zoom transformation, and this worked !
It is something in the spirit of:
var clip_orig_x = 100, clip_orig_y = 100;
function zoomed() {
var t = d3.event.translate;
var s = d3.event.scale;
// standard zoom transformation:
container.attr("transform", "translate(" + t +")scale(" + s + ")");
// the trick: reverse transform the clip object!
clip.attr("transform", "scale(" + 1/s + ")")
.attr("x", clip_orig_x - t[0])
.attr("y", clip_orig_y - t[1]);
}
where clip is the rectangle in the clipPath. Because of interactions between zooming and translation, you need to set "x" and "y" explicitly instead of using transform.
I am sure experienced d3 programmers out there will come up with a better solution, but this works !
Upvotes: 4