From b4b698ccbdec98dd902b6290f12207bf5547b140 Mon Sep 17 00:00:00 2001 From: pacien Date: Tue, 28 Apr 2020 01:51:08 +0200 Subject: viewer/LdPicture: fix centering in loading phase --- viewer/src/services/ldzoom.ts | 60 +++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 19 deletions(-) (limited to 'viewer/src/services') diff --git a/viewer/src/services/ldzoom.ts b/viewer/src/services/ldzoom.ts index 50f006e..c28c2c8 100644 --- a/viewer/src/services/ldzoom.ts +++ b/viewer/src/services/ldzoom.ts @@ -27,28 +27,31 @@ import "hammerjs"; export default class LdZoom { readonly containerElement: HTMLDivElement; readonly imageElement: HTMLImageElement; + readonly pictureProperties: Gallery.PictureProperties; readonly maxScaleFactor: number; readonly scrollZoomSpeed: number; scaleFactor: number = 0.0; constructor( containerElement: HTMLDivElement, imageElement: HTMLImageElement, + pictureProperties: Gallery.PictureProperties, maxScaleFactor: number, scrollZoomSpeed: number ) { this.containerElement = containerElement; this.imageElement = imageElement; + this.pictureProperties = pictureProperties; this.maxScaleFactor = maxScaleFactor; this.scrollZoomSpeed = scrollZoomSpeed; } /** * Register event listeners. - * The dimension of the image should be known before calling this method. */ public install() { + this.updateImageScale(this.scaleFactor); + new ResizeObserver(() => { - this.setImageScale(this.scaleFactor); - this.recenterImageElement(); + this.updateImageScale(this.scaleFactor); }).observe(this.containerElement); this.containerElement.addEventListener('wheel', wheelEvent => { @@ -60,8 +63,6 @@ export default class LdZoom { const pinchListener = new Hammer(this.containerElement); pinchListener.get('pinch').set({enable: true}); this.installPinchHandler(pinchListener); - - this.setImageScale(this.scaleFactor); } private installPinchHandler(pinchListener: HammerManager) { @@ -72,7 +73,6 @@ export default class LdZoom { }); pinchListener.on('pinchmove', (pinchEvent: HammerInput) => { - // FIXME: v-dragscroll interferes with our focus point scroll adjustment const focusX = pinchEvent.center.x + this.containerElement.scrollLeft; const focusY = pinchEvent.center.y + this.containerElement.scrollTop; const scaleFactor = pinchEvent.scale * startScaleFactor; @@ -80,33 +80,55 @@ export default class LdZoom { }); } + /** + * Returns the picture resolution as it should be displayed. + */ + private getDisplayResolution(): Gallery.Resolution { + return { + width: this.pictureProperties.resolution.width * this.scaleFactor, + height: this.pictureProperties.resolution.height * this.scaleFactor, + }; + } + + /** + * Applies scaling to the DOM image element. + * To call after internal intermediate computations because DOM properties aren't stable. + */ + private resizeImageElement() { + const imageDim = this.getDisplayResolution(); + this.imageElement.width = imageDim.width; + this.imageElement.height = imageDim.height; + } + /** * Centers the image element inside its container if it fits, or stick to the top and left borders otherwise. * It's depressingly hard to do in pure CSS… */ private recenterImageElement() { - const marginLeft = Math.max((this.containerElement.clientWidth - this.imageElement.clientWidth) / 2, 0); - const marginTop = Math.max((this.containerElement.clientHeight - this.imageElement.clientHeight) / 2, 0); + const imageDim = this.getDisplayResolution(); + const marginLeft = Math.max((this.containerElement.clientWidth - imageDim.width) / 2, 0); + const marginTop = Math.max((this.containerElement.clientHeight - imageDim.height) / 2, 0); this.imageElement.style.marginLeft = `${marginLeft}px`; this.imageElement.style.marginTop = `${marginTop}px`; } private zoom(focusX: number, focusY: number, scaleFactor: number) { - const ratioX = focusX / this.imageElement.clientWidth; - const ratioY = focusY / this.imageElement.clientHeight; - this.setImageScale(Math.min(scaleFactor, this.maxScaleFactor)); - this.containerElement.scrollLeft -= focusX - ratioX * this.imageElement.clientWidth; - this.containerElement.scrollTop -= focusY - ratioY * this.imageElement.clientHeight; + const imageDim = this.getDisplayResolution(); + const ratioX = focusX / imageDim.width; + const ratioY = focusY / imageDim.height; + this.updateImageScale(Math.min(scaleFactor, this.maxScaleFactor)); + + const newImageDim = this.getDisplayResolution(); + this.containerElement.scrollLeft -= focusX - ratioX * newImageDim.width; + this.containerElement.scrollTop -= focusY - ratioY * newImageDim.height; } - private setImageScale(newScaleFactor: number) { - const horizontalFillRatio = this.containerElement.clientWidth / this.imageElement.naturalWidth; - const verticalFillRatio = this.containerElement.clientHeight / this.imageElement.naturalHeight; + private updateImageScale(newScaleFactor: number) { + const horizontalFillRatio = this.containerElement.clientWidth / this.pictureProperties.resolution.width; + const verticalFillRatio = this.containerElement.clientHeight / this.pictureProperties.resolution.height; const minScaleFactor = Math.min(horizontalFillRatio, verticalFillRatio, 1.0); this.scaleFactor = Math.max(newScaleFactor, minScaleFactor); - - this.imageElement.width = this.scaleFactor * this.imageElement.naturalWidth; - this.imageElement.height = this.scaleFactor * this.imageElement.naturalHeight; + this.resizeImageElement(); this.recenterImageElement(); } } -- cgit v1.2.3