preserve current zoom level after switch to another page

103 views
Skip to first unread message

Andrew Borzilo

unread,
Oct 30, 2017, 3:59:03 PM10/30/17
to pdfnet-w...@googlegroups.com
Hello.

For my current task I need to change current page in mobile viewer using script, and keep viewer zoom level unchanged.
I've tried to achieve this by calling:

var zoomLevel = readerControl.getZoomLevel();
webViewer
.setCurrentPageNumber(newPage);
readerControl
.setZoomLevel(zoomLevel);

but this approach is unstable, if you call it often, I think because of asynchronous processes under the hood, and sometimes reset zoom level to the default fit screen.
Also visually this solution is ugly, coz after switch the page is displayed in fit screen mode and only then scaling up to correct zoom level.
I would like to avoid this transition.

Do you have any suggestions?

Thanks.

Danny Mendel

unread,
Nov 2, 2017, 8:57:48 AM11/2/17
to PDFTron WebViewer
Please,
we are looking few days for your official answer.

without your assistance we can not longer proceed with development.

Many thanks in advance,
Danny


On Monday, October 30, 2017 at 9:59:03 PM UTC+2, Andrew Borzilo wrote:
Hello.

For my current task I need to change current page in mobile viewer using script, and keep viewer zoom level unchanged.
I've tried to achieve this by calling:

var zoomLevel = readerControl.getZoomLevel();
webViewer
.setCurrentPageNumber(newPage);
readerControl
.setZoomLevel(zoomLevel);

but this approach is unstable, if you call it often, I think because of asynchronous processes under the hood, and sometimes reset zoom level to the default fit page.
Also visually this solution is ugly, coz after change the page it first display it in fit page scale and only after that scale it up to the previous zoom level.

Justin Jung

unread,
Nov 3, 2017, 4:07:44 PM11/3/17
to PDFTron WebViewer on behalf of Danny Mendel
Hello,

Unfortunately, this is currently difficult due to some assumptions that MobileReaderControl makes.
We are working on updating the mobile viewer as a whole to make the behaviour more consistent.
For now, we came up with a solution that isn't ideal, but is consistent in our testing.
Upon switching pages, it will first show up as "fit page" but right after it will zoom in to the desired zoom level.
In your code, you want to call setPagePreserveZoom with the page number you want to switch to.

var isRendering = false;
var waitingZoomLevel = null;

function setPagePreserveZoom(pageNumber) {
  var zoomLevel = readerControl.getZoomLevel();

  var newPageWrapper = readerControl.pageToWrapper(pageNumber - 1);
  readerControl.setCurrentPageNumber(pageNumber);

  readerControl.docViewer.on('pageComplete.zoom', function(e, pageIndex) {
    var pageWrapper = readerControl.pageToWrapper(pageIndex);
    if (pageWrapper === newPageWrapper && readerControl.pagesRendering.length === 0) {

      waitingZoomLevel = zoomLevel;
      if (!isRendering) {
        zoomPage();
      }
    }
  });
}

function zoomPage() {
  readerControl.docViewer.off('pageComplete.zoom');
  zoomToPoint(waitingZoomLevel, {x: 0, y: 0});
  waitingZoomLevel = null;
}

$(document).on('viewerLoaded', function() {
  readerControl.docViewer.on('beginRendering', function() {
    isRendering = true;
  });

  readerControl.docViewer.on('finishedRendering', function() {
    isRendering = false;
    if (waitingZoomLevel) {
      zoomPage();
    }
  });
});

function zoomToPoint(zoomLevel, touchLocation) {
  readerControl.newScale = 1;
  readerControl.oldScale = 1;

  var originalPageZoom = readerControl.docViewer.getPageZoom(readerControl.currentPageIndex);
  var newPageZoom = zoomLevel;

  var offset = readerControl.c.$e.offset();
  var width = readerControl.c.$e.width();
  var height = readerControl.c.$e.height();

  // calculate the location of the touch event on the page where (0,0) is at the center of the page
  var touchLocX = (touchLocation.x - offset.left) - width / 2;
  var touchLocY = (touchLocation.y - offset.top) - height / 2;
  // get the coordinates of the event for the new scaled page
  var scaledLocX = touchLocX * (newPageZoom / originalPageZoom);
  var scaledLocY = touchLocY * (newPageZoom / originalPageZoom);
  // calculate the amount that the zoomed page needs to be shifted so that the same part of the page is
  // under the touch location after it has been zoomed
  var offsetX = touchLocX - scaledLocX;
  var offsetY = touchLocY - scaledLocY;

  readerControl.c.tX += offsetX;
  readerControl.c.tY += offsetY;

  var animate = true;
  readerControl.setZoomLevel(newPageZoom, animate);
}

