【问题标题】:Resizing with handles in interact.js + SVG在 interact.js + SVG 中使用句柄调整大小
【发布时间】:2020-01-07 06:00:54
【问题描述】:

在这个jsFiddle 中,我有一个用interact.js 调整大小的SVG 矩形。这很好用,但是我需要在每个点添加调整大小句柄n/ne/e/se/s/sw/w/nw,8x8 像素正方形。这些手柄应该用于调整矩形的大小(而不是拖动矩形的边)。

我在 HTML 而不是 SVG 中找到了示例,例如 here,但我不知道如何在 SVG 而不是 HTML 中使其工作。任何帮助将不胜感激。

var svg = document.getElementById('mysvg');
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
svg.appendChild(rect);
rect.setAttribute('x', 100);
rect.setAttribute('y', 100);
rect.setAttribute('width', 100);
rect.setAttribute('height', 100);
rect.setAttribute('class', 'resize-me');
rect.setAttribute('stroke-width', 2);
rect.setAttribute('stroke', 'white');
rect.setAttribute('fill', 'grey')


interact('.resize-me')
    .resizable({
        edges: { left: true, right: true, bottom: true, top: true }
    })
    .on('resizemove', function(event) {
        var target = event.target;
        var x = (parseFloat(target.getAttribute('endx')) || 0)
        var y = (parseFloat(target.getAttribute('endy')) || 0)

        target.setAttribute('width', event.rect.width);
        target.setAttribute('height', event.rect.height);

        x += event.deltaRect.left
        y += event.deltaRect.top
        target.setAttribute('transform', 'translate(' + x + ', ' + y + ')')

        target.setAttribute('endx', x)
        target.setAttribute('endy', y)
    });

【问题讨论】:

    标签: javascript svg interact.js


    【解决方案1】:

    好的,完成。看看:

    const svg = document.getElementById('mysvg');
    const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
    
    svg.appendChild(group);
    group.appendChild(rect);
    group.setAttribute('class', 'resize-me');
    
    rect.setAttribute('x', 100);
    rect.setAttribute('y', 100);
    rect.setAttribute('width', 100);
    rect.setAttribute('height', 100);
    rect.setAttribute('stroke-width', 2);
    rect.setAttribute('stroke', 'white');
    rect.setAttribute('fill', 'grey');
    
    // Create the handles
    const handles = [];
    for (let i = 0; i < 8; i++) {
      const handle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    
      handle.setAttribute('width', 8);
      handle.setAttribute('height', 8);
      handle.setAttribute('stroke-width', 1);
      handle.setAttribute('stroke', 'white');
      handle.setAttribute('fill', 'black');
    
      handles.push(handle);
      group.appendChild(handle);
    }
    
    // Manually assign them their resize duties (R->L, T->B)
    handles[0].classList.add('resize-top', 'resize-left');
    handles[1].classList.add('resize-top');
    handles[2].classList.add('resize-top', 'resize-right');
    handles[3].classList.add('resize-left');
    handles[4].classList.add('resize-right');
    handles[5].classList.add('resize-bottom', 'resize-left');
    handles[6].classList.add('resize-bottom');
    handles[7].classList.add('resize-bottom', 'resize-right');
    
    // This function takes the rect and the list of handles and positions
    // the handles accordingly
    const findLocations = (r, h) => {
      const x = Number(r.getAttribute('x'));
      const y = Number(r.getAttribute('y'));
      const width = Number(r.getAttribute('width'));
      const height = Number(r.getAttribute('height'));
    
      // Important these are in the same order as the classes above
      let locations = [
        [0, 0],
        [width / 2, 0],
        [width, 0],
        [0, height / 2],
        [width, height / 2],
        [0, height],
        [width / 2, height],
        [width, height]
      ];
    
      // Move each location such that it's relative to the (x,y) of the rect,
      // and also subtract half the width of the handles to make up for their
      // own size.
      locations = locations.map(subarr => [
        subarr[0] + x - 4,
        subarr[1] + y - 4
      ]);
    
      for (let i = 0; i < locations.length; i++) {
        h[i].setAttribute('x', locations[i][0]);
        h[i].setAttribute('y', locations[i][1]);
      }
    }
    
    interact('.resize-me')
      .resizable({
        edges: {
          left: '.resize-left',
          right: '.resize-right',
          bottom: '.resize-bottom',
          top: '.resize-top'
        }
      })
      .on('resizemove', function(event) {
        // Resize the rect, not the group, it will resize automatically
        const target = event.target.querySelector('rect');
    
        for (const attr of ['width', 'height']) {
          let v = Number(target.getAttribute(attr));
          v += event.deltaRect[attr];
          target.setAttribute(attr, v);
        }
    
        for (const attr of ['top', 'left']) {
          const a = attr == 'left' ? 'x' : 'y';
          let v = Number(target.getAttribute(a));
          v += event.deltaRect[attr];
          target.setAttribute(a, v);
        }
    
        findLocations(rect, handles);
      });
    
    findLocations(rect, handles);
    svg {
      width: 100%;
      height: 240px;
      background-color: #2e9;
      -ms-touch-action: none;
      touch-action: none;
    }
    
    body {
      margin: 0;
    }
    <script src="https://cdn.jsdelivr.net/npm/interactjs@latest/dist/interact.min.js"></script>
    <svg id="mysvg"></svg>

    这通过利用 Interact.js 对使用单独元素作为句柄的支持(如他们的文档 here 中所述)以及您使用 SVG 而不是 HTML 的漂亮事实来实现的。这意味着您不必担心使用 CSS transform。相反,您只需移动rectxy,计算就会变得相当简单。

    我必须做的唯一容易错过的更改是我必须将矩形和手柄放在一个组中。这是因为 Interact.js 只允许您使用子元素作为调整大小的句柄。这意味着侦听器在组中,该组会在其内部调整矩形的大小(然后,当然会导致组增长,因为它们与其子项的大小相匹配)。

    如果我遗漏了什么,请告诉我。

    【讨论】:

    • 马修,你能看看this吗?
    猜你喜欢
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多