How to apply crop d3.js svg after scaling

I am trying to use svg-clippath with d3.js and scaling behavior. The following code creates a rectangle, which is then clipped by the clipping region of the rectangle.

<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>

      

I want the clipping to be applied again after scaling / moving (so I can't move the outh rectangle out of the clipping region, which I can do without problems right now.) How do I do this?

I am guessing that the current behavior is due to the fact that the clipping is applied before the transformation.

+3


source to share


1 answer


I had the same problem and spent the last couple of hours trying to find a solution. The clippath appears to be working with an object prior to transformation. So I tried to reverse the transformation of the clip object while doing the broadcast scaling and it worked!

This is something along the lines 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 clip. Due to the interaction between scaling and translation, you need to explicitly set "x" and "y" rather than use a transform.

I'm sure experienced d3 programmers will come up with a better solution, but it works!

+3


source







All Articles