Ngx-extended-pdf-viewer: Pinch to zoom on mobile

Created on 15 Apr 2020  路  10Comments  路  Source: stephanrauh/ngx-extended-pdf-viewer

In the demo (https://pdfviewer.net/simple) I could pinch to zoom the PDF with the macbook trackpad, but on mobile (using Firefox mobile on Android) I zoom the whole page, not just the embedded PDF.

Is doing so a new feature, or is this possible already, provided the right integration?

If it is a feature, how hard would it be to integrate using hammerjs? Currently, I am looking into different PDF plugins (along with ng2-pdf-viewer and ng2-pdfjs-viewer) and wondering, if I had to integrate it myself, a fork of which would be the easiest.

Confirmed Working on it bug enhancement

Most helpful comment

I've started to add your class to ngx-extended-pdf-viewer, but it doesn't seem to work yet. Maybe I've got more luck tomorrow!

https://pdfviewer.net/touch-gestures

All 10 comments

@codehippie1 @VadimDez I'm adding you to the loop. I suppose you've either already solved the problem, or you're interested in solving the problem. Let's do it with joint forces!

@philly-vanilly The PDF viewer behaves the same on my iPad. That's a bit surprising. It might be a feature on a small cell-phone, but I didn't expect that on a much larger iPad.

I've found it. OSX maps the pinch gesture to mouse-wheel events.

In order to implement zoom and pinch yourself using Hammer.js, all you have to do it to call this methods when you catch a zoom / pinch event:

PDFViewerApplication.zoomOut(1);
PDFViewerApplication.zoomIn(1);

Here's the original implementation: https://github.com/mozilla/pdf.js/blob/50bc4a18e8c564753365d927d5ec6a6d2cce3072/web/app.js#L2446

Maybe you also need to add this line:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

You may also want to look at https://gist.github.com/jsprpalm/12217feab2f1acc14bd8e8508291619e and - probably even better - at https://gist.github.com/larsneo/bb75616e9426ae589f50e8c8411020f6.

@philly-vanilly If you try one of these gists, can you tell me if it works? This looks like a nice feature for ngx-extended-pdf-viewer. However, I wonder which side-effects the feature has.

Did anyone try already the above mentioned gists or any other solutions? It would be nice to have them incorporated into the library. It's a very useful and sometimes critical feature to have.

I placed this code in the component-wrapper and it works quite well. let me know if anyone finds a way to optimize it.

export class MyPdfViewer {
    private enablePinchZoom: boolean = false;
    private viewer: any;
    private container: any;
    private startX: number = 0;
    private startY: number = 0;
    private initialPinchDistance: number = 0;
    private pinchScale: number = 1;

    constructor(private _zone: NgZone) {}

    private onViewerTouchStart(event: TouchEvent): EventListener {
        if (!this.enablePinchZoom) {
            return;
        }
        if (event.touches.length > 1) {
            this.startX = (event.touches[0].pageX + event.touches[1].pageX) / 2;
            this.startY = (event.touches[0].pageY + event.touches[1].pageY) / 2;
            this.initialPinchDistance = Math.hypot((event.touches[1].pageX - event.touches[0].pageX), (event.touches[1].pageY - event.touches[0].pageY));
        } else {
            this.initialPinchDistance = 0;
        }
    }

    private onViewerTouchMove(event: TouchEvent): EventListener {
        if (!this.enablePinchZoom) {
            return;
        }
        if (this.initialPinchDistance <= 0 || event.touches.length < 2) { return; }
        if (this.pinchScale !== 1) { event.preventDefault(); }
        const pinchDistance = Math.hypot((event.touches[1].pageX - event.touches[0].pageX), (event.touches[1].pageY - event.touches[0].pageY));
        const originX = this.startX + this.container.scrollLeft;
        const originY = this.startY + this.container.scrollTop;
        this.pinchScale = pinchDistance / this.initialPinchDistance;
        this.viewer.style.transform = `scale(${this.pinchScale})`;
        this.viewer.style.transformOrigin = `${originX}px ${originY}px`;
    }

    private onViewerTouchEnd(): EventListener {
        if (!this.enablePinchZoom) {
            return;
        }
        const PDFViewerApplication: any = (window as any).PDFViewerApplication;
        if (this.initialPinchDistance <= 0) { return; }
        this.viewer.style.transform = `none`;
        this.viewer.style.transformOrigin = `unset`;
        PDFViewerApplication.pdfViewer.currentScale *= this.pinchScale;
        const rect = this.container.getBoundingClientRect();
        const dx = this.startX - rect.left;
        const dy = this.startY - rect.top;
        this.container.scrollLeft += dx * (this.pinchScale - 1);
        this.container.scrollTop += dy * (this.pinchScale - 1);
        this.resetPinchZoomParams();
    }

    @HostListener('document:webviewerloaded')
    onWebViewerLoaded(): void {
        this.enablePinchZoom = true;
        this.initializePinchZoom();
    }

    private resetPinchZoomParams(): void {
        this.startX = this.startY = this.initialPinchDistance = 0;
        this.pinchScale = 1;
    }

    private initializePinchZoom(): void {
        this.viewer = document.getElementById('viewer');
        this.container = document.getElementById('viewerContainer');
        this._zone.runOutsideAngular(() => {
            document.addEventListener('touchstart', this.onViewerTouchStart.bind(this));
            document.addEventListener('touchmove', this.onViewerTouchMove.bind(this), { passive: false });
            document.addEventListener('touchend', this.onViewerTouchEnd.bind(this));
        });
    }
}

I've started to add your class to ngx-extended-pdf-viewer, but it doesn't seem to work yet. Maybe I've got more luck tomorrow!

https://pdfviewer.net/touch-gestures

It's working for me (tested in 3.7.2 version, bot hAndroid and iOS). The only thing missing (in my opinion) is the ability to set scale limits for zoom in/out. You can currently pinch-zoom out until the doc completely desappears. Would be nice to be able to set it with options or at least to have some default min/max scale preset (like in the desktop mode).

Good idea. Thanks!

BTW: the only reason why this ticket is still open is I don't check the finger position yet:

  • I make sure the first finger is somewhere on the document. But you can put the second finger anywhere, inside or outside the document.
  • As far as I remember, I don't check the scroll position properly. When you're scrolling the entire browser window, the pinch region should scroll, too, but it doesn't.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

JaceAD picture JaceAD  路  7Comments

sameerAhmad9291 picture sameerAhmad9291  路  7Comments

rscherer picture rscherer  路  7Comments

Avejack picture Avejack  路  4Comments

achapman009 picture achapman009  路  3Comments