在 D3 中调整大小时裁剪具有矩形边界的 SVG 图像

Clip SVG image with rectangle boundaries when it is resized in D3

在这个 jsFiddle 中,我结合了 D3interact.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: