Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pinch to Zoom all Canvas Objects #2658

Closed
Kampii opened this issue Nov 29, 2015 · 7 comments
Closed

Pinch to Zoom all Canvas Objects #2658

Kampii opened this issue Nov 29, 2015 · 7 comments

Comments

@Kampii
Copy link

Kampii commented Nov 29, 2015

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?

@kangax
Copy link
Member

kangax commented Dec 25, 2015

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.

@Anruin
Copy link

Anruin commented Feb 28, 2016

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);
  }
}

@Sphinxxxx
Copy link

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; }

@jtara
Copy link

jtara commented Jun 25, 2017

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 calling zoomToPoint(). This is why - for now - I've just enabled scaling of the entire document (which is not ideal).

@jtara
Copy link

jtara commented Jun 26, 2017

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));

@marsonmao
Copy link

@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?

@ShaMan123
Copy link
Contributor

viewportTransform
see http://fabricjs.com/fabric-intro-part-5#pan_zoom

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants