Fabric.js: Pinch to Zoom all Canvas Objects

Created on 29 Nov 2015  路  6Comments  路  Source: fabricjs/fabric.js

What is the syntax for that? Looks like pinching gesture scales an object, but how would I zoom in/out all of the canvas objects?

possible_feature

Most helpful comment

Hi, if it will help, that's what I'm using in my project, as an example. Works for me.

'touch:gesture': function(event) {
  // 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);
  }
}

All 6 comments

You'll need to hook up gestures to our zooming functions. Nothing like this built-in afair, but I'll mark it as possible feature.

Hi, if it will help, that's what I'm using in my project, as an example. Works for me.

'touch:gesture': function(event) {
  // 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);
  }
}

_Note: I only use the "free drawing" feature of the library, so this probably won't do as a general fix._

To allow normal pinch-to-zoom while drawing, I simply added this as the first line of _onMouseMove():

if((e.type === 'touchmove') && (e.touches.length > 1)) { return; }

Unfortunately, Sphinxxx's solution makes marks in drawing mode. It's of course impossible to make two touches at EXACTLY the same time!

I did it a bit differently, BTW, so that I can easily shut it off. And I first did it as a monkey-patch, but the monkey-patch became impractical when I started meddling with other code that isn't so easily patched. (I will probably go back to monkey-patch).

    _onMouseMove: function (e) {
      // LOCALMOD: ignore multi-touch
      if (this.allowTouchScrolling) {
        if((e.type === 'touchmove') && (e.touches.length > 1)) { return;}
      }
      e.preventDefault && e.preventDefault();
      this.__onMouseMove(e);
    },

allowTouchScrolling on it's own is a non-starter, as it does nothing to prevent marks, and makes much bigger marks!

I think what is needed here is to delete the most recently-started path in drawing mode when a multi-touch touchmove is seen. I'm not familiar enough with the code to do that.

I haven't tried Anruin's solution yet. Problem is, I need to scale both the canvas and multiple positioned overlays. But I think perhaps it will work for me if I substitute a CSS transform of the container (of canvas and overlays) for callingzoomToPoint(). This is why - for now - I've just enabled scaling of the entire document (which is not ideal).

Some changes to my solution, it is still far from perfect. The 400mSec delay is annoying, and still it sometimes leaves a small mark in drawing mode.

(Note the sv_ prefix is just to make names unique to my app...)

*jslint browser: true, devel: true, vars: true, unparam: true, white: true, indent: 2 */
/*global fabric */

(function fabricZoomMonkeypatchSelfEx(window, document, undefined) {
  'use strict';

  fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {

    _svTouchStartDeferTimerID: undefined,

    _svOnMouseDownOriginal: fabric.Canvas.prototype._onMouseDown,

    _onMouseDown: function (e) {
      if (this.allowTouchScrolling) {
        // This is dubious, because it will be almost impossible to have touchstart with multi-touch
        if (e.touches && (e.touches.length > 1)) {return;}
        clearTimeout(this._svTouchStartDeferTimerID);
        this._svTouchStartDeferTimerID = undefined;
        if(e.type === 'touchstart') {
          var _this = this;
          this._svTouchStartDeferTimerID = setTimeout(function() {
            _this._svTouchStartDeferTimerID = undefined;
            _this._svOnMouseDownOriginal(e);
          }, 400);
        }
      } else {
        this._svOnMouseDownOriginal(e);
      }
    },

    _onMouseMove: function (e) {
      if (this.allowTouchScrolling) {
        if((e.type === 'touchmove') && e.touches && (e.touches.length > 1)) {return;}
      }
      e.preventDefault && e.preventDefault();
      this.__onMouseMove(e);
    }

  });

}(window, document));

@Anruin

  1. I'd like to know what is self.canvas in the codes you share? Is it event.self.canvas? Thanks.
  2. Also that I can't get touch:gesture fired on my canvas, but my objects on the canvas can be scaled by gesture. Not sure if you've ever had the same issue?
Was this page helpful?
0 / 5 - 0 ratings

Related issues

lyzs90 picture lyzs90  路  3Comments

zhangzhzh picture zhangzhzh  路  4Comments

amancqlsys picture amancqlsys  路  5Comments

semiadam picture semiadam  路  3Comments

bhaskardas9475 picture bhaskardas9475  路  4Comments