FabricJS触摸平移/缩放整个画布

6
我需要在FabricJS画布上启用触摸缩放/平移功能。有一些库可以实现图像的此类行为(请参见pinch-zoom-canvas),或通过鼠标点击事件来实现(请参见这个Fiddle),但我似乎无法正确连接'touch:gesture'事件。 我已经构建了启用手势的库(所以这个FabricJS 演示对我本地有效),但我不知道从哪里开始将手势与工作中的Fiddle组合起来。 我尝试了这样代码的变化:
    canvas.on({
        'touch:gesture': function() {
            var text = document.createTextNode(' Gesture ');
            info.insertBefore(text, info.firstChild);
            // Handle zoom only if 2 fingers are touching the screen
            if (event.e.touches && event.e.touches.length == 2) {
                // Get event point
                var point = new fabric.Point(event.self.x, event.self.y);
                // Remember canvas scale at gesture start
                if (event.self.state == "start") {
                    zoomStartScale = self.canvas.getZoom();
                }
                // Calculate delta from start scale
                var delta = zoomStartScale * event.self.scale;
                // Zoom to pinch point
                self.canvas.zoomToPoint(point, delta);
            }

        },
        'touch:drag': function(e) {
            panning = true;
            var text = document.createTextNode(' Dragging ');
            info.insertBefore(text, info.firstChild);
            if (panning && e && e.e) {
                debugger;
                var units = 10;
                var delta = new fabric.Point(e.e.movementX, e.e.movementY);
                canvas.relativePan(delta);
            }
            panning = false;
        },
        'touch:longpress': function() {
            var text = document.createTextNode(' Longpress ');
            info.insertBefore(text, info.firstChild);
        }
    });

但是在 iPhone/iPad 上测试时没有任何反应。

3个回答

13

捏合放大是一个愚蠢的错误,我没有在函数参数中包含该事件。下面的代码适用于捏合/缩放和轻触/拖动。

    canvas.on({
        'touch:gesture': function(e) {
            if (e.e.touches && e.e.touches.length == 2) {
                pausePanning = true;
                var point = new fabric.Point(e.self.x, e.self.y);
                if (e.self.state == "start") {
                    zoomStartScale = self.canvas.getZoom();
                }
                var delta = zoomStartScale * e.self.scale;
                self.canvas.zoomToPoint(point, delta);
                pausePanning = false;
            }
        },
        'object:selected': function() {
            pausePanning = true;
        },
        'selection:cleared': function() {
            pausePanning = false;
        },
        'touch:drag': function(e) {
            if (pausePanning == false && undefined != e.e.layerX && undefined != e.e.layerY) {
                currentX = e.e.layerX;
                currentY = e.e.layerY;
                xChange = currentX - lastX;
                yChange = currentY - lastY;

                if( (Math.abs(currentX - lastX) <= 50) && (Math.abs(currentY - lastY) <= 50)) {
                    var delta = new fabric.Point(xChange, yChange);
                    canvas.relativePan(delta);
                }

                lastX = e.e.layerX;
                lastY = e.e.layerY;
            }
        }
    });

绝对 ~50像素的if/then语句是为了避免拖动图形远离上一个点导致画布跳动。此外,暂停平移以便能够独立移动对象。捏合/缩放代码在github问题线程中找到。


太棒了!对于所有的Fabric用户来说,这真是一个巨大的帮助! - Marson Mao
有几个问题:我尝试了这个答案,但是我的 canvas 没有接收到 touch:gesture,似乎只有对象才能接收 touch:gesture?真的想知道您的画布如何接收 touch:gesture 事件,谢谢!顺便说一下,我正在使用 1.7.20(带有 build_with_gestures)。 - Marson Mao
能否只缩放元素?如果我尝试在画布背景上缩放,我想要整个页面都被缩放。 - Simone
1
@Simone,你可以使用“object:hover”来改变对象的比例。不过我建议你另外创建一个问题,详细说明你想要的功能。 - Lauren

4

我在使用 Fabric 2.3.3 的时候,遇到了一些问题,无法让 Laurens 代码中的平移部分正常工作。如果有人遇到同样的问题,我想分享我的解决方案。

我的问题是,在电脑上可以正常工作,但在智能手机上无法进行平移。经过一些调试,我发现可以通过将 e.e.layerX 替换为 e.self.x(并将 e.e.layerY 替换为 e.self.y)来解决这个问题。

下面是完整修改后的代码:

canvas.on({
    'touch:gesture': function(e) {
        if (e.e.touches && e.e.touches.length == 2) {
            pausePanning = true;
            var point = new fabric.Point(e.self.x, e.self.y);
            if (e.self.state == "start") {
                zoomStartScale = canvas.getZoom();
            }
            var delta = zoomStartScale * e.self.scale;
            canvas.zoomToPoint(point, delta);
            pausePanning = false;
        }
    },
    'object:selected': function() {
        pausePanning = true;
    },
    'selection:cleared': function() {
        pausePanning = false;
    },
    'touch:drag': function(e) {
        if (pausePanning == false && undefined != e.self.x && undefined != e.self.x) {
            currentX = e.self.x;
            currentY = e.self.y;
            xChange = currentX - lastX;
            yChange = currentY - lastY;

            if( (Math.abs(currentX - lastX) <= 50) && (Math.abs(currentY - lastY) <= 50)) {
                var delta = new fabric.Point(xChange, yChange);
                canvas.relativePan(delta);
            }

            lastX = e.self.x;
            lastY = e.self.y;
        }
    }
});}

非常感谢您!我也遇到了画布平移的问题,这个解决方法很有效。 - Kenji Miwa

-1

我能够通过鼠标滚轮事件实现多点触控平移和缩放。

在进行捏合缩放时,大多数浏览器 通常也会发出 ctrl 按钮以区分滚动操作和非滚动操作。

然后,我利用 Fabric 事件的 DeltaX 和 DeltaY 属性来实现类似于他们提供的 示例 代码的缩放或平移。

如果您没有使用 React,请将下面每个调用 setState 的地方设置为函数外的变量。

    this.canvas.on("mouse:wheel", opt => {
      if (!this.canvas.viewportTransform) {
        return;
      }

      var evt: any = opt.e;
      if (evt.ctrlKey === true) {
        var evt: any = opt.e;
        var deltaY = evt.deltaY;
        var zoom = this.canvas.getZoom();
        zoom = zoom - deltaY / 100;
        if (zoom > 20) zoom = 20;
        if (zoom < 0.01) zoom = 0.01;
        this.canvas.zoomToPoint(
          new fabric.Point(evt.offsetX, evt.offsetY),
          zoom
        );
      } else {
        console.log("Scrolling!!");

        //inverted scrolling enabled. Remove the -1 multiplier to disable

        this.canvas.viewportTransform[4] += (evt.deltaX)*-1; 
        this.canvas.viewportTransform[5] += (evt.deltaY)*-1;
        this.canvas.requestRenderAll();
        this.setState({ lastPosX: evt.clientX });
        this.setState({ lastPosY: evt.clientY });
      }
      opt.e.preventDefault();
      opt.e.stopPropagation();
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接