且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Fabricjs在调整大小时捕捉到网格

更新时间:2023-10-19 15:49:28

可能看起来很复杂但是,以下内容将会得到完成工作:

Might seem pretty complicated but, the following will get the job done :

canvas.on('object:scaling', options => {
   var target = options.target,
      w = target.width * target.scaleX,
      h = target.height * target.scaleY,
      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
      },
      threshold = grid,
      dist = { // Distance from snapping points
         top: Math.abs(snap.top - target.top),
         left: Math.abs(snap.left - target.left),
         bottom: Math.abs(snap.bottom - target.top - h),
         right: Math.abs(snap.right - target.left - w)
      },
      attrs = {
         scaleX: target.scaleX,
         scaleY: target.scaleY,
         top: target.top,
         left: target.left
      };
   switch (target.__corner) {
      case 'tl':
         if (dist.left < dist.top && dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.top = target.top + (h - target.height * attrs.scaleY);
            attrs.left = snap.left;
         } else if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.left = attrs.left + (w - target.width * attrs.scaleX);
            attrs.top = snap.top;
         }
         break;
      case 'mt':
         if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.top = snap.top;
         }
         break;
      case 'tr':
         if (dist.right < dist.top && dist.right < threshold) {
            attrs.scaleX = (snap.right - target.left) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.top = target.top + (h - target.height * attrs.scaleY);
         } else if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.top = snap.top;
         }
         break;
      case 'ml':
         if (dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.left = snap.left;
         }
         break;
      case 'mr':
         if (dist.right < threshold) attrs.scaleX = (snap.right - target.left) / target.width;
         break;
      case 'bl':
         if (dist.left < dist.bottom && dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.left = snap.left;
         } else if (dist.bottom < threshold) {
            attrs.scaleY = (snap.bottom - target.top) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.left = attrs.left + (w - target.width * attrs.scaleX);
         }
         break;
      case 'mb':
         if (dist.bottom < threshold) attrs.scaleY = (snap.bottom - target.top) / target.height;
         break;
      case 'br':
         if (dist.right < dist.bottom && dist.right < threshold) {
            attrs.scaleX = (snap.right - target.left) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
         } else if (dist.bottom < threshold) {
            attrs.scaleY = (snap.bottom - target.top) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
         }
         break;
   }
   target.set(attrs);
});

以下是一个有效的例子:

Here is a working example :

var canvas = new fabric.Canvas('c', {
   selection: false
});
var grid = 50;

// create grid
for (var i = 0; i < (600 / grid); i++) {
   canvas.add(new fabric.Line([i * grid, 0, i * grid, 600], {
      stroke: '#ccc',
      selectable: false
   }));
   canvas.add(new fabric.Line([0, i * grid, 600, i * grid], {
      stroke: '#ccc',
      selectable: false
   }))
}

// add objects
canvas.add(new fabric.Rect({
   left: 100,
   top: 100,
   width: 50,
   height: 50,
   fill: '#faa',
   originX: 'left',
   originY: 'top',
   centeredRotation: true
}));

canvas.add(new fabric.Circle({
   left: 300,
   top: 300,
   radius: 50,
   fill: '#9f9',
   originX: 'left',
   originY: 'top',
   centeredRotation: true
}));

// snap to grid
canvas.on('object:moving', options => {
   options.target.set({
      left: Math.round(options.target.left / grid) * grid,
      top: Math.round(options.target.top / grid) * grid
   });
});

canvas.on('object:scaling', options => {
   var target = options.target,
      w = target.width * target.scaleX,
      h = target.height * target.scaleY,
      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
      },
      threshold = grid,
      dist = { // Distance from snapping points
         top: Math.abs(snap.top - target.top),
         left: Math.abs(snap.left - target.left),
         bottom: Math.abs(snap.bottom - target.top - h),
         right: Math.abs(snap.right - target.left - w)
      },
      attrs = {
         scaleX: target.scaleX,
         scaleY: target.scaleY,
         top: target.top,
         left: target.left
      };
   switch (target.__corner) {
      case 'tl':
         if (dist.left < dist.top && dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.top = target.top + (h - target.height * attrs.scaleY);
            attrs.left = snap.left;
         } else if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.left = attrs.left + (w - target.width * attrs.scaleX);
            attrs.top = snap.top;
         }
         break;
      case 'mt':
         if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.top = snap.top;
         }
         break;
      case 'tr':
         if (dist.right < dist.top && dist.right < threshold) {
            attrs.scaleX = (snap.right - target.left) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.top = target.top + (h - target.height * attrs.scaleY);
         } else if (dist.top < threshold) {
            attrs.scaleY = (h - (snap.top - target.top)) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.top = snap.top;
         }
         break;
      case 'ml':
         if (dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.left = snap.left;
         }
         break;
      case 'mr':
         if (dist.right < threshold) attrs.scaleX = (snap.right - target.left) / target.width;
         break;
      case 'bl':
         if (dist.left < dist.bottom && dist.left < threshold) {
            attrs.scaleX = (w - (snap.left - target.left)) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
            attrs.left = snap.left;
         } else if (dist.bottom < threshold) {
            attrs.scaleY = (snap.bottom - target.top) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
            attrs.left = attrs.left + (w - target.width * attrs.scaleX);
         }
         break;
      case 'mb':
         if (dist.bottom < threshold) attrs.scaleY = (snap.bottom - target.top) / target.height;
         break;
      case 'br':
         if (dist.right < dist.bottom && dist.right < threshold) {
            attrs.scaleX = (snap.right - target.left) / target.width;
            attrs.scaleY = (attrs.scaleX / target.scaleX) * target.scaleY;
         } else if (dist.bottom < threshold) {
            attrs.scaleY = (snap.bottom - target.top) / target.height;
            attrs.scaleX = (attrs.scaleY / target.scaleY) * target.scaleX;
         }
         break;
   }
   target.set(attrs);
});

canvas {border: 1px solid #ccc}

<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>