Clip path is moving with group of elements when using d3.drag

心已入冬 提交于 2020-01-06 05:29:12

问题


I'm trying to drag a group of shapes on a clipped path. For the first time, It works fine, but as soon as I started dragging, clipping does not work at all.

Here is my working code;

var svg = d3.select("svg");

// draw a circle
    svg.append("clipPath")       // define a clip path
    	.attr("id", "clip") // give the clipPath an ID
      .append("circle")            // shape it as an ellipse
    	.attr("cx", 100)            // position the x-centre
    	.attr("cy", 80)            // position the y-centre
    	.attr("r", 80)            // set the x radius
			.attr("fill", "red")


		var g = svg.append("g")
				.datum({x:0, y:0})
				.attr("transform", function(d) { return 'translate(' + d.x + ' '+ d.y + ')'; })
				.attr("clip-path","url(#clip)")
				.call(d3.drag()
            .on("start", function(d){
							d3.select(this).raise().classed("active", true);
						})
            .on("drag", function(d){
							d3.select(this).attr("transform","translate(" + (d3.event.x) + "," + (d3.event.y) + ")" );
						})
            .on("end", function(d){
							d3.select(this).classed("active", false);
						}));


    g.append("rect")
    	.attr("x",100)
    	.attr("y",80)
    	.attr("height",100)
    	.attr("width",200)

			g.append("line")
				.attr("x1", 100)
				.attr("y1", 80)
				.attr("x2", 200)
				.attr("y2", 80)
				.style("stroke", "purple")
				.style("stroke-width", 12)
.svgClass{
border:2px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>
        <svg width="500" height="300" class="svgClass"></svg>

You can see on dragging, first time clipped shape is moving all the way. No further clipping is there.

To make it easy, I redraw the outer circle again. Check this code;

var svg = d3.select("svg");

    // draw a circle
        svg.append("clipPath")       // define a clip path
        	.attr("id", "clip") // give the clipPath an ID
          .append("circle")            // shape it as an ellipse
        	.attr("cx", 100)            // position the x-centre
        	.attr("cy", 80)            // position the y-centre
        	.attr("r", 80)            // set the x radius
    			.attr("fill", "red")
          
          // redraw circle to make it easy
          
          svg.append("circle")            // shape it as an ellipse
        	.attr("cx", 100)            // position the x-centre
        	.attr("cy", 80)            // position the y-centre
        	.attr("r", 80)            // set the x radius
    			.attr("fill", "red")


    		var g = svg.append("g")
    				.datum({x:0, y:0})
    				.attr("transform", function(d) { return 'translate(' + d.x + ' '+ d.y + ')'; })
    				.attr("clip-path","url(#clip)")
    				.call(d3.drag()
                .on("start", function(d){
    							d3.select(this).raise().classed("active", true);
    						})
                .on("drag", function(d){
    							d3.select(this).attr("transform","translate(" + (d3.event.x) + "," + (d3.event.y) + ")" );
    						})
                .on("end", function(d){
    							d3.select(this).classed("active", false);
    						}));


        g.append("rect")
        	.attr("x",100)
        	.attr("y",80)
        	.attr("height",100)
        	.attr("width",200)

    			g.append("line")
    				.attr("x1", 100)
    				.attr("y1", 80)
    				.attr("x2", 200)
    				.attr("y2", 80)
    				.style("stroke", "purple")
    				.style("stroke-width", 12)
.svgClass{
border:2px solid red;
}
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.5.0/d3.min.js"></script>
        <svg width="500" height="300" class="svgClass"></svg>

Here You can see clipping is not working at all. I want to bound this dragging within circle and if moves out of clipping boundaries, it should clip it accordingly.

Can anyone help me out with this requirement? Or let me know where I'm doing it wrong.


回答1:


The drag callback is transforming the same g element that the clip path has been applied to. This means that the g element's clip path is also being transformed, which is why the clipped shape is moving around as you drag your shape.

The snippet below uses a grey rectangle to show the clip path definition, and a pink rectangle to show the area of the transformed g element. The circle is retaining the original clip shape because the g element's clip path is being translated along with the rest of the element.

<svg width="300" height="300">
  <clipPath id="cut">
    <rect width="100" height="100" x="100" y="50"></rect>
  </clipPath>
    
  <rect x="100" y="50" width="100" height="100" fill="#eee"></rect>
    
  <g clip-path="url(#cut)" transform="translate(50, 50)">
    <rect x="100" y="50" width="100" height="100" fill="pink"></rect>
    <circle       
      class="consumption"
      cx="100" 
      cy="100" 
      r="50">
    </circle>
  </g>
</svg>

In the snippet below, a clip path is applied to an outer g element (which is not translated and has the same co-ordinates as the original clip path definition), while the transformation is applied to an inner g element.

<svg width="300" height="300">
  <clipPath id="cut">
    <rect width="100" height="100" x="100" y="50"></rect>
  </clipPath>
    
  <rect x="100" y="50" width="100" height="100" fill="#eee"></rect>
    
  <g clip-path="url(#cut)">
    <rect x="100" y="50" width="100" height="100" fill="pink"></rect>
      
    <g transform="translate(100, 50)">
      <circle       
        class="consumption"
        cx="100" 
        cy="100" 
        r="50">
      </circle>
    </g>
  </g>
</svg>

So, as shown in the example you should apply the clip path to an outer g element, while transforming an inner g element.



来源:https://stackoverflow.com/questions/57924761/clip-path-is-moving-with-group-of-elements-when-using-d3-drag

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!