【问题标题】:Maintaining object size AND position while zooming in fabric js在放大织物 js 时保持对象大小和位置
【发布时间】:2021-08-08 17:29:27
【问题描述】:

我试图在缩放时保持对象大小,我试图从this answer 中获得灵感,其中编写它的人在这种情况下没有解决控件问题,因此你可以看到它们没有像this screenshot一样在缩放时粘在对象上。

但我提出了这个解决方案,通过在基于倒置的 viewportTransform 计算后更新其 lefttop 来保持对象的位置和控件> 通过使用 fabric.util.transformPoint 函数

计算新的 fabric.Point
fabric.Object.prototype.transform = function(ctx) {
    const obj = this;
    const {
        ignoreZoom,
        group,
        canvas,
        left,
        top
    } = obj;
    const {
        contextTop,
        viewportTransform,
        getZoom,
        requestRenderAll,
    } = canvas;

    var needFullTransform = (group && !group._transformDone) || (group && canvas && ctx === contextTop);

    if (ignoreZoom) {
        const oldP = new fabric.Point(left, top);
        const newP = fabric.util.transformPoint(oldP, fabric.util.invertTransform(viewportTransform));
        var zoom = 1 / getZoom();
        /* // here i tried to refresh the whole canvas with requestRenderAll()
        this.set({
            left: newP.x,
            top: newP.y,
            scaleX: zoom,
            scaleY: zoom,
        });
        this.setCoords();
        requestRenderAll();
        */
        // but here i try refresh the object only which is better i think
        this.left = newP.x;
        this.top = newP.y;
        this.scaleX = zoom;
        this.scaleY = zoom;
        this.drawObject(ctx);
    }
    var m = this.calcTransformMatrix(!needFullTransform);
    ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}

我制作了this codesandbox 作为我的代码的演示。如您所见in this screenshot,控件粘在对象周围,但它们整体并不能保持相对于背景的位置,有时它们会完全消失。 我需要对象保持其相对于背景的位置。 如何让它变得更好?

// 编辑

我试图更好地理解缩放时会发生什么,我找到了用于缩放的 fabric.Canvas.zoomToPoint() (as in their tutorial)

   zoomToPoint: function (point, value) {
      // TODO: just change the scale, preserve other transformations
      var before = point, vpt = this.viewportTransform.slice(0);
      point = transformPoint(point, invertTransform(this.viewportTransform));
      vpt[0] = value;
      vpt[3] = value;
      var after = transformPoint(point, vpt);
      vpt[4] += before.x - after.x;
      vpt[5] += before.y - after.y;
      return this.setViewportTransform(vpt);
    },

我想相对于背景固定对象位置的最佳方法是应用应用于画布的逆变换以缩放到对象。 所以我写了这个函数

function getNewVpt(point, value) {
  var before = point, 
  vpt = canvas.viewportTransform.slice(0);

  point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));

  vpt[0] = value;
  vpt[3] = value;
  var after = fabric.util.transformPoint(point, vpt);
  vpt[4] += before.x - after.x;
  vpt[5] += before.y - after.y;
  return vpt;
}

我用它重写了 fabric.Object.prototype.transform

fabric.Object.prototype.transform = function (ctx) {
  const obj = this;
  const { ignoreZoom, group, canvas: objCanvas, left, top } = obj;
  const {
    contextTop,
    viewportTransform,
  } = objCanvas;
  var needFullTransform =
    (group && !group._transformDone) ||
    (group && objCanvas && ctx === contextTop);

  if (ignoreZoom && zoomingIsOn) {
    zoomingIsOn = false;
    var zoom = 1 / objCanvas.getZoom();
    const oldP = new fabric.Point(left, top);
    console.log('transform : oldP : ', oldP);
    const newVpt = getNewVpt(oldP, zoom)
    const newP = fabric.util.transformPoint(oldP, newVpt);
    console.log('transform : newP : ', newP);    

    // here i tried to refresh the whole canvas with requestRenderAll()
    this.set({
      left: newP.x,
      top: newP.y,
      scaleX: zoom,
      scaleY: zoom
    });
    this.setCoords();
    console.log('transform : CALLING objCanvas.requestRenderAll() ');
    objCanvas.requestRenderAll();

    // but here i try refresh the object only which is better i think
    // this.left = newP.x;
    // this.top = newP.y;
    // this.scaleX = zoom;
    // this.scaleY = zoom;
    // this.drawObject(ctx);
  }
  var m = this.calcTransformMatrix(!needFullTransform);
  ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
};

在这里我为第二个解决方案分叉了this new codesandboxthe result 似乎比前一个解决方案更好,但它仍然不完美。我可能仍然做错了什么?!

// 编辑 2

我尝试将 objCanvas.getZoom() 而不是 zoom 作为第二个参数传递给 getNewVpt() 函数。似乎还有一些改进,但仍然不完美

// 编辑 3This codesandbox 中,我可能使用另一个直接返回新点的函数得到了the best result i could get

function getNewPt(point, value) {
  // TODO: just change the scale, preserve other transformations
  var vpt = canvas.viewportTransform.slice(0);

  point = fabric.util.transformPoint(point, fabric.util.invertTransform(canvas.viewportTransform));

  vpt[0] = value;
  vpt[3] = value;
  
  return fabric.util.transformPoint(point, vpt);;
}

我仍然希望任何人都可以告诉我是否有办法进一步改进它。正如您所看到的,三角形在缩放/取消缩放后返回到其初始位置并返回到相同的初始缩放值,这很好,但在初始和最终状态之间,它似乎仍然不在正确的位置..

【问题讨论】:

    标签: fabricjs


    【解决方案1】:

    您只需调用 zoomToPoint 进行缩放,对象将保持其相对于背景的位置和比例。

    试试下面的

    canvas.on('mouse:wheel', function(opt) {
    
      // console.log(opt.e.deltaY)
      let zoomLevel = canvas.getZoom();
      // console.log('zoom Level: ', (zoomLevel * 100).toFixed(0), '%');
      zoomLevel += opt.e.deltaY * -0.01;
    
      // Restrict scale
      zoomLevel = Math.min(Math.max(.125, zoomLevel), 20);
    
      canvas.zoomToPoint(
          new fabric.Point(opt.e.offsetX, opt.e.offsetY),
          zoomLevel,
      );
      canvas.renderAll();
    
      })
    

    【讨论】:

      猜你喜欢
      • 2018-07-12
      • 2018-08-06
      • 1970-01-01
      • 2017-10-01
      • 2015-02-12
      • 2017-03-28
      • 2014-12-30
      • 2023-03-23
      • 2011-05-10
      相关资源
      最近更新 更多