Pdf.js: Use more natural zooming on mobile

Created on 18 Jan 2013  ·  95Comments  ·  Source: mozilla/pdf.js

Right now you have to hit the plus/minus buttons even on mobile in order to zoom the document. This is really strange especially since pinch-to-zoom is active as well. I think the best way to go on mobile is maybe to render at a "natural" size, and let the browser control the zoom, similar to a web page.

1-viewer 2-feature

Most helpful comment

@ltullman @hetalv985 I managed make it working implement it myself, check my gist here:

https://gist.github.com/squallstar/1d720e93eabe7f60dc61b547d2c19228
simply paste that to the end of viewer.html 👍 that's it.

All 95 comments

This is what we wanted to do, but for V1 the pinch to zoom was having issues so we had to use the zoom buttons.

Can you elaborate on the issues? I think we could probably prioritize those for you in order to get PDF.js working well.

I really don't think you want the browser to do the zooming in this case. If pdf.js renders a document at 800x600, and you pinch zoom in, the browser is just going to continue to render that 800x600 content at a new higher resolution which may or may not look like crap depending on the resolution of the device and how much you've zoomed. (I assume pdf.js still uses canvas for rendering and not svg?)

@Snuffleupagus @timvandermeij Are either of you interested in working on this? It seems it shouldn't be too hard using the shared library in gaia https://github.com/mozilla-b2g/gaia/blob/master/shared/js/gesture_detector.js

@brendandahl I'll definitely put it on my to-do list and start experimenting with it soon. https://github.com/mozilla-b2g/gaia/blob/862de8489b648a9af7e8a5b88be031b5479404ba/apps/camera/js/panzoom.js#L15 seems to have a good example, as 'transform' is used for 2-finger pinch events. It would be really great if pinch to zoom would work, as it's used quite often on mobile.

I'm working on this. Interested users can keep an eye on https://github.com/timvandermeij/pdf.js/tree/pinch-to-zoom for the progress. It is already catching the pinch-to-zoom command on my tablet and phone, but the accuracy must be improved, as well as the actual re-rendering (I'll need to find a way to calculate the new scale with the old scale and the new middle point, or some other way).

@timvandermeij One thing we may need to do before we implement this is improve the zoom. We've talked about first just using css transforms to to scale the canvas, then start re-rendering and then once re-rendering is done show the new canvas.

I strongly believe the best solution here is going to be one that relies on the browser's compositor to do the transient zoom (the animation during the pinch or double tap) and then just let pdf.js redraw at the new resolution. The sad part here is that right now content is oblivious to zoom changes, and I don't think resizing the canvas to the new resolution will work. We may need to enhance the canvas spec to handle this.

I had some success with hammer.js. I allowed the "native" pinch of the browser (which leads to blurry PDF) and upon pinchend I redraw the PDF canvas, with scale = scale*zoom and give the canvas the css "transform: scale(1/zoom)". So all will be in the same place (especially text and anchors). Looks neat.

