最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Canvas: Rectangles -- Snap to gridSnap to objects - Stack Overflow

programmeradmin4浏览0评论

I managed to manipulate Fabric.js to add a snap and scale to grid functionality by:

var grid = 100;
//Snap to Grid
canvas.on('object:moving', function (options) {
    options.target.set({
        left: Math.round(options.target.left / grid) * grid,
        top: Math.round(options.target.top / grid) * grid
    });
});
canvas.on('object:scaling', function (options) {
    options.target.set({
        left: Math.round(options.target.left / grid) * grid,
        top: Math.round(options.target.top / grid) * grid
    });
});

Now I want to add snap to objects functionality. My idea was to check intersection of two objects and then lock somehow the movement. I know its not the best attempt, but at least it snaps to it, but does not allow to move the object away anymore. And: right now it is not implemented well. See: /

I have three issues:

  1. The "snap" doesn't work well, because the object left attribute depends on the pointer somehow. Replication by dragging object and watching my controls output. For example when moving the red rectangle to position left:62, the rectangle isn't intersected with the blue rectangle and can still moved away. How can I reload the actual left value of the rectangle. Because of my snap to grid lines, it is at left:100 and not at left:62.
  2. Any idea how I can add a snap to object functionality? And prohibit intersection?
  3. How can I check this for n objects and not only for two?

Thanks for your ments.

PS: The jsfiddle example doesn't show the scale to grid functionality, because it needed Fabric.js manipulation in line: 11100

var distroundedforgrid = Math.round(dist/100)*100;      
      transform.newScaleX = Math.round((transform.original.scaleX * distroundedforgrid / lastDist)*10)/10;
      transform.newScaleY = Math.round((transform.original.scaleY * distroundedforgrid / lastDist)*10)/10;

      target.set('scaleX', transform.newScaleX);
      target.set('scaleY', transform.newScaleY);
    }

I managed to manipulate Fabric.js to add a snap and scale to grid functionality by:

var grid = 100;
//Snap to Grid
canvas.on('object:moving', function (options) {
    options.target.set({
        left: Math.round(options.target.left / grid) * grid,
        top: Math.round(options.target.top / grid) * grid
    });
});
canvas.on('object:scaling', function (options) {
    options.target.set({
        left: Math.round(options.target.left / grid) * grid,
        top: Math.round(options.target.top / grid) * grid
    });
});

Now I want to add snap to objects functionality. My idea was to check intersection of two objects and then lock somehow the movement. I know its not the best attempt, but at least it snaps to it, but does not allow to move the object away anymore. And: right now it is not implemented well. See: http://jsfiddle/gcollect/y9kyq/

I have three issues:

  1. The "snap" doesn't work well, because the object left attribute depends on the pointer somehow. Replication by dragging object and watching my controls output. For example when moving the red rectangle to position left:62, the rectangle isn't intersected with the blue rectangle and can still moved away. How can I reload the actual left value of the rectangle. Because of my snap to grid lines, it is at left:100 and not at left:62.
  2. Any idea how I can add a snap to object functionality? And prohibit intersection?
  3. How can I check this for n objects and not only for two?

Thanks for your ments.

PS: The jsfiddle example doesn't show the scale to grid functionality, because it needed Fabric.js manipulation in line: 11100

var distroundedforgrid = Math.round(dist/100)*100;      
      transform.newScaleX = Math.round((transform.original.scaleX * distroundedforgrid / lastDist)*10)/10;
      transform.newScaleY = Math.round((transform.original.scaleY * distroundedforgrid / lastDist)*10)/10;

      target.set('scaleX', transform.newScaleX);
      target.set('scaleY', transform.newScaleY);
    }
Share Improve this question edited Jan 29, 2014 at 22:27 kangax 39.2k13 gold badges100 silver badges135 bronze badges asked Jan 27, 2014 at 15:54 gcogco 1,7007 gold badges24 silver badges46 bronze badges 1
  • Unfortunately till now, I don't have any progress regarding the snap to objects functionality. – gco Commented Mar 23, 2014 at 3:42
Add a ment  | 

3 Answers 3

Reset to default 5

For those who are still interested in the solution: I solved it here: https://stackoverflow./a/22649022/3207478 See jsfiddle: http://jsfiddle/gcollect/FD53A/

Working with .oCoords.tl .tr .bl. and .br solved it.

For rescaling based on the grid see this JSfiddle

function snapScaling(options) {
    var target = options.target;
    var type = canvas.getActiveObject().get('type');
    var corner = target.__corner;
    var w = target.getWidth();
    var h = target.getHeight();
    var snap = {   // Closest snapping points
      top: Math.round(target.top / grid) * grid,
      left: Math.round(target.left / grid) * grid,
      bottom: Math.round((target.top + h) / grid) * grid,
      right: Math.round((target.left + w) / grid) * grid,
    };
    snap.height = snap.top - snap.bottom;
    if(snap.height < 0) {
      snap.height *= - 1;
    }
    snap.width = snap.left - snap.right;
    if(snap.width < 0) {
      snap.width *= - 1;
    }
    switch (corner) {
      case 'mt':
      case 'mb':
          target.top = snap.top;
          target.height = snap.height;
          target.scaleY = 1;
        break;
      case 'ml':
      case 'mr':
        target.left = snap.left;
        target.width = snap.width;
        target.scaleX = 1;
        break;
      case 'tl':
      case 'bl':
      case 'tr':
      case 'br':
        target.top = snap.top;
        target.left = snap.left;

        target.height = snap.height;
        target.width = snap.width;

        target.scaleY = 1;
        target.scaleX = 1;
    }

    if(type == 'ellipse') {
      target.rx = (target.width / 2);
      target.ry = (target.height / 2);
    }
  }

I figured it out to solve the snap to objects on x-axis and will work on a solution for the y-axis. See JSfiddle here.

I did this by setting a new "left"-value for the active object, when I detect an intersection.

        if (options.target.isContainedWithinObject(obj)||options.target.intersectsWithObject(obj)||obj.isContainedWithinObject(options.target)) {

            var distx = ((obj.left + obj.width)/2) - ((options.target.left + options.target.width)/2);
            var disty = ((obj.top + obj.height)/2) - ((options.target.top + options.target.height)/2);                  

            if (distx > 0){
                options.target.left = obj.left - options.target.width;
            } else {
                options.target.left = obj.left + obj.width;
            }

        }
发布评论

评论列表(0)

  1. 暂无评论