Resizing with snap in interact.js

强颜欢笑 提交于 2020-04-11 18:41:12

问题


In this jsFiddle I have an interact.js rect that can be resized with a snap of 10px by 10px. The rect is positioned in x = 95px, and when I move the left side to the left, it moves to x = 90x. This is fine, however the right side also moves to the right and it shouldn't.

What's wrong with this code? The rect has handles, is that creating the problem?

  .on('resizemove', function(event) {

    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, Math.round(v/10)*10);
    }

    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, Math.round(v/10)*10);
    }

    findLocations(rect, handles);


 });

回答1:


Ahh, I see the problem. Here's what's happening: when the rectangle is resized, you're rounding both the size and the position. This has the following effect that:

  • You have a rect whose sides go from x = 95 to x = 115. It has its left side moved by -3 units. It is now 92 to 115.
  • You check the width: it is 115 - 92 = 23 units across, so you round to the nearest ten: 20 units.
  • You check the position: It is on 92, so you move it to 90. This slides the entire, now resized, rectangle over.

You'll need to handle the top and left cases differently from the right and bottom cases, since the former two update the rectangles position on top of its size. On top of that, you'll have to only round the respective side that was changed: you don't want to round the bottom when you move the right.

  • For left or top...
    • Move the x or y to the new position, rounded
    • Don't round width or height, since that will move right or bottom
  • For right or bottom...
    • Do nothing to x or y, since rounding them will budge the whole rectangle over
    • Well, we can still change x or y, since they'll be zero, but we can't round them!
    • Only change the width or hight, but round this time

That's quite a few cases to check for, but by using a function, this isn't too hard to see how it all works:

.on('resizemove', function(event) {
  const target = event.target.querySelector('rect');

  function changeVal(attr, change, round) {
    let val = Number(target.getAttribute(change));
    val += event.deltaRect[attr];
    if (round) val = Math.round(val / 10) * 10;
    target.setAttribute(change, val);
  }

  let round = false;
  if (event.deltaRect.top != 0) round = true;
  changeVal('top', 'y', round);

  round = false;
  if (event.deltaRect.left != 0) round = true;
  changeVal('left', 'x', round);

  round = false;
  if (event.deltaRect.right != 0) round = true;
  changeVal('width', 'width', round);

  round = false;
  if (event.deltaRect.bottom != 0) round = true;
  changeVal('height', 'height', round);

  findLocations(rect, handles);
});

Shortening this and changing to the same loop style as before:

.on('resizemove', function(event) {
  const target = event.target.querySelector('rect');

  const attributes = [
    { check: 'top', change: 'y' },
    { check: 'left', change: 'x' },
    { check: 'right', change: 'width' },
    { check: 'bottom', change: 'height' }
  ];

  for (const {check, change} of attributes) {
    let val = Number(target.getAttribute(change));
    val += event.deltaRect[check];
    if (event.deltaRect[check]) val = Math.round(val / 10) * 10;
    target.setAttribute(change, val);
  }

  findLocations(rect, handles);
});

This uses ES6 destructuring assignment, so it won't work in IE.


There still seems to be some jankiness on the right edge when resizing the left edge, but I think that's an error with rounding...?

Even if not, I hope this is enough to get you started.



来源:https://stackoverflow.com/questions/61010102/resizing-with-snap-in-interact-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!