@skruse I prepared a patch for implementing pinch to zoom a while ago (see #3708), also with Hammer.js, but I have not yet succeeded in getting it to work properly on mobile/tablet devices. The pinch motions caused a lot of performance and stability problems. Do you mind sharing your implementation with us? If not, could you create a pull request with your pinch to zoom implementation? Perhaps it could replace mine if it works more fluently on mobile/tablet devices. :)

Hey skruse, how were you able to calculate the zoom ratio at end of zoom?

var zoom = document.documentElement.clientWidth / window.innerWidth;

And I got performance issues too: One should not zoom in "too far" on a mobile device, in terms of the "scale" parameter. I guess 2 or 3 is the very maximum.

+2 for this

Someone got a solution for this 2 year old issue?

Nothing has been done about this as far as I know. I refer to my previous comment in https://github.com/mozilla/pdf.js/issues/2582#issuecomment-30316908. We invite anyone to submit a PR for this once there is working code.

Would love to see a solution for this. At the moment this is the only thing that is stopping me from using pdf.js

:(

Pinch zoom would be great! I found this jquery plugin that uses pdf.js and has pinch zoom and swiping pages. http://touchpdf.net/demo/index.htm But it would be good if it was build in pdf.js from the start :-)

+1 Would love to see this here.

+1, also would the example elsewhere that uses hammer.js to capture the event and then call the pdf.js zoom functions not be a relatively "clean" method?

@sporkman what i did in the end was to render the canvas really large, then to use native browser zooming to allow zooming (my app was designed for touch devices). i can share the source if needed.

@rorysmorris how did you manage to get around disabling native browser zoom when pinching while scrolling? I have also implemented hammer.js on pdf.js but cannot get around that particular issue

Have you tried to use the touch-action CSS property?
https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action

On Oct 5, 2016 3:15 PM, "toplay3" [email protected] wrote:

@rorysmorris https://github.com/rorysmorris how did you manage to get
around disabling native browser zoom when pinching while scrolling? I have
also implemented hammer.js on pdf.js but cannot get around that particular
issue


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/mozilla/pdf.js/issues/2582#issuecomment-251670785,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABTUT83E287dv4LSs4T_TGnzwe8yqCMYks5qw6LmgaJpZM4AXvZ2
.

@Rob--W
wow genius! works perfectly now! thanks so much!

When is this issue planning to be implemented? Its been quite some time since this issue was originally posted. Needless to say +1!

I also check this issue every week since a year now. Would be awesome to have it in core or as a addon with hammer js.

To be more constructive on this thread, here is requirements for UI (if somebody wants to really help out and speed out the resolution of the issue) and there is nothing specific to PDF.js:

  • to zoom and pan set of DIVs (with different sizes) that are vertically stacked
  • not allowing user to get lost in viewport at different scales
  • detect and inform when a div visibility or visible scale changes.

The latter is important since we don't want paint all pages at max resolution on low powered devices. If somebody will have prototype, find to me at IRC I'll help to hook PDFPageView for visibility and scale events. Shall I also set 5-good-beginner-bug?

I agree that this would be a good beginner bug, so I'm labeling it as such.

This is not just for mobile, I'm also getting feature requests to support two-finger trackpad zooming (on Mac).

From my brief investigation, I found that there is no cross-browser way to support zoom gestures yet.

+1

@toplay3 and @Rob--W What did you do to get it working? Adding "touch-action: auto;"? To what? And what else did you do? Thanks!

Hi everyone, like most of you I'm interested in getting pinch to zoom working, has anyone been able to do so, even by using external libs like hammer? If you made it, what is the set up? @rorysmorris @toplay3 @Rob--W thanks

👍

@rorysmorris any advice about the above question? thanks :)

Hi @squallstar - at first I tried to use a JS pinch and zoom library to handle this for me, but I found a few problems. It didn't zoom how i wanted, i.e. it would allow the PDF canvas to go completely off-screen, when i never wanted the edges to be away from the screen edge, if that makes sense. In the end, I just used the native zooming that's built into the mobile browser to pinch/zoom/navigate. I setup PDF.js to render the PDF at 3x the pixel size it was being displayed, then scaled down with CSS, so it would remain fairly crisp when zoomed in. If you need any help, I could show you a working example of my implementation.

@rorysmorris thanks, it would be great if you show me (or send a snippet) or how you implemented it. Much appreciated 👍

@squallstar send me an email through the contact form on my site and I'll get a demo over to you later on today :) http://rorymorris.co.uk

@squallstar This is not really a solution but kind of a workaround. Disadvantages are: Performance, result has devices dependency, zoom is not endless.

The performance is greatly improved by using native scrolling and panning, as opposed to using JavaScript to perform those tasks. Maximum zoom-level is easily configurable with a meta viewport tag, and who wants endless zoom on a rasterised image anyway? Great looking "JS-ImageResizer" library by the way! @MickL

Performance was more a guess. Lets say using an iPhone Plus in landscape @ 2208px width. Now you would have a 6624px Canvas. Depending on the PDF complexity and count of pages you may have 3 rendered 6000px Canvas with HTML-text, graphics etc.

I guess your solution is great for a lot of people. But as you described its more a fake-zoom than it actually triggers PDF.js zoom and rerendering :)

True, performance-wise from that aspect isn't great. In my particular use-case for this, I had to render out 300+ page PDF's at iPad (retina) size, as well as have a drawing canvas on top of each one!

