Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have the following simple example, When the line extends outside the rectangle, I want to clip it. I already have the rectangle used as an outline, what is a simple way to the same rectangle as a clipping path? My current approach using id is ignored. This related question has an answer but it requires creating the clip area separately. I'd like to re-use my info rather than repeat nearly the same info.

<!DOCTYPE html>
<meta charset="utf-8">

<body>
<script src = "http://d3js.org/d3.v3.min.js"> </script>
<script>

var margin = {top: 100, right: 20, bottom: 20, left: 20},
    width = 600 - margin.left - margin.right,
    height = 270 - margin.top - margin.bottom;

var xdata = d3.range(0, 20);
var ydata = [1, 4, 5, 9, 10, 14, 15, 15, 11, 10, 5, 5, 4, 8, 7, 5, 5, 5, 8, 10];


var xy = []; // start empty, add each element one at a time
for(var i = 0; i < xdata.length; i++ ) {
   xy.push({x: xdata[i], y: ydata[i]});
}

var xscl = d3.scale.linear()
    .domain(d3.extent(xy, function(d) {return d.x;})) //use just the x part
    .range([margin.left, width + margin.left])

var yscl = d3.scale.linear()
    .domain([1, 8]) // use just the y part
    .range([height + margin.top, margin.top])

var slice = d3.svg.line()
  .x(function(d) { return xscl(d.x);}) // apply the x scale to the x data
  .y(function(d) { return yscl(d.y);}) // apply the y scale to the y data

var svg = d3.select("body")
    .append("svg")

svg.append('rect') // outline for reference
    .attr({x: margin.left, y: margin.top,
           width: width,
           height: height,
           id: "xSliceBox",
           stroke: 'black',
           'stroke-width': 0.5,
           fill:'white'});

svg.append("path")
    .attr("class", "line")
    .attr("d", slice(xy))
    .attr("clip-path", "#xSliceBox")
    .style("fill", "none")
    .style("stroke", "red")
    .style("stroke-width", 2);

</script>
</body>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
192 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can't reference the rectangle directly in the clip-path property, you need to create a <clipPath> element. Then, inside the <clipPath> element, you can use a <use> element to reference the rectangle.

(Yes, it's round-about and more complicated that you would think it should be, but that's how the SVG specs defined it.)

Working from your code:

var svg = d3.select("body")
    .append("svg")

var clip = svg.append("defs").append("clipPath")
   .attr("id", "clipBox");

svg.append('rect') // outline for reference
    .attr({x: margin.left, y: margin.top,
           width: width,
           height: height,
           id: "xSliceBox",
           stroke: 'black',
           'stroke-width': 0.5,
           fill:'white'});

clip.append("use").attr("xlink:href", "#xSliceBox");

svg.append("path")
    .attr("class", "line")
    .attr("d", slice(xy))
    .attr("clip-path", "url(#clipBox)") //CORRECTION
    .style("fill", "none")
    .style("stroke", "red")
    .style("stroke-width", 2);

You could also do this the other way around, defining the rectangle within the clipPath element and then using a <use> element to actually draw it to the screen. Either way, you want to only define the rectangle once, so that if you decide to change it you only have to do it in one place and the other will update to match.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...