Pinch zoom in steps

Hi. This is a ‘how to’ question.

Scenario: I have a gojs canvas displaying an image. I control the ‘zoom depth’ that the user can select. I do this because I want to show different quality images at different zooms. So when you zoom 300% you are going to see an image that is actually 3 x the size of the 100% image. I do this so that at the set zoom steps there is no pixelation of the images. The scale of the gojs is never changed - I just change the image layer on show as the zoom increases. All works well with mouse-click and tap events to fire zoom process.

Question; I want to provide a familiar pinch-zoom facility on tablet. To do so I will need to listen for a pinch event and to know the delta on the pinch. And to do the stepping smoothly I will need to be able to do so during the pinch action. I can then relate the pinch delta to my pre-set images and expose as required.

So - what event should I be listening for and are there any examples you could link me to?


Actually, you don’t care about the delta of the zoom/scale. You just need to know the actual new Diagram.scale. You can look at that in a “ViewportBoundsChanged” DiagramEvent listener.

Thanks for the quick answer - but can I just check…

You are suggesting I use the scale which would normally make sense, but I am dis-allowing zoom (allowZoom: false in diagram constructor) because I want control of the zoom as I described in my opening post.

So if the diagram neither zooms not pans then if I understand correctly the ViewportBoundsChanged will not fire. Did I get that right ?

Oh, I’m sorry, I misunderstood you.

Have you read and seen ? That should make you more aware of what is possible, especially

I haven’t tried what I think you are looking for, so I’m not sure what would be best regarding implementation.

Thanks. Yes I have seen the viewport, scroll modes and scale calculation function examples.

Sadly I am stuck with the allowZoom=false setting which precludes the scale calculation approach. I will set up a demo and see what I can find. Will report back.

ok - see codepen

I am using the touch library hammer.js and its touch emulator so we can test on desktop. The outer region illustrates touch events for panning and pinching (hold shift and click-drag for pinch) on a plain div.

Requirement: Detect user wants to pinch zoom and how much by, but do not allow the actual zoom to happen.

Looking at the docs it appeared that the best option for me is the ViewportBoundsChanged event, as per your suggestion. This is fine if I allow zoom but remember I want to detect the pinch gesture without zooming the canvas.

I went on to stop the zoom in gojs by setting allowZoom false, or having maxScale and minScale = 1. No surprises that when the zoom is disallowed the viewport does not change and the event is not triggered.

I also tried with zooming allowed and reset the diagram.scale back to 1 in the ViewportBoundsChanged event. However this caused the diagram to skitter across the page. I left that line commented out in the codepen for now.

What I think I need is a ‘before-zoom’ event which I could read and cancel.

I conclude that I need to either:

  1. Subclass the pinch start, move, and end events, or
  2. Subclass the before-zoom-step event so that I can know the delta, but cancel the actual zoom.

Are there any unpublished events I can listen for that would help ?

Explanation of need: In anticipation of the question ‘why do you need this?’ I need to do this because my diagram is a view of an image that has user annotations ‘around’ it. Think of sticky notes and arrows to points of note on the image. When the user zooms the image the sticky notes should not scale but the image should. Except that, like Google maps, as the image ‘zooms’ the initial image is replaced by an associated version of the same thing but at a scale matching that which the user wants.

That’s what the Tool.standardPinchZoomStart and Tool.standardPinchZoomMove methods are for. You can override the methods on the ToolManager. As the documentation states, you’ll probably want to call this.doCancel() before computing what you need from the touch points and modifying your images. You can get the TouchEvent from this.diagram.lastInput.event.

Alas, I cannot find an example for you at the moment.

Excellent - I’ll get on that immediately. Is there a gojs documentation link for Tool.standardPinchZoomStart ?

Will report back.

Yes, I even mentioned their documentation in my previous post.

Whenever you want to look something up, just Google “gojs” and whatever words you are interested in.

Thanks and sorry if I missed it but I can’t see your reference to the gojs docs. I see the mozilla link. No worries though, I have it now.

Thanks this is looking useful. Looking at the calculation for the amount of zoom I need to know the distance between the two touch points (fingertips) because the scaling is proportional to the distance moved.

Zoom = new distance / initial distance.

Can you direct me to the gojs docs regarding the attributed of the pinch events please ?

I am currently getting the delta by using the diagram.lastInput in the standardPinchZoomStart event as the starting point and the same in the standardPinchZoomMove event as the new point and subtracting. Math.hypot() gives the distance travelled but that is not the value I need. Looking at the Mozilla docs there might be a collection of ‘touches’ that I need to iterate.

You do not want to use any of the information in the InputEvent besides the InputEvent.event, which is a TouchEvent. Everything that you need is available in the MDN documentation, nothing involving GoJS or the GoJS documentation. The hard part, as usual, is dealing with the various coordinate systems used by HTML DOM.