Skip to content

Instantly share code, notes, and snippets.

@larsneo
Forked from jsprpalm/viewer.html
Last active May 21, 2025 17:22
Show Gist options
  • Save larsneo/bb75616e9426ae589f50e8c8411020f6 to your computer and use it in GitHub Desktop.
Save larsneo/bb75616e9426ae589f50e8c8411020f6 to your computer and use it in GitHub Desktop.
Pinch zoom implementation for PDF.js viewer
<!-- Goes into viewer.html just before ending </body> -->
<script>
let pinchZoomEnabled = false;
function enablePinchZoom(pdfViewer) {
let startX = 0, startY = 0;
let initialPinchDistance = 0;
let pinchScale = 1;
const viewer = document.getElementById("viewer");
const container = document.getElementById("viewerContainer");
const reset = () => { startX = startY = initialPinchDistance = 0; pinchScale = 1; };
// Prevent native iOS page zoom
//document.addEventListener("touchmove", (e) => { if (e.scale !== 1) { e.preventDefault(); } }, { passive: false });
document.addEventListener("touchstart", (e) => {
if (e.touches.length > 1) {
startX = (e.touches[0].pageX + e.touches[1].pageX) / 2;
startY = (e.touches[0].pageY + e.touches[1].pageY) / 2;
initialPinchDistance = Math.hypot((e.touches[1].pageX - e.touches[0].pageX), (e.touches[1].pageY - e.touches[0].pageY));
} else {
initialPinchDistance = 0;
}
});
document.addEventListener("touchmove", (e) => {
if (initialPinchDistance <= 0 || e.touches.length < 2) { return; }
if (e.scale !== 1) { e.preventDefault(); }
const pinchDistance = Math.hypot((e.touches[1].pageX - e.touches[0].pageX), (e.touches[1].pageY - e.touches[0].pageY));
const originX = startX + container.scrollLeft;
const originY = startY + container.scrollTop;
pinchScale = pinchDistance / initialPinchDistance;
viewer.style.transform = `scale(${pinchScale})`;
viewer.style.transformOrigin = `${originX}px ${originY}px`;
}, { passive: false });
document.addEventListener("touchend", (e) => {
if (initialPinchDistance <= 0) { return; }
viewer.style.transform = `none`;
viewer.style.transformOrigin = `unset`;
PDFViewerApplication.pdfViewer.currentScale *= pinchScale;
const rect = container.getBoundingClientRect();
const dx = startX - rect.left;
const dy = startY - rect.top;
container.scrollLeft += dx * (pinchScale - 1);
container.scrollTop += dy * (pinchScale - 1);
reset();
});
}
document.addEventListener('webviewerloaded', () => {
if (!pinchZoomEnabled) {
pinchZoomEnabled = true;
enablePinchZoom();
}
});
</script>
@naynara87
Copy link

I have a question. As I touch to zoom out, I want to set my pdf page scale for min size (page fit)
How can I do. I waiting for your ask.

@BekNaji
Copy link

BekNaji commented Jun 21, 2022

So I have set minScale and maxScale like this. Just replace touchend event

const pinchMaxScale = 5;
const pinchMinScale = 0.3;
      document.addEventListener("touchend", (e) => {
            if (initialPinchDistance <= 0) { return; }
            viewer.style.transform = `none`;
            viewer.style.transformOrigin = `unset`;
            
            const newPinchScale = PDFViewerApplication.pdfViewer.currentScale * pinchScale;

            if (newPinchScale <= pinchMaxScale && newPinchScale >= pinchMinScale) {
                PDFViewerApplication.pdfViewer.currentScale = newPinchScale;
                const rect = container.getBoundingClientRect();
                const dx = startX - rect.left;
                const dy = startY - rect.top;
                container.scrollLeft += dx * (pinchScale - 1);
                container.scrollTop += dy * (pinchScale - 1);
            }else{
            	if(newPinchScale >= pinchMaxScale){
            		PDFViewerApplication.pdfViewer.currentScale = pinchMaxScale;
            	}else{
            		PDFViewerApplication.pdfViewer.currentScale = pinchMinScale;
            	}
            }
            reset();
        });

I hope it will help someone else :-)

@Ikau
Copy link

Ikau commented Jun 22, 2022

So this code is working fine but it may need a little update if you're using recent versions of mozilla/pdf.js

webviewerloaded was not firing on iOS 13+ and Android 10+ when I tested because the event was fired using deprecated code.

In this case, you should be listening on DOMContentLoaded instead of webviewerloaded

Replace

