javascript - 使用 interact.js + SVG 中的句柄调整大小

标签 javascript svg interact.js

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

我找到了 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)
    });

最佳答案

好的,完成。看看:

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 即可,计算变得相当简单。

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

如果我错过了什么,请告诉我。

关于javascript - 使用 interact.js + SVG 中的句柄调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59506140/

相关文章:

javascript - 绘制透明形状时覆盖在 Canvas 上绘制的内容

angular - 无法绑定(bind)到 ':xlink:href',因为它不是 ':svg:image' 的已知属性

javascript - 使用组件作为 React 按钮

javascript - 如何触发 interact.js 事件/将所有可拖动对象恢复到默认位置 ( x : 0 , y : 0 )

php - 在 PHP foreach 循环中使用 jQuery 函数

javascript - 我的输入以奇怪的值开头

javascript - 从网站删除 cookie javascript

javascript - d3.select(this) 返回什么?

javascript - Interact.js - 使用句柄移动 iframe

javascript - Interactive.js 拖动对象后旋转和缩放