PDF.js would crash the browser (iOS Safari) at around 10 rendered PDF pages, so in the end I had to only show one PDF page at a time with previous/next buttons. Not ideal! And I agree, native zoom functionality built into PDF.js would've been a lot nicer.

checkout kamihq.com for working pinch-zoom example

@rorysmorris I've sent you my email yesterday evening through the contact form, any chance you can send me the example you were talking about? :) thanks

Can anyone who has a working example (@rorysmorris, @Rob--W, etc) please share?

@rorysmorris I tried to contact you through your website. If anyone has a working example of this, can you please share?

@ltullman @hetalv985 I managed make it working implement it myself, check my gist here:

https://gist.github.com/squallstar/1d720e93eabe7f60dc61b547d2c19228
simply paste that to the end of viewer.html 👍 that's it.

Thanks squallstar. But we are not using the viewer.html. We are rendering the pdf in our iOS mobile app inside a div tag. How do we use this feature in that case? Do we need to include the viewer files?

So we have the function handleMouseWheel which is very similar. Why not use the exact same function with touch gesture oder hammer js? Isnt this fixed in 1-2 hours then?

Unfortunately it's not that easy. Please refer to my previous comment at https://github.com/mozilla/pdf.js/issues/2582#issuecomment-30316908. We need to limit the amount of touch gestures so that the canvas is not re-rendered on every delta change, which is a major performance issue. If someone is willing to work on this, feel free to submit a PR and we'll review it.

If thats the only issue... :)

I also noticed on "ctrl + mousewheel" it scrolls to the cursor-position like on Google Maps. But this won't work if there are no scrollbars (which is default on page-load). So to let this feel natural we have to create a padding if needed for pinch-zoom and mousewheel-zoom.

A nice addition would be if mousewheel-zoom and pinch-zoom would use the same function.

Your commit looks good already. Maybe performance is no more an issue, it is more than 3 years ago. Ofcourse the best solution would be: start-pinch -> blurred zoom -> end-pinch -> really zoom pdf. Also user-scalable=no is not working on latest iOS anymore. So we may have to preventDefault(), too.