document.addEventListener('webviewerloaded', () => {

With

document.addEventListener('DOMContentLoaded', () => {

@meghrathod
Copy link

Hence the final code should be this:

let pinchZoomEnabled = false;
function enablePinchZoom(pdfViewer) {
    let startX = 0,
        startY = 0;
    let initialPinchDistance = 0;
    let pinchScale = 1;
    const viewer = document.getElementById("viewer");
    const container = document.getElementById("viewerContainer");
    const reset = () => {
        startX = startY = initialPinchDistance = 0;
        pinchScale = 1;
    };
    // Prevent native iOS page zoom
    //document.addEventListener("touchmove", (e) => { if (e.scale !== 1) { e.preventDefault(); } }, { passive: false });
    document.addEventListener("touchstart", (e) => {
        if (e.touches.length > 1) {
            startX = (e.touches[0].pageX + e.touches[1].pageX) / 2;
            startY = (e.touches[0].pageY + e.touches[1].pageY) / 2;
            initialPinchDistance = Math.hypot(
                e.touches[1].pageX - e.touches[0].pageX,
                e.touches[1].pageY - e.touches[0].pageY
            );
        } else {
            initialPinchDistance = 0;
        }
    });
    document.addEventListener(
        "touchmove",
        (e) => {
            if (initialPinchDistance <= 0 || e.touches.length < 2) {
                return;
            }
            if (e.scale !== 1) {
                e.preventDefault();
            }
            const pinchDistance = Math.hypot(
                e.touches[1].pageX - e.touches[0].pageX,
                e.touches[1].pageY - e.touches[0].pageY
            );
            const originX = startX + container.scrollLeft;
            const originY = startY + container.scrollTop;
            pinchScale = pinchDistance / initialPinchDistance;
            viewer.style.transform = `scale(${pinchScale})`;
            viewer.style.transformOrigin = `${originX}px ${originY}px`;
        },
        { passive: false }
    );
    document.addEventListener("touchend", (e) => {
        if (initialPinchDistance <= 0) {
            return;
        }
        viewer.style.transform = `none`;
        viewer.style.transformOrigin = `unset`;
        PDFViewerApplication.pdfViewer.currentScale *= pinchScale;
        const rect = container.getBoundingClientRect();
        const dx = startX - rect.left;
        const dy = startY - rect.top;
        container.scrollLeft += dx * (pinchScale - 1);
        container.scrollTop += dy * (pinchScale - 1);
        reset();
    });
}
document.addEventListener("DOMContentLoaded", () => {
    if (!pinchZoomEnabled) {
        pinchZoomEnabled = true;
        enablePinchZoom();
    }
});

It can be placed in a file called zoom.js and you can just add this line before the final </body> tag in viewer.html file in the web folder.

<body>
    ---
    ---
    <script src="zoom.js"></script>
</body>

@yc-cui
Copy link

yc-cui commented Aug 15, 2022

Is this just suitable for viewer.html? Can I utilize it within my customed viewer? Like a viewer in a div using canvas backend?

@sergiobellini
Copy link

sergiobellini commented Sep 13, 2022

Unfortunately pinch-to-zoom doesn't work if I put the viewer in an iframe :( Is there any kind of solution?

@meghrathod
Copy link

Is this just suitable for viewer.html? Can I utilize it within my customed viewer? Like a viewer in a div using canvas backend?

I think it should work but you would have to make appropriate changes as required by the back end that you make.

@azazel404
Copy link

hello guys , when i implement and test it on my application ,it doesn't work

@duandre
Copy link

duandre commented Apr 15, 2023

Thank you @meghrathod - It's working for BlazorWebView in MAUI Blazor

@mazhewei
Copy link

hi guys, if you use modern browser, please upgrade pdfjs to latest version or the supported version(version >=3.3.122, for more info see this PR), pdfjs now support pinch-to-zoom feature.
if unfortunately, not use modern browser(for example, you have to use pdfjs version v2.x), this code work perfectly!

@kosuke-zhang
Copy link

kosuke-zhang commented Nov 5, 2024

hi guys, if you use modern browser, please upgrade pdfjs to latest version or the supported version(version >=3.3.122, for more info see this PR), pdfjs now support pinch-to-zoom feature. if unfortunately, not use modern browser(for example, you have to use pdfjs version v2.x), this code work perfectly!

example mobile-viewer not support pinch zoom, do you know how to enable?

mozilla/pdf.js#19004
https://github.com/mozilla/pdf.js/tree/master/examples/mobile-viewer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment