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