在 D3 中调整大小时裁剪具有矩形边界的 SVG 图像
Clip SVG image with rectangle boundaries when it is resized in D3
在这个 jsFiddle 中,我结合了 D3
和 interact.js
,两者都在 SVG
上工作。有一个包含矩形和图像的组。组 class 可以调整大小并且工作正常。问题是矩形在调整大小时应该裁剪图像(即图像永远不应该超出矩形边界)但事实并非如此。我为此使用了 D3 clipPath
,但它不起作用。有什么问题?
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)");
});
您希望图像始终扩展以填充灰色框吗? https://jsfiddle.net/alexander_L/u607w315/12/(图像扩展版本 12)
此外,您在每次事件触发时附加 <def/>
标签:
它很快就会失控。
您应该将 <def/>
附加到一些虚拟的单元素数组数据并使用 d3.js 更新模式,或者更简单地说,您可以在源代码中创建 <def/>
标记,然后每次更新同一个标签的属性。
一开始可以做一次:
var def = svg.append('defs')
.append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', 200)
.attr('height', 200);
然后在您的活动期间使用此变量并更新:
def.attr('x', 0)
.attr('y', 0)
.attr('width', event.rect.width)
.attr('height', event.rect.height);
那你就避免了这个问题。
https://jsfiddle.net/alexander_L/u607w315/11/(图像剪辑版本 11)
你想要这样的行为吗:
当灰色框在一维上小于图像时,图像被裁剪了?
更新
由于 OP 注意到原始代码中的一个错误,该错误导致灰色框总是至少回到图像的高度或宽度,我也尝试解决这个问题。
但是,我也注意到一些奇怪的行为,即盒子的左上角无法进一步向上或向左延伸,所以我首先修复了这个问题:https://jsfiddle.net/alexander_L/u607w315/25/
查看 OP 提到的新行为和旧错误的 .gif:
在这个 jsFiddle 中,我结合了 D3
和 interact.js
,两者都在 SVG
上工作。有一个包含矩形和图像的组。组 class 可以调整大小并且工作正常。问题是矩形在调整大小时应该裁剪图像(即图像永远不应该超出矩形边界)但事实并非如此。我为此使用了 D3 clipPath
,但它不起作用。有什么问题?
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)");
});
您希望图像始终扩展以填充灰色框吗? https://jsfiddle.net/alexander_L/u607w315/12/(图像扩展版本 12)
此外,您在每次事件触发时附加 <def/>
标签:
它很快就会失控。
您应该将 <def/>
附加到一些虚拟的单元素数组数据并使用 d3.js 更新模式,或者更简单地说,您可以在源代码中创建 <def/>
标记,然后每次更新同一个标签的属性。
一开始可以做一次:
var def = svg.append('defs')
.append('clipPath')
.attr('id', 'clip2')
.append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', 200)
.attr('height', 200);
然后在您的活动期间使用此变量并更新:
def.attr('x', 0)
.attr('y', 0)
.attr('width', event.rect.width)
.attr('height', event.rect.height);
那你就避免了这个问题。
https://jsfiddle.net/alexander_L/u607w315/11/(图像剪辑版本 11)
你想要这样的行为吗:
当灰色框在一维上小于图像时,图像被裁剪了?
更新
由于 OP 注意到原始代码中的一个错误,该错误导致灰色框总是至少回到图像的高度或宽度,我也尝试解决这个问题。
但是,我也注意到一些奇怪的行为,即盒子的左上角无法进一步向上或向左延伸,所以我首先修复了这个问题:https://jsfiddle.net/alexander_L/u607w315/25/
查看 OP 提到的新行为和旧错误的 .gif: