Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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 });
viewer.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;
}
});
viewer.addEventListener("touchmove", (e) => {
if (initialPinchDistance <= 0 || e.touches.length < 2) { return; }
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`;
});
viewer.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>
@rodgaldeano
Copy link

rodgaldeano commented Sep 20, 2019

When I tested it in Xamarin.Forms 4 the EventListeners were overriding those of the viewer.js, so I could pinch zoom but not swipe the page. Fixed it by replacing "viewer" for "document" in lines 15, 25 and 37, and adding the code in line 13 to the corresponding event.

Thanks

@aidrouge
Copy link

aidrouge commented Oct 8, 2019

When I tested it in Xamarin.Forms 4 the EventListeners were overriding those of the viewer.js, so I could pinch zoom but not swipe the page. Fixed it by replacing "viewer" for "document" in lines 15, 25 and 37, and adding the code in line 13 to the corresponding event.

Thanks

@rodgaldeano can you please post the fixed code please man.

@MickLesk
Copy link

MickLesk commented Oct 15, 2019

@rodgaldeano i dont know what you mean with

adding the code in line 13 to the corresponding event.

I use xF 4.2 and i cant swipe pages

@larsneo
Copy link

larsneo commented Nov 7, 2019

guess this means instead of line 13 add the stuff in the corresponding touchmove-function

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

@aidrouge
Copy link

aidrouge commented Nov 8, 2019

@larsneo thank you so so so much its working prefectly now

<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("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>

@larsneo
Copy link

larsneo commented Nov 8, 2019

my pleasure, complete code also forked at https://gist.github.com/larsneo/bb75616e9426ae589f50e8c8411020f6

@cepm-nate
Copy link

cepm-nate commented Apr 13, 2021

This works well for zooming, but seems to disable the normal drag-on-finger-to-pan action because of line 13. If I change the condition to be e.touches.length > 1 && e.scale !== 1, then it seems to work without problem on Android.

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