Justin Jung
Software Developer
PDFTron Systems Inc.

Andrew Borzilo

unread,
Nov 6, 2017, 11:40:05 AM11/6/17
to PDFTron WebViewer
Hello Justin.

Thanks for responce.

Unfortunately your solution has same issues like mine. If to call this setPagePreserveZoom often at some moment it reset zoom level to default.
I've tried to use both pageComplete and finishedRendering events to delay next page switching, but it still unstable.
Also I'm using setOffset, suggested by you here: https://groups.google.com/d/msg/pdfnet-webviewer/V6eXEaPxh9A/2sf2A6QoBAAJ
And it also has issues, sometimes it just didn't move page position at all.
Perhaps both issues has same reason coz if to call it from console, it work fine always.
How I can check is it safe to do next action (switch page, set offset, change zoom etc)
Perhaps there are some other events I could subscribe or some internal flags I could check?

Thanks for your help.

Matt Parizeau

unread,
Nov 6, 2017, 7:46:46 PM11/6/17
to PDFTron WebViewer
Can you use the isRendering flag in the above code to check when it's safe? We made a couple small modifications so that we set it just before calling setPagePreserveZoom and also as part of zoomPage and it seems to be pretty consistent. Here's the full code:

$('#myButton').on('click', function() {
  if (!isRendering) {
    isRendering = true;
    setPagePreserveZoom(newPageNumber);
  }
});

var isRendering = false;
var waitingZoomLevel = null;

function setPagePreserveZoom(pageNumber) {
  var zoomLevel = readerControl.getZoomLevel();

  var newPageWrapper = readerControl.pageToWrapper(pageNumber - 1);
  readerControl.setCurrentPageNumber(pageNumber);

  readerControl.docViewer.on('pageComplete.zoom', function(e, pageIndex) {
    var pageWrapper = readerControl.pageToWrapper(pageIndex);
    if (pageWrapper === newPageWrapper && readerControl.pagesRendering.length === 0) {

      waitingZoomLevel = zoomLevel;
      if (!isRendering) {
        zoomPage();
      }
    }
  });
}

function zoomPage() {
  isRendering = true;
Matt Parizeau
Software Developer
PDFTron Systems Inc.

Andrew Borzilo

unread,
Nov 7, 2017, 12:43:20 PM11/7/17
to PDFTron WebViewer
Hello Matt.

I solved this problem ... at last.
I've tried to use this approach but unfortunatelly it wasn't enough.
After all I had to add some throttling of each action like setPageNumber setPagePosition.
So currently I come into solution with updateState function, which is called when something need to be changed.
It's called instantly only if isRenedering is false, else it will be called in next finishedRendering event.
This function is checking global state object and applying just one paramether per call.
If state.page is different from current page, than it's setting new page and waiting for finishedRendering event to be called again.
If state.page is same as current page, it's checking page position and if it's different from current - than set it and waiting for finishedRendering event to be called again and so on.
Also each call throttled by 300ms, otherwise it start resseting zoom level to fit screen again, when I'm switching pages too quick.
To preserve zoomLevel I'm using this technique:

      var zoom = this.readerControl.getZoomLevel();
     
this.readerControl.setCurrentPage(this.state.page - 1, true);
     
this.readerControl.setZoomLevel(zoom);
     
this.readerControl.forEachPageInWrapper(this.state.page - 1, pageIndex => {
       
this.readerControl.docViewer.setPageZoom(pageIndex, zoom);
     
});


It's working pretty good, it still displaying some artifacts for split second on page switch, but nothing critical.

Matt Parizeau

unread,
Nov 8, 2017, 7:08:52 PM11/8/17
to PDFTron WebViewer
Glad to hear you were able to get it working! We hope to improve this for the mobile viewer in future versions so that the behavior is more consistent.

Matt Parizeau
Software Developer
PDFTron Systems Inc.
Reply all
Reply to author
Forward
0 new messages