Обрезать изображение SVG с границами прямоугольника при изменении его размера в D3 - PullRequest
1 голос
/ 10 февраля 2020

В этом jsFiddle я объединяю D3 с interact.js, оба работают на SVG. Есть группа, которая содержит прямоугольник и изображение. Размер группы можно изменять, и это прекрасно работает. Проблема в том, что прямоугольник при изменении размера должен обрезать изображение (то есть изображение никогда не должно выходить за границы прямоугольника), но это не так. Я использую 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)");

    });

1 Ответ

1 голос
/ 11 февраля 2020

Хотите ли вы, чтобы изображение всегда расширялось, чтобы заполнить серое поле? https://jsfiddle.net/alexander_L/u607w315/12/ (версия 12 для увеличения изображения)

enter image description here

Кроме того, вы добавляете теги <def/> каждый раз, когда происходит событие fires:

enter image description here

Это быстро выходит из-под контроля.

Вы должны либо присоединить <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 для обрезки изображения)

Хотите ли вы это поведение:

enter image description here

Изображение обрезается, когда серый прямоугольник меньше в одном измерении, чем изображение?

ОБНОВЛЕНИЕ

Поскольку OP обнаружил ошибку в исходном коде, из-за которой серое поле всегда отображалось Вернувшись хотя бы к высоте или ширине изображения, я также попытался решить эту проблему.

Тем не менее, я также заметил странное поведение: верхний левый угол рамки не может быть расширен дальше или левее, поэтому я исправил это сначала: https://jsfiddle.net/alexander_L/u607w315/25/

Смотрите .gif нового поведения и старой ошибки, упомянутой ОП:

enter image description here

...