Skip to content

Commit 60e74c7

Browse files
committed
improve zoom gesture
* simplify implementation by using scale factor * scroll during zooming to keep zoom focus at the same place instead of top-left corner
1 parent 8a33a9d commit 60e74c7

File tree

3 files changed

+36
-46
lines changed

3 files changed

+36
-46
lines changed

app/src/main/java/app/grapheneos/pdfviewer/GestureHelper.java

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
class GestureHelper {
1515
public interface GestureListener {
1616
boolean onTapUp();
17-
// Can be replaced with ratio when supported
18-
void onZoomIn(float value);
19-
void onZoomOut(float value);
17+
void onZoom(float scaleFactor, float focusX, float focusY);
2018
void onZoomEnd();
2119
}
2220

@@ -33,29 +31,10 @@ public boolean onSingleTapUp(MotionEvent motionEvent) {
3331

3432
final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context,
3533
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
36-
final float SPAN_RATIO = 600;
37-
float initialSpan;
38-
float prevNbStep;
39-
40-
@Override
41-
public boolean onScaleBegin(ScaleGestureDetector detector) {
42-
initialSpan = detector.getCurrentSpan();
43-
prevNbStep = 0;
44-
return true;
45-
}
46-
4734
@Override
4835
public boolean onScale(ScaleGestureDetector detector) {
49-
float spanDiff = initialSpan - detector.getCurrentSpan();
50-
float curNbStep = spanDiff / SPAN_RATIO;
51-
52-
float stepDiff = curNbStep - prevNbStep;
53-
if (stepDiff > 0) {
54-
listener.onZoomOut(stepDiff);
55-
} else {
56-
listener.onZoomIn(Math.abs(stepDiff));
57-
}
58-
prevNbStep = curNbStep;
36+
listener.onZoom(detector.getScaleFactor(), detector.getFocusX(),
37+
detector.getFocusY());
5938

6039
return true;
6140
}

app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
120120
public int mPage;
121121
public int mNumPages;
122122
private float mZoomRatio = 1f;
123+
private float mZoomFocusX = 0f;
124+
private float mZoomFocusY = 0f;
123125
private int mDocumentOrientationDegrees;
124126
private int mDocumentState;
125127
private String mEncryptedDocumentPassword;
@@ -177,6 +179,16 @@ public void setZoomRatio(final float ratio) {
177179
mZoomRatio = Math.max(Math.min(ratio, MAX_ZOOM_RATIO), MIN_ZOOM_RATIO);
178180
}
179181

182+
@JavascriptInterface
183+
public float getZoomFocusX() {
184+
return mZoomFocusX;
185+
}
186+
187+
@JavascriptInterface
188+
public float getZoomFocusY() {
189+
return mZoomFocusY;
190+
}
191+
180192
@JavascriptInterface
181193
public float getMinZoomRatio() {
182194
return MIN_ZOOM_RATIO;
@@ -363,13 +375,8 @@ public boolean onTapUp() {
363375
}
364376

365377
@Override
366-
public void onZoomIn(float value) {
367-
zoomIn(value, false);
368-
}
369-
370-
@Override
371-
public void onZoomOut(float value) {
372-
zoomOut(value, false);
378+
public void onZoom(float scaleFactor, float focusX, float focusY) {
379+
zoom(scaleFactor, focusX, focusY, false);
373380
}
374381

375382
@Override
@@ -559,20 +566,12 @@ private void shareDocument() {
559566
}
560567
}
561568

562-
private void zoomIn(float value, boolean end) {
563-
if (mZoomRatio < MAX_ZOOM_RATIO) {
564-
mZoomRatio = Math.min(mZoomRatio + value, MAX_ZOOM_RATIO);
565-
renderPage(end ? 1 : 2);
566-
invalidateOptionsMenu();
567-
}
568-
}
569-
570-
private void zoomOut(float value, boolean end) {
571-
if (mZoomRatio > MIN_ZOOM_RATIO) {
572-
mZoomRatio = Math.max(mZoomRatio - value, MIN_ZOOM_RATIO);
573-
renderPage(end ? 1 : 2);
574-
invalidateOptionsMenu();
575-
}
569+
private void zoom(float scaleFactor, float focusX, float focusY, boolean end) {
570+
mZoomRatio = Math.min(Math.max(mZoomRatio * scaleFactor, MIN_ZOOM_RATIO), MAX_ZOOM_RATIO);
571+
mZoomFocusX = focusX;
572+
mZoomFocusY = focusY;
573+
renderPage(end ? 1 : 2);
574+
invalidateOptionsMenu();
576575
}
577576

578577
private void zoomEnd() {

viewer/js/index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger=0) {
131131

132132
const viewport = page.getViewport({scale: newZoomRatio, rotation: orientationDegrees});
133133

134+
const scaleFactor = newZoomRatio / zoomRatio;
135+
const ratio = globalThis.devicePixelRatio;
136+
134137
if (useRender) {
135138
if (newZoomRatio !== zoomRatio) {
136139
canvas.style.height = viewport.height + "px";
@@ -142,11 +145,20 @@ function renderPage(pageNumber, zoom, prerender, prerenderTrigger=0) {
142145
if (zoom === 2) {
143146
textLayerDiv.hidden = true;
144147
pageRendering = false;
148+
149+
// zoom focus relative to page origin, rather than screen origin
150+
const globalFocusX = channel.getZoomFocusX() / ratio + globalThis.scrollX;
151+
const globalFocusY = channel.getZoomFocusY() / ratio + globalThis.scrollY;
152+
153+
const translationFactor = scaleFactor - 1;
154+
const scrollX = globalFocusX * translationFactor;
155+
const scrollY = globalFocusY * translationFactor;
156+
scrollBy(scrollX, scrollY);
157+
145158
return;
146159
}
147160

148161
const newCanvas = document.createElement("canvas");
149-
const ratio = globalThis.devicePixelRatio;
150162
newCanvas.height = viewport.height * ratio;
151163
newCanvas.width = viewport.width * ratio;
152164
newCanvas.style.height = viewport.height + "px";

0 commit comments

Comments
 (0)