【问题标题】:Maintaining object size while zooming in fabric js在放大织物js时保持对象大小
【发布时间】:2018-07-12 17:39:35
【问题描述】:

即使用户放大或缩小,是否有任何解决方案可以保持对象大小?我想在谷歌地图上实现类似的行为。因此,如果我有一个高度和宽度为 20 的对象(对象组),即使我放大它,默认情况下它仍应为 20 像素。现在我的行​​为是,当用户放大或缩小图像时,图像会变大/变小。我还循环了画布上的所有对象,然后为其设置了 scaleX 和 scaleY,但结果对我来说太迟钝了。

var canvas = new fabric.Canvas('c') ;

var circle = new fabric.Circle({
  radius: 20, fill: 'red', left: 100, top: 100
});


var triangle = new fabric.Triangle({
   fill: 'red', left: 200, top: 200
});
canvas.add(circle, triangle) ;
//canvas.zoomToPoint(new fabric.Point(canvas.getCenter().left, canvas.getCenter().top,1)) ;

$(function(){
   
    $('#zoomIn').click(function(){
        canvas.setZoom(canvas.getZoom() * 1.1 ) ;
    }) ;
    
    $('#zoomOut').click(function(){
        canvas.setZoom(canvas.getZoom() / 1.1 ) ;
    }) ;
    
}) ;
#canvasContainer {border: dotted gray thin ;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
<div id="canvasContainer">
    <canvas id="c" width="400" height="400"></canvas>
</div>

【问题讨论】:

  • 如果要保持对象的比例,那么画布缩放有什么用?
  • 我使用缩放级别除以 1 做了一些工作,但输出对我来说太迟钝了。
  • 我已经更新了小提琴示例。现在我在放大或缩小时遇到了很大的延迟,因为该组由 6 种不同类型的对象组成。
  • 我的问题的正确例子是谷歌地图。我希望对象不会变大或变小,即使我放大或缩小它。
  • 标记延迟可以来自fabric 1.5版本。根据您编写的代码量和您的项目,尝试切换到 2.0 或至少 1.7.22 您的地图上有多少组 6 个对象?

标签: javascript html5-canvas fabricjs scaling


【解决方案1】:

这不是fabricjs的内置功能,您必须通过子类化或修改fabric.Object类的标准代码来解决它。

我会做一个例子,然后你可以用它来找到更适合你的项目的解决方案。

所以对于整个画布有一个缩放阶段,然后每个对象都有自己的变换。这发生在fabric.Object.prototype.transform。到那时,缩放就完成了,你无法真正避免它。你可以做的是在绘图之前向相反的方向放大。

因此,使用新属性 ignoreZoom 默认为 false 标记您需要不缩放的对象。

这样修改fabric.Object.prototype.transform:

transform: function(ctx, fromLeft) {
      if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {
        this.group.transform(ctx);
      }
      // ADDED CODE FOR THE ANSWER
      if (this.ignoreZoom && !this.group && this.canvas) {
        var zoom = 1 / this.canvas.getZoom();
        ctx.scale(zoom, zoom);
      }
      // END OF ADDED CODE FOR THE ANSWER
      var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
      ctx.translate(center.x, center.y);
      this.angle && ctx.rotate(degreesToRadians(this.angle));
      ctx.scale(
        this.scaleX * (this.flipX ? -1 : 1),
        this.scaleY * (this.flipY ? -1 : 1)
      );
      this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
      this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
    },

这解决了渲染问题,但不解决控件和缓存问题。 缓存更难理解,所以我建议你对不需要缩放的对象禁用缓存。

对于控件我稍后会回来,不是超级简单。

fabric.Object.prototype.ignoreZoom = false;
fabric.Object.prototype.transform = function(ctx, fromLeft) {
          if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) {
            this.group.transform(ctx);
          }
          // ADDED CODE FOR THE ANSWER
          if (this.ignoreZoom && !this.group && this.canvas) {
            var zoom = 1 / this.canvas.getZoom();
            ctx.scale(zoom, zoom);
          }
          // END OF ADDED CODE FOR THE ANSWER
          var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
          ctx.translate(center.x, center.y);
          this.angle && ctx.rotate(degreesToRadians(this.angle));
          ctx.scale(
            this.scaleX * (this.flipX ? -1 : 1),
            this.scaleY * (this.flipY ? -1 : 1)
          );
          this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
          this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
        };

var canvas = new fabric.Canvas('c') ;

var circle = new fabric.Circle({
  radius: 20, fill: 'red', left: 100, top: 100, ignoreZoom: true
});


var triangle = new fabric.Triangle({
   fill: 'red', left: 200, top: 200
});
canvas.add(circle, triangle) ;
//canvas.zoomToPoint(new fabric.Point(canvas.getCenter().left, canvas.getCenter().top,1)) ;

$(function(){
   
    $('#zoomIn').click(function(){
        canvas.setZoom(canvas.getZoom() * 1.1 ) ;
    }) ;
    
    $('#zoomOut').click(function(){
        canvas.setZoom(canvas.getZoom() / 1.1 ) ;
    }) ;
    
}) ;
#canvasContainer {border: dotted gray thin ;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<button id="zoomIn">+</button>
<button id="zoomOut">-</button>
<div id="canvasContainer">
    <canvas id="c" width="400" height="400"></canvas>
</div>

【讨论】:

  • 安德烈亚,谢谢你的回答。我应该说在你的例子中圆圈上有一些模糊,这种模糊在缩放时变得非常强烈。能避免吗?
  • 什么模糊问题?
  • @AndreaBogazzi 你好安德里亚我刚刚打开了一个与这个问题相关的帖子,你可以看看它。 The link。提前很多 thnks
  • 我尝试在此处修复控件问题,但仍然无法保持位置stackoverflow.com/questions/67603796/…
【解决方案2】:

以下是我们如何解决此问题的以下步骤:

1.获取比例 - (1 / zoomLevel)。我默认设置为“1”。

循环所有组对象,并将“scaleX”和“scaleY”设置为这种计算。

objects.forEach(object => {
  object.scaleX = (scale || 1) * 2.5;
  object.scaleY = (scale || 1) * 2.5;
});

【讨论】:

  • 如果可能的话,你能澄清一下吗?
猜你喜欢
  • 2021-08-08
  • 2018-08-06
  • 2015-02-12
  • 2017-10-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
相关资源
最近更新 更多