-
-
Save larsneo/bb75616e9426ae589f50e8c8411020f6 to your computer and use it in GitHub Desktop.
<!-- 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> |
This solution does not work correctly if we render the entire document at once, rather than one page. Has anyone tried to solve this problem?
Lazy loading would be the correct way. You would also need to ensure that if user scrolls a page after let's say 5 pages,free it from memory, but i believe pdfjs is already doing it. I better solution would be to just translate pdfjs when user is zooming and do not do actual zooming and store the value. When user has finished, do the actual zooming. Plus the code is resetting currentscale after every time. Instead we can set a maximum and minimum possible scale say 3 and 0.1. I noticed that google drive also do not do any zoom while user is pinching but it does when user has finished it.
It looks like the code is doing exactly the same thing except setting max and min scale
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.
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 :-)
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', () => {
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>
Is this just suitable for viewer.html
? Can I utilize it within my customed viewer? Like a viewer in a div
using canvas backend?
Unfortunately pinch-to-zoom doesn't work if I put the viewer in an iframe :( Is there any kind of solution?
Is this just suitable for
viewer.html
? Can I utilize it within my customed viewer? Like a viewer in adiv
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.
hello guys , when i implement and test it on my application ,it doesn't work
Thank you @meghrathod - It's working for BlazorWebView in MAUI Blazor
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!
One solution would be to only zoom only the current page and save the scale value somewhere so that next pages renders with the new scale. Currently, I believe it's trying to resize whole pdf or part of the pdf which has been loaded which explains the delay. I do not have any idea on how to implement it.