I invested alot of time in this. Actually it seems possible but there are several problems i couldn't solve:

  • hammer.js only works on pinchend (pinchmove always gets canceled when pdf.js zooms)
  • I could not scroll perfectly to the center of pinchend even though i used the same method as mousewheel-zoom does
  • Sometimes the center is not set correctly by hammer.js
  • Sometimes pinchend is not called by hammer.js and no zoom happens
  • I tried to add css transformation on pinchmove(css zoom on pinchmove, pdf js zoom on pinchend) which would give great performance but again i was not able to scroll perfectly (position #viewer with css translate)
  • hammer.js prevents any other touch-action(in our case regular page scroll) so i had to modify hammer.js to only prevent when 2 fingers are used
  • (Same for mousewheel zoom:) If there are no scrollbars (zoomed out so you see the whole document) we cant position (scroll) the document to the center of pinch.

Probably all of this is solvable but iOS 10 allows page-zoom even when it is disabled with user-scalable=no. So a few times on pinch preventDefault() is not working and the whole page is zoomed. This would lead into major issue for the end user (only way to get out is to double-tap the toolbar).

@MickL I gave it a try. I was able to avoid the "pinch zoom" cancellation by adding the CSS property "pointer-events: none" to the classes pdfViewer and page (and calling stopPropagation + preventDefault when viewerContainer dispatches double touch events so the entire page doesn't zoom on iOS).

I'm having the same issue you describe of not having the perfect zoom position event when I use the modified mousewheel method (pass the next scale to be applied, current "middle position" or target and the delta of "middle position" to know how much to move to left, right, up, down, managed by pdfViewer.container.scrollLeft and pdfViewer.container.scrollTop). There seems to be always an error introduced maybe by the timeout that keeps the viewer from rendering on every double touch event.

Any hint on where to apply those CSS scale transformations to avoid rendering everything on every scale delta?

@betovidal I know it's been a few months since your last post. Have you made any updates on getting pinch-zooming to work in PDF.js? I'm working on a project for work that requires this.
Maybe we could work together to figure something out?

@squallstar I tested your solution on iOS very briefly. And so far, it's working for me! Thanks for sharing your solution 💯

@vuinguyen thanks! I'm glad it worked for you too ;)

+1

Any hope of getting @squallstar's code integrated into a PR? Currently, if a user tries to pinch and zoom on a mobile device, they are often "locked" out of scrolling, and have to reload the page simply to navigate further. Relying on the tiny "+" and "-" buttons to navigate is rather counterintuitive for a mobile viewer in 2018.

Pinch-zoom is "broken" on iOS since iOS 10. Even if everything is implemented perfectly Safari will screw everything up.

Is this an iOS specific issue? Is it possible to pinch zoom a PDF served by pdfjs on Android?

Depends on the browser. I assume that only iOS browsers ignore "user-scalable=no".

Right now you have to hit the plus/minus buttons even on mobile in order to zoom the document. This is really strange especially since pinch-to-zoom is active as well. I think the best way to go on mobile is maybe to render at a "natural" size, and let the browser control the zoom, similar to a web page.

To me, this says it all. I guess this is less about a specific feature and rather an approach to mobile experience.

I assume that only iOS browsers ignore "user-scalable=no".

Correct.

I saw that "Box Content Preview" (which uses PDFJS to show PDFs) does a good implementation for this. This is a Codepen of their viewer:

https://codepen.io/box-platform/pen/rmZdjm

And this is the pull request for their fix:

https://github.com/box/box-content-preview/pull/567

I thought that maybe someone could make something similar for PDFJS, based on their solution. I'll try to implement it myself and post the code if I do. I'll be great if someone else (that probably have more experience than me) can also collaborate and try it!

@amurillo17 thanks for the link. The Box solution looks fantastic. I'd love to see something like this working with pdfjs. Please keep us updated on your progress!

Is there any good solution for this problem?

Any updates for this? Would be a great feature to have!

any updates ? Thanks

Are there any simple ways to add this feature to the existing viewer?

Are there any simple ways to add this feature to the existing viewer?

No.

@prohtex Hm, that's pretty sad. I hope, that such a feature will be added soon after all these years.

@prohtex Hm, that's pretty sad. I hope, that such a feature will be added soon after all these years.

It will only be added when someone steps up and integrates code into a PR (not me, sadly), and even then, it could take years.

I have a workaround, but it is "Android only" as I don't care about iOS in my "Firefox for Android" addon:
https://github.com/M-Reimer/android-pdf-js/blob/master/patches/pdfjs-pinch-gestures.js
My Makefile just appends this to "web/viewer.js". It registers to the touch events and translates the pinch gestures to button clicks.

I have a workaround, but it is "Android only" as I don't care about iOS in my "Firefox for Android" addon:

It works on my iPad as well, but it feels a little bit sluggish and not very natural. It zooms one step after each pinch. So you have to release the fingers to make it zoom and it doesn't matter how far of a distance you have pinched. Is this the normal behavior, or just a device-specific bug? Thank you anyways, cause this is a step into the right direction.

It works on my iPad as well, but it feels a little bit sluggish and not very natural. It zooms one step after each pinch. So you have to release the fingers to make it zoom and it doesn't matter how far of a distance you have pinched. Is this the normal behavior, or just a device-specific bug? Thank you anyways, cause this is a step into the right direction.

Looking at the code, this is not a viable solution or even a good workaround. All this does is watch for zoom events and simulate clicking on the [-] [+] buttons with jQuery.

@prohtex Exactly. If you try it, it does something, but it doesn't work well at all.

As I said: Not perfect but better than nothing.
At least for me it's easier to do the pinch gesture than to hit a small zoom button on a small mobile screen. It makes gestures work that every mobile device user expects to work.

It works on my iPad as well, but it feels a little bit sluggish and not very natural. It zooms one step after each pinch. So you have to release the fingers to make it zoom and it doesn't matter how far of a distance you have pinched. Is this the normal behavior, or just a device-specific bug? Thank you anyways, cause this is a step into the right direction.

It hits the buttons. "Natural zooming" is not possible with this simple approach and I don't want to mess too much with PDF.js. This is not the goal of my Addon.

But it should be possible to do multiple button presses depending on how far the fingers have moved. I'll try that.

Looking at the code, this is not a viable solution or even a good workaround. All this does is watch for zoom events and simulate clicking on the [-] [+] buttons with jQuery.

I'm open to suggestions, but as this is part of an Addon which just wants to make PDF.js usable as PDF viewer inside Firefox, I won't do deep modifications.

BTW: There is not a single line of jQuery in my code. This is raw JavaScript.

It should be actually possible to do the zoom steps while moving the fingers...
I'll try to do some more improvements, but the only communication path, I'll use, are the two buttons that I'll remote-control. This way my code doesn't interfere with PDF.js.

BTW: There is not a single line of jQuery in my code. This is raw JavaScript.

I stand corrected. Hoping for a mature solution soon.

The way to accomplish this is by using css transformation while pinch-zoom. Also the movement of the fingers needs to be applied not just the zoom. Then on pinch-zoom-end you can reset css transformation and apply actual zoom and scroll to pdf.js.

P.S. Using jQuery inside a non-jQuery project already seems like a bad practice to me.

P.S. Using jQuery inside a non-jQuery project already seems like a bad practice to me.

Where does @M-Reimer use JQuery? As he already stated, his workaround does only use plain Javascript.

Yeah.. my bad. Point being, this solution doesn't work well.

Updated so the distance between fingers changes the zoom amount:
https://github.com/M-Reimer/android-pdf-js/blob/master/patches/pdfjs-pinch-gestures.js
It is not possible to zoom while moving the fingers as, for some reason, the actual zoom and redraw causes the touch event to somehow "end".
Again: Better than not handling the gesture at all.

@M-Reimer Thank you very much for your work. At least, it's an improvement compared to the last version. Maybe someone finds a solution to make it redraw while zooming. Or it might be possible to temporarily zoom using css transformations and then redraw it eventually after the touch gesture ends.

@anvaka Looked into the case and it seems like there might be a rather simple solution. Unfortunately I currently don't have the time to test it, but maybe one wants to give it a try.

I made a version based on @squallstar solution that also uses css transform durring the pinch move to give more user feedback. The rendering is only done on touchend. It's not perfect, there are some small issues with scroll positioning after rendering but maybe someone could use it as a start.

https://gist.github.com/jsprpalm/12217feab2f1acc14bd8e8508291619e

Is there still no fix for this issue? I'd like to use pdf.js on mobile but without the ability to zoom it is mostly useless on smaller screens.

I made it work without the use of hammer.js but since it was for a customers project i cant share the code. I implemented pinch and doubletap and zoomed with css and on pinchend i zoomed pdf.js. Some elements require to set width/height and some can be transformed with css-transform. Also while zooming the scroll-watch of pdf.js viewer.js has to be prevented. Took me lot of time but it worked pretty well in the end.

Is there still no fix for this issue? I'd like to use pdf.js on mobile but without the ability to zoom it is mostly useless on smaller screens.

Until a developer experienced with the pdf.js codebase steps to offer a solution, it will be up to each person who implements pdf.js to cobble something together. Doesn’t seem to be a big priority for this project.

Here’s a PR that could be integrated without too much difficulty:

https://github.com/box/box-content-preview/pull/567

https://gist.github.com/jsprpalm/12217feab2f1acc14bd8e8508291619e

@jsprpalm thank you works great needs a fix please someone help to fix

@aidrouge https://gist.github.com/larsneo/bb75616e9426ae589f50e8c8411020f6

I've added this one to my PDF viewer addon. Seems to work pretty well.
https://addons.mozilla.org/android/addon/android-pdf-js/

Edit: works for me

For me working more natural setting this:

<meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=10.0, minimum-scale=1.0"
    />

How do I set the minimum zoom? I can reduce the image so much that it turns into a dot.

I have the same question as @KazysNoobiys.
minimum-scale on the viewport doesn't affect the zooming

I'm working on another work around: a transparent css layer overlaying pdf.js to handle various swipe functionality. The overlay portion works now, but I don't know what functions to call.
if(swipe=='left') ????
What function would I call in order to advance to the next page or backup to the previous page or zoom?

save your time & life, edit your .html file like this

// delete the 'maximum-scale'
<meta name="viewport" content="width=device-width, initial-scale=1">

eg. https://github.com/mozilla/pdf.js/blob/master/web/viewer.html#L26

Was this page helpful?
0 / 5 - 0 ratings