Skip to content

Instantly share code, notes, and snippets.

@pbogden
Last active September 24, 2017 11:22
Show Gist options
  • Select an option

  • Save pbogden/7547035 to your computer and use it in GitHub Desktop.

Select an option

Save pbogden/7547035 to your computer and use it in GitHub Desktop.
Clipped image

Clipped

Drag the various elements to see how things work.

Clipping an SVG image

Gotchas

Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<title>clipped</title>
<script src="http://d3js.org/d3.v4.min.js"></script>
<body>
<form style='position: absolute; top: 10px; left: 500px;'>
<input type="radio" name='choice' value = 'image' checked> image</input></br>
<input type="radio" name='choice' value = 'clone'> clone</input></br>
<input type="radio" name='choice' value = 'rect'> rect</input></br>
<input type="radio" name='choice' value = 'clip'> clipPath</input></br>
<input type="radio" name='choice' value = 'clipped'> clipped image (image & clipPath)</input>
<form/>
<script>
var imgWidth = 466, imgHeight = 609, // PNG dimensions
clipX0 = 50, clipY0 = 40, // upper left corner of the clipped region
clipWidth = imgWidth - clipX0, clipHeight = 200, // dimensions of clipped region
x0 = null, y0 = null, target = null, choice = null, selection = null,
width = 960, height = 500;
var drag = d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended);
var svg = d3.select("body").append("svg")
.attr("width", width + "px")
.attr("height", height + "px");
// Define the SVG clipPath
var clip = svg.append("defs")
.append("clipPath")
.attr("id", "rect-clip")
.append("rect")
.attr("id", "my-rect")
.attr("x", clipX0)
.attr("y", clipY0)
.attr("width", clipWidth)
.attr("height", clipHeight)
.style('stroke', 'black')
.style('stroke-width', '5px')
.style('fill-opacity', 0);
// Render the <rect> in <defs> with a <use> element
var rect = svg.append("use")
.attr("xlink:href", "#my-rect")
.attr("y", 0)
.attr("x", 0)
// Add the image, which is clipped via the clip-path attribute
var image = target = svg.append("image")
.attr("xlink:href", "pooch.png")
.attr("x", 0)
.attr("y", 0)
.attr("width", imgWidth + "px")
.attr("height", imgHeight + "px")
.attr("clip-path", "url(#rect-clip)");
// Translate a cloned image, which is clipped because attributes are cloned too
var clone = svg.append("g")
.attr("transform", "translate( " + 0 + ", " + 210 + ")")
.append(function() { return image.node().cloneNode(true) });
// Initialize
d3.selectAll('form input').on('change', changed);
changed.call(d3.selectAll('input:checked').node())
function dragstarted() {
x0 = d3.event.x - (choice === 'clip' ? clipX0 : 0);
y0 = d3.event.y - (choice === 'clip' ? clipY0 : 0);
}
function dragged() {
target.attr("x", d3.event.x - x0).attr("y", d3.event.y - y0);
if (choice === 'clipped') clip.attr("x", d3.event.x - x0 + clipX0).attr("y", d3.event.y - y0 + clipY0);
}
function dragended() {
clip.transition().attr('x', clipX0).attr('y', clipY0);
image.transition().attr('x', 0).attr('y', 0);
clone.transition().attr('x', 0).attr('y', 0);
rect.transition().attr('x', 0).attr('y', 0);
svg.transition().attr('x', 0).attr('y', 0);
}
function changed() {
choice = this.value;
selection = window[choice];
image.on('.drag', null);
clone.on('.drag', null);
rect.on('.drag', null);
if (choice === 'image' || choice === 'rect') {
svg.insert(function() { return selection.node(); })
target = selection.call(drag);
} else if (choice === 'clone') {
target = clone.call(drag);
} else if (choice === 'clip') {
svg.insert(function() { return rect.node(); });
target = clip; // clip won't detect mouse events
rect.call(drag);
} else if (choice === 'clipped') {
target = image.call(drag);
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment