From f38127a4ad9f9867a115cd50caa30a4a1c6645de Mon Sep 17 00:00:00 2001 From: Adrien Burgun Date: Sun, 2 Apr 2023 15:59:04 +0200 Subject: [PATCH] :sparkles: Create a class for PannableState, add inverse transformation --- src/index.js | 71 ++++++++++++++++++++++++++-------------- src/solid/usePannable.ts | 13 ++++---- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/index.js b/src/index.js index 837b000..1fe9614 100644 --- a/src/index.js +++ b/src/index.js @@ -313,17 +313,6 @@ export function attachTouch(element, options = {}) { } } -/** - * @typedef {object} PannableState - * An immutable object returned by `Pannable::getState()` - * @prop {number} dx - * @prop {number} dy - * @prop {number} scale - * @prop {number} logScale - * @prop {(x: number, y: number) => [x: number, y: number]} get - * Returns the transformed coordinates - **/ - /** * @typedef {object} PannableOptions * @prop {number=} downscale @@ -391,19 +380,8 @@ export class Pannable { } /** @returns {PannableState} **/ - getState() { - const scale = this.scale; - const dx = this.dx; - const dy = this.dy; - return { - dx, - dy, - logScale: this.logScale, - scale, - get: (x, y) => { - return [x * scale + dx, y * scale + dy]; - } - }; + getState(cx = 0, cy = 0) { + return new PannableState(this.dx + cx, this.dy + cy, this.logScale); } /** @@ -448,6 +426,51 @@ export class Pannable { } } +/** + * An immutable view of `Pannable`, returned by `Pannable::getState`. + **/ +export class PannableState { + /** + * @param {number} dx + * @param {number} dy + * @param {number} logScale + **/ + constructor(dx, dy, logScale) { + /** @readonly The X offset to move coordinates by *after* multiplying them by `scale` **/ + this.dx = dx; + /** @readonly The Y offset to move coordinates by *after* multiplying them by `scale` **/ + this.dy = dy; + /** @readonly The base-2 logarithm of `scale`, used internally for precision purposes **/ + this.logScale = logScale; + /** @readonly The zoom strength **/ + this.scale = Math.pow(2, logScale); + } + + /** + * Transforms the input coordinates from the "pannable" coordinates + * to the "real" coordinates (what you will display on screen) + * + * @param {number} x The X "pannable" coordinate + * @param {number} y The Y "pannable" coordinate + * @returns {[x: number, y: number]} + **/ + get(x, y) { + return [x * this.scale + this.dx, y * this.scale + this.dy]; + } + + /** + * Transforms the input coordinates from the "real" coordinates (where they are on screen) + * to the "pannable" coordinates; this is the inverse operation of the `PannableState::get` method. + * + * @param {number} x The X "real" coordinate + * @param {number} y The Y "real" coordinate + * @returns {[x: number, y: number]} + **/ + inverse(x, y) { + return [(x - this.dx) / this.scale, (y - this.dy) / this.scale]; + } +} + /** * @typedef {PannableOptions & { * onUpdate?: (state: PannableState) => void, diff --git a/src/solid/usePannable.ts b/src/solid/usePannable.ts index a675d8f..ea84e41 100644 --- a/src/solid/usePannable.ts +++ b/src/solid/usePannable.ts @@ -28,13 +28,14 @@ export function usePannable(config: PannableOptions & UsePannableOptions) { return newState; }, getState: () => { - const result = state(); + const preTransformed = state(); const [cx, cy] = center(); - return { - ...result, - dx: result.dx + cx, - dy: result.dy + cy, - }; + + return new PannableState( + preTransformed.dx + cx, + preTransformed.dy + cy, + preTransformed.logScale + ); } }; }