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