From 5bbc6002cb09a65ce02c2406a4b5541ebf7c7844 Mon Sep 17 00:00:00 2001 From: marlon-erler Date: Sun, 6 Sep 2026 01:50:56 +0200 Subject: [PATCH] make kanban zoom smoother --- bun.lockb | Bin 13647 -> 14022 bytes node_modules/@types/hammerjs/LICENSE | 21 ++ node_modules/@types/hammerjs/README.md | 15 + node_modules/@types/hammerjs/index.d.ts | 345 ++++++++++++++++++ node_modules/@types/hammerjs/package.json | 25 ++ package.json | 1 + src/.index.tsx.swp | Bin 0 -> 12288 bytes src/Model/Utility/utility.ts | 139 +++---- src/ViewModel/Global/.coreViewModel.ts.swp | Bin 16384 -> 16384 bytes .../Global/.fileTransferViewModel.ts.swp | Bin 24576 -> 0 bytes src/ViewModel/Global/coreViewModel.ts | 2 +- src/index.tsx | 1 - 12 files changed, 482 insertions(+), 67 deletions(-) create mode 100644 node_modules/@types/hammerjs/LICENSE create mode 100644 node_modules/@types/hammerjs/README.md create mode 100644 node_modules/@types/hammerjs/index.d.ts create mode 100644 node_modules/@types/hammerjs/package.json create mode 100644 src/.index.tsx.swp delete mode 100644 src/ViewModel/Global/.fileTransferViewModel.ts.swp diff --git a/bun.lockb b/bun.lockb index 359d98271468c3a917ebdff33dc43fc318d3232e..143adbbbf74df313c16cdc906d528042bd971c3e 100755 GIT binary patch delta 2128 zcmcgtdrX^E6u-BnrL^NwhQLP)ZD~te9(_ucrru6+NkvEo`qRki$m5(xIq&4$%Q=Mn5XRLa zry=_|n>fca9!B97jRjoc`~&An&IgfKVqApt4$jYTZbeQ-UF2NK+0NO>nJqgREihUiYJrMj7!Q_nX)uD=N*s&3i_b1ISUg;i>iUV;}9=in4#6&T}0 zx<|sFCA338Bhr3`nqzT<)WcbIE!9AiR-}y*zAoV}5<1~3j`vCUxrFy6tOKfJ^D?}^ zP?Mn}WQ{b}MzAG_bWFl)5_+IU&t_pb0lW2Lf?iKZ02h-8HbWJy0Kp&%gE&@=W4QAV zG%qx%eKZQ~22qu7fR7Ao=vJ6B)DFjE7&F$Eawhr~X>?f`Z^tr!2(JdQvX5Z1O1PBq z`)sRnxgaxh|CgPKt$$g!SX$bD9VOctk5!VFZb@u_jX$t6(MOY}_0^}h^lu(NJauTo zb@BR&=_A^KhI2i)x3y)@?rS!>n>8Ju?bq!(zOFdy4`Fr9+L@N2<^$i|_-Xsmzus>- zS3mWkz5*JBOh^drAmmox9T*CHRR%noLMfFy-&WocrkLcM$xB%x&^E!CU>JF4UY(~L--wMxUk^m zu8tI1St1=0A^CWK*sAm46?Z+%xc#mi3})5&rSj4<^tq&k0UnaWi@SdHP_04YuZ s)_Uym-R*sSU7LHNPkB1^us0Z=#Rmp`MLxM(6uU0)O`#=vA~-_-1u3F!8UO$Q delta 1859 zcmcgtZERCj7(S=#N_W=|TISZ!h@VkOj7BpTg9-YayK{5(hd<{@-{-mS zdEa~PIX&ln&L{m>`-Y?8>-l##&Ca(UTN6r7_ATu?^m}*RHvVP!y@OwEotqz?yLLLk zw07sdjn%nG?SfRt0l{y)bM=`f7UQX4yzbj;5mWCRx4u} zZInkTUXtY_8h)msn;uuhC;|`DK_y%AX9;6*tiw+6(nh|D!lhZ>MU$mj)2u=!TZRXz z*|s)k!E%L(_D^=fU#ayjDtBm~Sj-P``p{OH!!ctuaydE+_kUVGPBz+NF7v;}$8l%X zj6SkC?f?1@3KM1L6}qfG!o8%rHoq%JYNldF#=EdAe`c`SN&eH2Bgi_i}Tp8IXAasH$cNz?s7wMrMQ)VfP2 z#zu}kZ^YZ^nV`zI(_Uohk~d@?@7e0Occ+oHpH2tWq%M(DOCEbO^JD)xBd&|6>(;G! z>%~;J5t$)-NKNXZJNx3cO#Hz0vqoIgWo&Z98LH=dza29oHrf(Wt8^Ww`+lnJd;RSp zBc7l)FtV=uhpJ*9e|ocXvk}*ChSr9ex)mPB5hF4{H!!k(lYEfrZGW~g_>K`DB}Z80 z$EglDO%I3H`z~NV@yn0;^Q-D!>h4&^8xql2G{)HHp@q$Jh3Q1N1*dN$5_4ZguDHzh eq?4EU&a&H0;f16l32KQn7Y;|-ltM#ti2n`ezb{At diff --git a/node_modules/@types/hammerjs/LICENSE b/node_modules/@types/hammerjs/LICENSE new file mode 100644 index 00000000..9e841e7a --- /dev/null +++ b/node_modules/@types/hammerjs/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/node_modules/@types/hammerjs/README.md b/node_modules/@types/hammerjs/README.md new file mode 100644 index 00000000..0d5db159 --- /dev/null +++ b/node_modules/@types/hammerjs/README.md @@ -0,0 +1,15 @@ +# Installation +> `npm install --save @types/hammerjs` + +# Summary +This package contains type definitions for hammerjs (http://hammerjs.github.io/). + +# Details +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hammerjs. + +### Additional Details + * Last updated: Mon, 07 Oct 2024 22:07:58 GMT + * Dependencies: none + +# Credits +These definitions were written by [Han Lin Yap](https://github.com/codler). diff --git a/node_modules/@types/hammerjs/index.d.ts b/node_modules/@types/hammerjs/index.d.ts new file mode 100644 index 00000000..83372314 --- /dev/null +++ b/node_modules/@types/hammerjs/index.d.ts @@ -0,0 +1,345 @@ +declare var Hammer: HammerStatic; + +declare module "hammerjs" { + export = Hammer; +} + +interface HammerStatic { + new(element: HTMLElement | SVGElement, options?: HammerOptions): HammerManager; + + defaults: HammerDefaults; + + VERSION: number; + + INPUT_START: 1; + INPUT_MOVE: 2; + INPUT_END: 4; + INPUT_CANCEL: 8; + + STATE_POSSIBLE: 1; + STATE_BEGAN: 2; + STATE_CHANGED: 4; + STATE_ENDED: 8; + STATE_RECOGNIZED: 8; // same as STATE_ENDED + STATE_CANCELLED: 16; + STATE_FAILED: 32; + + DIRECTION_NONE: 1; + DIRECTION_LEFT: 2; + DIRECTION_RIGHT: 4; + DIRECTION_UP: 8; + DIRECTION_DOWN: 16; + DIRECTION_HORIZONTAL: 6; // DIRECTION_LEFT | DIRECTION_RIGHT + DIRECTION_VERTICAL: 24; // DIRECTION_UP | DIRECTION_DOWN + DIRECTION_ALL: 30; // DIRECTION_HORIZONTAL | DIRECTION_VERTICAL + + Manager: HammerManagerConstructor; + Input: HammerInput; + TouchAction: TouchAction; + + TouchInput: TouchInput; + MouseInput: MouseInput; + PointerEventInput: PointerEventInput; + TouchMouseInput: TouchMouseInput; + SingleTouchInput: SingleTouchInput; + + Recognizer: RecognizerStatic; + AttrRecognizer: AttrRecognizerStatic; + Tap: TapRecognizerStatic; + Pan: PanRecognizerStatic; + Swipe: SwipeRecognizerStatic; + Pinch: PinchRecognizerStatic; + Rotate: RotateRecognizerStatic; + Press: PressRecognizerStatic; + + on(target: EventTarget, types: string, handler: Function): void; + off(target: EventTarget, types: string, handler: Function): void; + each(obj: any, iterator: Function, context: any): void; + merge(dest: any, src: any): any; + extend(dest: any, src: any, merge: boolean): any; + inherit(child: Function, base: Function, properties: any): any; + bindFn(fn: Function, context: any): Function; + prefixed(obj: any, property: string): string; +} + +type RecognizerTuple = + | [RecognizerStatic] + | [RecognizerStatic, RecognizerOptions] + | [RecognizerStatic, RecognizerOptions, string | string[]] + | [RecognizerStatic, RecognizerOptions, string | string[], (string | Recognizer) | Array]; + +interface HammerDefaults extends HammerOptions { + domEvents: boolean; + enable: boolean; + preset: RecognizerTuple[]; + touchAction: string; + cssProps: CssProps; + + inputClass: HammerInput; + inputTarget: EventTarget; +} + +interface CssProps { + contentZooming: string; + tapHighlightColor: string; + touchCallout: string; + touchSelect: string; + userDrag: string; + userSelect: string; +} + +interface HammerOptions { + cssProps?: CssProps | undefined; + domEvents?: boolean | undefined; + enable?: boolean | ((manager: HammerManager) => boolean) | undefined; + preset?: RecognizerTuple[] | undefined; + touchAction?: string | undefined; + recognizers?: RecognizerTuple[] | undefined; + + inputClass?: HammerInput | undefined; + inputTarget?: EventTarget | undefined; +} + +interface HammerManagerConstructor { + new(element: EventTarget, options?: HammerOptions): HammerManager; +} + +interface HammerListener { + (event: HammerInput): void; +} + +interface HammerManager { + add(recogniser: Recognizer): Recognizer; + add(recogniser: Recognizer): HammerManager; + add(recogniser: Recognizer[]): Recognizer; + add(recogniser: Recognizer[]): HammerManager; + destroy(): void; + emit(event: string, data: any): void; + get(recogniser: Recognizer): Recognizer; + get(recogniser: string): Recognizer; + off(events: string, handler?: HammerListener): void; + on(events: string, handler: HammerListener): void; + recognize(inputData: any): void; + remove(recogniser: Recognizer): HammerManager; + remove(recogniser: string): HammerManager; + set(options: HammerOptions): HammerManager; + stop(force: boolean): void; +} + +declare class HammerInput { + constructor(manager: HammerManager, callback: Function); + + destroy(): void; + handler(): void; + init(): void; + + /** Name of the event. Like panstart. */ + type: string; + + /** Movement of the X axis. */ + deltaX: number; + + /** Movement of the Y axis. */ + deltaY: number; + + /** Total time in ms since the first input. */ + deltaTime: number; + + /** Distance moved. */ + distance: number; + + /** Angle moved. */ + angle: number; + + /** Velocity on the X axis, in px/ms. */ + velocityX: number; + + /** Velocity on the Y axis, in px/ms */ + velocityY: number; + + /** Highest velocityX/Y value. */ + velocity: number; + + overallVelocity: number; + + overallVelocityX: number; + + overallVelocityY: number; + + /** Direction moved. Matches the DIRECTION constants. */ + direction: number; + + /** Direction moved from it's starting point. Matches the DIRECTION constants. */ + offsetDirection: number; + + /** Scaling that has been done when multi-touch. 1 on a single touch. */ + scale: number; + + /** Rotation that has been done when multi-touch. 0 on a single touch. */ + rotation: number; + + /** Center position for multi-touch, or just the single pointer. */ + center: HammerPoint; + + /** The amount of multi-taps being recognized. */ + tapCount?: number; + + /** Source event object, type TouchEvent, MouseEvent or PointerEvent. */ + srcEvent: TouchEvent | MouseEvent | PointerEvent; + + /** Target that received the event. */ + target: HTMLElement; + + /** Primary pointer type, could be touch, mouse, pen or kinect. */ + pointerType: string; + + /** Event type, matches the INPUT constants. */ + eventType: + | HammerStatic["INPUT_START"] + | HammerStatic["INPUT_MOVE"] + | HammerStatic["INPUT_END"] + | HammerStatic["INPUT_CANCEL"]; + + /** true when the first input. */ + isFirst: boolean; + + /** true when the final (last) input. */ + isFinal: boolean; + + /** Array with all pointers, including the ended pointers (touchend, mouseup). */ + pointers: any[]; + + /** Array with all new/moved/lost pointers. */ + changedPointers: any[]; + + /** Maximum number of pointers detected in the gesture */ + maxPointers: number; + + /** Timestamp of a gesture */ + timeStamp: number; + + /** Reference to the srcEvent.preventDefault() method. Only for experts! */ + preventDefault: Function; +} + +declare class MouseInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class PointerEventInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class SingleTouchInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class TouchInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +declare class TouchMouseInput extends HammerInput { + constructor(manager: HammerManager, callback: Function); +} + +interface RecognizerOptions { + direction?: number | undefined; + enable?: boolean | ((recognizer: Recognizer, inputData: HammerInput) => boolean) | undefined; + event?: string | undefined; + interval?: number | undefined; + pointers?: number | undefined; + posThreshold?: number | undefined; + taps?: number | undefined; + threshold?: number | undefined; + time?: number | undefined; + velocity?: number | undefined; +} + +interface RecognizerStatic { + new(options?: RecognizerOptions): Recognizer; +} + +interface Recognizer { + defaults: any; + + canEmit(): boolean; + canRecognizeWith(otherRecognizer: Recognizer): boolean; + dropRecognizeWith(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + dropRequireFailure(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + emit(input: HammerInput): void; + getTouchAction(): any[]; + hasRequireFailures(): boolean; + process(inputData: HammerInput): string; + recognize(inputData: HammerInput): void; + recognizeWith(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + requireFailure(otherRecognizer: Recognizer | Recognizer[] | string): Recognizer; + reset(): void; + set(options?: RecognizerOptions): Recognizer; + tryEmit(input: HammerInput): void; +} + +interface AttrRecognizerStatic { + attrTest(input: HammerInput): boolean; + process(input: HammerInput): any; +} + +interface AttrRecognizer extends Recognizer { + new(options?: RecognizerOptions): AttrRecognizer; +} + +interface PanRecognizerStatic { + new(options?: RecognizerOptions): PanRecognizer; +} + +interface PanRecognizer extends AttrRecognizer { +} + +interface PinchRecognizerStatic { + new(options?: RecognizerOptions): PinchRecognizer; +} + +interface PinchRecognizer extends AttrRecognizer { +} + +interface PressRecognizerStatic { + new(options?: RecognizerOptions): PressRecognizer; +} + +interface PressRecognizer extends AttrRecognizer { +} + +interface RotateRecognizerStatic { + new(options?: RecognizerOptions): RotateRecognizer; +} + +interface RotateRecognizer extends AttrRecognizer { +} + +interface SwipeRecognizerStatic { + new(options?: RecognizerOptions): SwipeRecognizer; +} + +interface SwipeRecognizer extends AttrRecognizer { +} + +interface TapRecognizerStatic { + new(options?: RecognizerOptions): TapRecognizer; +} + +interface TapRecognizer extends AttrRecognizer { +} + +declare class TouchAction { + constructor(manager: HammerManager, value: string); + + compute(): string; + preventDefaults(input: HammerInput): void; + preventSrc(srcEvent: any): void; + set(value: string): void; + update(): void; +} + +interface HammerPoint { + x: number; + y: number; +} diff --git a/node_modules/@types/hammerjs/package.json b/node_modules/@types/hammerjs/package.json new file mode 100644 index 00000000..5b9abafa --- /dev/null +++ b/node_modules/@types/hammerjs/package.json @@ -0,0 +1,25 @@ +{ + "name": "@types/hammerjs", + "version": "2.0.46", + "description": "TypeScript definitions for hammerjs", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/hammerjs", + "license": "MIT", + "contributors": [ + { + "name": "Han Lin Yap", + "githubUsername": "codler", + "url": "https://github.com/codler" + } + ], + "main": "", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/hammerjs" + }, + "scripts": {}, + "dependencies": {}, + "typesPublisherContentHash": "940610a83da8b99e3035028564e9536f6c44025e0387899fdaafa00474821be4", + "typeScriptVersion": "4.8" +} \ No newline at end of file diff --git a/package.json b/package.json index c2ae3f0b..feff6f07 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "@types/hammerjs": "^2.0.46", "@types/uuid": "^10.0.0", "bloatless-react": "1.3.14", "esbuild": "^0.23.1", diff --git a/src/.index.tsx.swp b/src/.index.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000..91f0b2a241e862e081933efc54a3c85190646766 GIT binary patch literal 12288 zcmeI2%ZnUE9LIl&@fEWw@t_2R-U-T#W~Z}>kjOrQ?qUpNA#tH}*)~1hYgf;1 z)?^hCeBkS#2OkRx;z{(9gPtOakBguuFM_%U528f!ANZ|)R98P{*MJ~_YWVDAs_OTv zUwwbSs;S*f=iuUrIpe|hLBex8(eEE^Jo(;TchdVdQO}J;>$Z;<*p{~x@a;xF1BWJ$ zg3#(Qb8&WV_JlbT^!wc8p>4Xp!_KuMes0_8^Z>1ZR^VzC7)0H%qa$?q(0IJn_cun3 zJN7PItrtCBE1(t73TOqi0$KsBfL1^&pcS}=6^NF1(6fktXS#-N`nsd^n!eR9S^=$q zRzNGD70?Q31+)TM0j+>mKr5gX&)>F)@OcX z;Au^ecoEM$iz3(W@wvdUyrvz5Y|&+_c*nd022VR>Q|kc5R>Cm(N=Ut3(pP7uco3et zuE)-Vme0E^l*98$#1K31eP%~);13<322H|7JhN70Wv=5W9}lhNWfnFm?#7Q9>A7|l zH4`h*&n#KdDSRg;^IDS5M)ygVM>1x`RQaa}r82a*{{KRvN+OF>q+jomu@-xaD?M~pV$)(VG z8mF>fD#>c|c$v%*1<_uyya6*trwsUKUDsz$zPbiq3Rbb##)OYX(w-@jOdJKhp2r@F zqR{OOA}G7fY<$q+Hpa4Mvt>+88|TS1jTP))9KFdFuc_f=;`)?tQENj=s8k%7k4MH5 zN<$WtF=hB{H7*y~)+C(fgijvY#8I7{j9J@nXv_YTO^L_az*5hT)SV&4qYP?nD@ggQ zOLVGTUnMPRB%%Zgn;sdA1*u6xW+Km^T%5w3h&%C7NkHmhz8rXE>8X9`P|nOt%@u1B z*;^T3SjMJwaD0}dL&*)2K3R2YwvvyMcn4>)sZDbEN@KQCwJC`*ZOKGc&V4DT($>tj zLu|&Wrk3KK)K;ydxV@Qfl4MpRPh#9qS5wKzc(MO>5oyW9mf0fIwrU9#h8FcJL|myH z)iA4?xNV4;qIt1c5+nFW?)&1Z0Bv!>2*Sw7wm>phHw^klqix3TOwnf+il8we?TQOA zik8Q{pksMvDFeB6C3W@omAcG56!fUKE@V`(RAs6STP>s9?molfMtVIfO_;WtgXHoC z8*v;S2EQuDW!CnKa$Kfa$hWKXob6w8Wjv4JeEAM!tV;uN9*M+R9xn=Sd8&h9*Q_C) zobs(q^`#`i@`gB2vQP|UUglxAtujQNR}`jlmn+XKN>=GsEwf8d*+hH-3X^=Sn4|F7 zP!PIigUHVV#fRJ^va`lZWwXe^swd@~+{%YCEVov-n{+ (point(e, direction, 0) + point(e, direction, 1)) / 2; - function apply(factor: number, offset: [number, number]) { - if (factor < MIN) return apply(MIN, offset); - if (factor > MAX) return apply(5, offset); + function apply(factor: number, _offset?: [number, number]) { + if (factor < MIN) return apply(MIN, _offset); + if (factor > MAX) return apply(5, _offset); - const [x, y] = offset; - element().style.transform = `scale(${(Math.floor(factor * 100) / 100).toString()}) translate(${x}px, ${y}px)`; - currentX = x; - currentY = y; - currentZoom = factor; + let x: number, y: number; + if (_offset) [x, y] = _offset; + else { + x = currentX + y = currentY + } + element().style.transform = `scale(${factor.toString()}) translate(${x}px, ${y}px)`; + currentX = x; + currentY = y; + currentZoom = factor; } - canvas.addEventListener("touchstart", (event: TouchEvent) => { - (document.activeElement as HTMLElement).blur(); - - if (lastElement != undefined && lastElement != element()) reset(); - lastElement = element(); - - initialZoom = currentZoom; - initialX = currentX; - initialY = currentY; - - if (event.touches.length != 2) { - pinching = false; - initialTouchX = event.touches[0].clientX; - initialTouchY = event.touches[0].clientY; - return; - } - - pinching = true; - initialDistance = distance(event); - initialTouchX = midpoint(event, "x"); - initialTouchY = midpoint(event, "y"); - }); - canvas.addEventListener("touchmove", (event: TouchEvent) => { - if (!pinching) { - apply(currentZoom, [ - initialX + - (event.touches[0].clientX - initialTouchX) / initialZoom, - initialY + - (event.touches[0].clientY - initialTouchY) / initialZoom, - ]); - return; - } - if (event.touches.length < 2) return; - event.preventDefault(); - const currentDistance = distance(event); - const midX = midpoint(event, "x"); - const midY = midpoint(event, "y"); - const ratio = currentDistance / initialDistance; - const difference = currentDistance - initialDistance; - apply(initialZoom * ratio, [ - initialX + (midX - difference - initialTouchX) / initialZoom, - initialY + (midY - difference - initialTouchY) / initialZoom, - ]); - }); canvas.addEventListener("wheel", (event: WheelEvent) => { - event.preventDefault(); - if (!event.shiftKey) { - apply(currentZoom, [ - currentX - event.deltaX, - currentY - event.deltaY, - ]); - return; - } - apply(currentZoom + (event.deltaY < 0 ? 1 : -1) * 0.1, [ - initialX, - initialY, - ]); + event.preventDefault(); + + initialZoom = currentZoom; + initialX = currentX; + initialY = currentY; + + if (!event.shiftKey) { + apply(currentZoom, [ + currentX - event.deltaX, + currentY - event.deltaY, + ]); + return; + } + apply(currentZoom - event.deltaY * 0.01); }); canvas.addEventListener("scroll", (event: MouseEvent) => { - event.preventDefault(); + event.preventDefault(); + }); + + canvas.addEventListener("touchstart", (event: TouchEvent) => { + (document.activeElement as HTMLElement).blur(); + + if (lastElement != undefined && lastElement != element()) reset(); + lastElement = element(); + + initialZoom = currentZoom; + initialX = currentX; + initialY = currentY; + + if (event.touches.length != 2) { + pinching = false; + initialTouchX = event.touches[0].clientX; + initialTouchY = event.touches[0].clientY; + return; + } + + pinching = true; + initialDistance = distance(event); + initialTouchX = midpoint(event, "x"); + initialTouchY = midpoint(event, "y"); + }); + canvas.addEventListener("touchmove", (event: TouchEvent) => { + if (!pinching) { + apply(currentZoom, [ + initialX + + (event.touches[0].clientX - initialTouchX) / initialZoom, + initialY + + (event.touches[0].clientY - initialTouchY) / initialZoom, + ]); + return; + } + if (event.touches.length < 2) return; + event.preventDefault(); + const currentDistance = distance(event); + const midX = midpoint(event, "x"); + const midY = midpoint(event, "y"); + const ratio = currentDistance / initialDistance; + const difference = currentDistance - initialDistance; + apply(initialZoom * ratio, [ + initialX + (midX - difference - initialTouchX) / initialZoom, + initialY + (midY - difference - initialTouchY) / initialZoom, + ]); }); } diff --git a/src/ViewModel/Global/.coreViewModel.ts.swp b/src/ViewModel/Global/.coreViewModel.ts.swp index 5196f81ccc6f7012e58e301403e0e7c9ba2234a0..f1deea6778f035714c0edb82127541cb42923c03 100644 GIT binary patch delta 79 zcmZo@U~Fh$lut4U^Ym4))H7fJ0s#hwldI-rMM;P=%ui-uNY5;pxKVYZOPemE+2+%_ cUHqa6s-HH>z%QY13si-F#ZN bi(ixjqzVY6ff%Tm;XN}01N-JI+i6Sy(^L@m diff --git a/src/ViewModel/Global/.fileTransferViewModel.ts.swp b/src/ViewModel/Global/.fileTransferViewModel.ts.swp deleted file mode 100644 index 2b17644e987ca281a7e858aab531749ae47d210f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 Jr&pbE{0HohuV(-N diff --git a/src/ViewModel/Global/coreViewModel.ts b/src/ViewModel/Global/coreViewModel.ts index 8f897998..6cce6625 100644 --- a/src/ViewModel/Global/coreViewModel.ts +++ b/src/ViewModel/Global/coreViewModel.ts @@ -9,7 +9,7 @@ import ConnectionModel from "../../Model/Global/connectionModel"; import ChatListModel from "../../Model/Chat/chatListModel"; export default class CoreViewModel { - readonly BUILD = "Build 26.09.05.A"; + readonly BUILD = "Build 26.09.06.A"; translations: Translations; diff --git a/src/index.tsx b/src/index.tsx index a44a0c5e..34daa9fe 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -100,4 +100,3 @@ document StorageModal(coreViewModel, storageViewModel), SettingsModal(coreViewModel, settingsViewModel), ); -Utility.implementPinchZoom(".zoom");