aboutsummaryrefslogtreecommitdiff
path: root/viewer/src
diff options
context:
space:
mode:
authorpacien2020-04-26 21:51:37 +0200
committerpacien2020-04-26 21:55:10 +0200
commit29d432e64e0482935ef91dbfed37d4d4cf26c42f (patch)
treea9ffc21c3b8385f405bcf6638abd3b017b0d0d63 /viewer/src
parentf8a1763c3bee0e236c86ba9f6b46aceb212dea10 (diff)
downloadldgallery-29d432e64e0482935ef91dbfed37d4d4cf26c42f.tar.gz
viewer/LdZoom: add support for pinch-to-zoom
GitHub: closes #106
Diffstat (limited to 'viewer/src')
-rw-r--r--viewer/src/services/ldzoom.ts46
-rw-r--r--viewer/src/views/MainLayout.vue1
2 files changed, 33 insertions, 14 deletions
diff --git a/viewer/src/services/ldzoom.ts b/viewer/src/services/ldzoom.ts
index 61b5dc6..27debb5 100644
--- a/viewer/src/services/ldzoom.ts
+++ b/viewer/src/services/ldzoom.ts
@@ -19,25 +19,26 @@
19 19
20// polyfill still required for IE and Safari, see https://caniuse.com/#feat=resizeobserver 20// polyfill still required for IE and Safari, see https://caniuse.com/#feat=resizeobserver
21import ResizeObserver from 'resize-observer-polyfill'; 21import ResizeObserver from 'resize-observer-polyfill';
22import "hammerjs";
22 23
23/** 24/**
24 * Mousewheel picture zoom helper. 25 * Mousewheel and pinch zoom handler.
25 */ 26 */
26export default class LdZoom { 27export default class LdZoom {
27 readonly containerElement: HTMLDivElement; 28 readonly containerElement: HTMLDivElement;
28 readonly imageElement: HTMLImageElement; 29 readonly imageElement: HTMLImageElement;
29 readonly maxScaleFactor: number; 30 readonly maxScaleFactor: number;
30 readonly zoomSpeed: number; 31 readonly scrollZoomSpeed: number;
31 scaleFactor: number = 0.0; 32 scaleFactor: number = 0.0;
32 33
33 constructor( 34 constructor(
34 containerElement: HTMLDivElement, imageElement: HTMLImageElement, 35 containerElement: HTMLDivElement, imageElement: HTMLImageElement,
35 maxScaleFactor: number, zoomSpeed: number 36 maxScaleFactor: number, scrollZoomSpeed: number
36 ) { 37 ) {
37 this.containerElement = containerElement; 38 this.containerElement = containerElement;
38 this.imageElement = imageElement; 39 this.imageElement = imageElement;
39 this.maxScaleFactor = maxScaleFactor; 40 this.maxScaleFactor = maxScaleFactor;
40 this.zoomSpeed = zoomSpeed; 41 this.scrollZoomSpeed = scrollZoomSpeed;
41 } 42 }
42 43
43 /** 44 /**
@@ -52,10 +53,30 @@ export default class LdZoom {
52 53
53 this.containerElement.addEventListener('wheel', wheelEvent => { 54 this.containerElement.addEventListener('wheel', wheelEvent => {
54 wheelEvent.preventDefault(); 55 wheelEvent.preventDefault();
55 this.zoom(wheelEvent); 56 const zoomDelta = -Math.sign(wheelEvent.deltaY) * this.scrollZoomSpeed;
57 this.zoom(wheelEvent.offsetX, wheelEvent.offsetY, zoomDelta);
56 }); 58 });
57 59
58 // TODO: handle pinch-to-zoom. 60 const pinchListener = new Hammer(this.containerElement);
61 pinchListener.get('pinch').set({enable: true});
62 this.installPinchHandler(pinchListener);
63 }
64
65 private installPinchHandler(pinchListener: HammerManager) {
66 let lastScaleFactor = 0.0;
67
68 pinchListener.on('pinchstart', (pinchEvent: HammerInput) => {
69 lastScaleFactor = pinchEvent.scale;
70 });
71
72 pinchListener.on('pinchmove', (pinchEvent: HammerInput) => {
73 // FIXME: pinchEvent.center isn't always well-centered
74 const focusX = pinchEvent.center.x + this.containerElement.scrollLeft;
75 const focusY = pinchEvent.center.y + this.containerElement.scrollTop;
76 const zoomDelta = pinchEvent.scale - lastScaleFactor;
77 lastScaleFactor = pinchEvent.scale;
78 this.zoom(focusX, focusY, zoomDelta);
79 });
59 } 80 }
60 81
61 /** 82 /**
@@ -69,15 +90,12 @@ export default class LdZoom {
69 this.imageElement.style.marginTop = `${marginTop}px`; 90 this.imageElement.style.marginTop = `${marginTop}px`;
70 } 91 }
71 92
72 private zoom(wheelEvent: WheelEvent) { 93 private zoom(focusX: number, focusY: number, zoomDelta: number) {
73 const ratioX = wheelEvent.offsetX / this.imageElement.clientWidth; 94 const ratioX = focusX / this.imageElement.clientWidth;
74 const ratioY = wheelEvent.offsetY / this.imageElement.clientHeight; 95 const ratioY = focusY / this.imageElement.clientHeight;
75
76 const zoomDelta = -Math.sign(wheelEvent.deltaY) * this.zoomSpeed;
77 this.setImageScale(Math.min(this.scaleFactor + zoomDelta, this.maxScaleFactor)); 96 this.setImageScale(Math.min(this.scaleFactor + zoomDelta, this.maxScaleFactor));
78 97 this.containerElement.scrollLeft -= focusX - ratioX * this.imageElement.clientWidth;
79 this.containerElement.scrollLeft -= wheelEvent.offsetX - ratioX * this.imageElement.clientWidth; 98 this.containerElement.scrollTop -= focusY - ratioY * this.imageElement.clientHeight;
80 this.containerElement.scrollTop -= wheelEvent.offsetY - ratioY * this.imageElement.clientHeight;
81 } 99 }
82 100
83 private setImageScale(newScaleFactor: number) { 101 private setImageScale(newScaleFactor: number) {
diff --git a/viewer/src/views/MainLayout.vue b/viewer/src/views/MainLayout.vue
index 6e707e6..c09e99a 100644
--- a/viewer/src/views/MainLayout.vue
+++ b/viewer/src/views/MainLayout.vue
@@ -87,6 +87,7 @@ body,
87html { 87html {
88 height: 100%; 88 height: 100%;
89 overflow: hidden; 89 overflow: hidden;
90 touch-action: none;
90 background-color: $content-bgcolor; 91 background-color: $content-bgcolor;
91 --layout-top: #{$layout-top}; 92 --layout-top: #{$layout-top};
92 --layout-left: #{$layout-left}; 93 --layout-left: #{$layout-left};