在放大Fabric JS时保持对象大小和位置 [英] Maintaining object size AND position while zooming in fabric js

查看:21
本文介绍了在放大Fabric JS时保持对象大小和位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

但我提供了此解决方案来维护对象位置和控件,方法是更新其左侧顶部,然后根据倒置的视图计算Transform,使用Fabric.util.TransPoint函数计算新的Fabric.util.TransPoint

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所示,控件围绕着对象,但它们的整体并不保持相对于背景的位置,有时它们完全消失。 我需要对象保持其相对于背景的位置。 如何让它变得更好?

//编辑

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

Fabric.Canvar.zoomToPoint()
   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

我尝试将objCanvar.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);;
}

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

推荐答案

只需调用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();

  })

这篇关于在放大Fabric JS时保持对象大小和位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