Reputation: 1071
In this jsFiddle I combine D3
with interact.js
, both working on SVG
. There's a group that contains a rect and an image. The group class is resizable and that works fine. The problem is that the rect, when resized, should clip the image (i.e. the image should never be out of the rectangle borders) but it does not. I use a D3 clipPath
for that, but it's not working. What is the problem?
var svg = d3.select("body")
.append("svg")
.attr("width", 500)
.attr("height", 200);
var g = svg.append('g')
.attr('class', 'resize-me');
var rect = g.append('rect')
.attr('stroke', 'blue')
.attr('x', 0)
.attr('y', 0)
.attr("width", 200)
.attr("height", 200)
.attr('stroke-width', 2)
.attr('stroke', 'white')
.attr('fill', 'grey');
var image = g.append('image')
.attr('x', 0)
.attr('y', 0)
.attr('width', 128)
.attr('height', 128)
.attr("xlink:href", imageUrl);
interact('.resize-me')
.resizable({
edges: { left: true, right: true, bottom: true, top: true }
})
.on('resizemove', function(event) {
var target = event.target;
var rect = target.childNodes[0];
var img = target.childNodes[1];
var x = (parseFloat(target.getAttribute('endx')) || 0)
var y = (parseFloat(target.getAttribute('endy')) || 0)
rect.setAttribute('width', event.rect.width);
rect.setAttribute('height', event.rect.height);
x += event.deltaRect.left
y += event.deltaRect.top
rect.setAttribute('transform', 'translate(' + x + ', ' + y + ')')
rect.setAttribute('endx', x)
rect.setAttribute('endy', y)
// clip image
svg.append('defs')
.append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', event.rect.width)
.attr('height', event.rect.height);
image.attr("clip-path", "url(#clip2)");
});
Upvotes: 1
Views: 384
Reputation: 4241
Do you want the image to always expand to fill the grey box? https://jsfiddle.net/alexander_L/u607w315/12/ (version 12 for image expanding)
Also, you are appending <def/>
tags every time the event fires:
It gets quickly out of hand.
You should either attach the <def/>
to some dummy one element array data and use the d3.js update pattern or simpler you could just create the <def/>
tag in your source code and update the attribute of that same tag each time.
You can do it once at the start:
var def = svg.append('defs')
.append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', 200)
.attr('height', 200);
And then use this variable and update during your event:
def.attr('x', 0)
.attr('y', 0)
.attr('width', event.rect.width)
.attr('height', event.rect.height);
Then you avoid this issue.
https://jsfiddle.net/alexander_L/u607w315/11/ (version 11 for image clipping)
Do you want this behaviour:
The image is clipped when the grey box is smaller in one dimension than the image?
UPDATE
Since the OP noticed a bug in the original code which causes the grey box to always snap back to at least the height or width of the image, I tried to also solve this problem.
However, I also noticed some odd behaviour, that the top left corner of the box could not be extended further up or left so I fixed that first: https://jsfiddle.net/alexander_L/u607w315/25/
See the .gif of the new behaviour and the old bug the OP mentioned:
Upvotes: 1