Skip to content

Instantly share code, notes, and snippets.

@jsprpalm
Created May 23, 2019 12:25
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jsprpalm/12217feab2f1acc14bd8e8508291619e to your computer and use it in GitHub Desktop.
Save jsprpalm/12217feab2f1acc14bd8e8508291619e 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 });
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>
@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

@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