Loading packages/client/src/components/Template.tsx +60 −2 Original line number Diff line number Diff line Loading @@ -2,10 +2,12 @@ import { useEffect, useRef } from "react"; import { Template as TemplateCl } from "../lib/template"; import { useAppContext } from "../contexts/AppContext"; import { useTemplateContext } from "../contexts/TemplateContext"; import { Canvas } from "../lib/canvas"; export const Template = () => { const { config } = useAppContext(); const { enable, url, width, setWidth, x, y, opacity } = useTemplateContext(); const { enable, url, width, setWidth, x, y, opacity, setX, setY } = useTemplateContext(); const templateHolder = useRef<HTMLDivElement>(null); const instance = useRef<TemplateCl>(); Loading @@ -15,15 +17,71 @@ export const Template = () => { return; } const templateHolderRef = templateHolder.current; instance.current = new TemplateCl(config!, templateHolder.current); instance.current.on("autoDetectWidth", (width) => { console.log("autodetectwidth", width); setWidth(width); }); let startLocation: { clientX: number; clientY: number } | undefined; let offset: [x: number, y: number] = [0, 0]; const handleMouseDown = (e: MouseEvent) => { if (!e.altKey) return; startLocation = { clientX: e.clientX, clientY: e.clientY }; offset = [e.offsetX, e.offsetY]; Canvas.instance?.getPanZoom().panning.setEnabled(false); }; const handleMouseMove = (e: MouseEvent) => { if (!startLocation) return; if (!Canvas.instance) { console.warn( "[Template#handleMouseMove] Canvas.instance is not defined" ); return; } const deltaX = e.clientX - startLocation.clientX; const deltaY = e.clientY - startLocation.clientY; const newX = startLocation.clientX + deltaX; const newY = startLocation.clientY + deltaY; const [canvasX, canvasY] = Canvas.instance.screenToPos(newX, newY); templateHolderRef.style.setProperty("left", canvasX - offset[0] + "px"); templateHolderRef.style.setProperty("top", canvasY - offset[1] + "px"); }; const handleMouseUp = (e: MouseEvent) => { startLocation = undefined; Canvas.instance?.getPanZoom().panning.setEnabled(true); const x = parseInt( templateHolderRef.style.getPropertyValue("left").replace("px", "") || "0" ); const y = parseInt( templateHolderRef.style.getPropertyValue("top").replace("px", "") || "0" ); setX(x); setY(y); }; templateHolder.current.addEventListener("mousedown", handleMouseDown); document.addEventListener("mousemove", handleMouseMove); document.addEventListener("mouseup", handleMouseUp); return () => { instance.current?.destroy(); templateHolderRef?.removeEventListener("mousedown", handleMouseDown); document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); }; }, []); Loading packages/client/src/lib/canvas.ts +10 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,10 @@ export class Canvas extends EventEmitter<CanvasEvents> { return this.config; } getPanZoom() { return this.PanZoom; } /** * Get nearby pixels * @param x Loading Loading @@ -325,6 +329,12 @@ export class Canvas extends EventEmitter<CanvasEvents> { document.body.appendChild(el); } /** * Screen (clientX, clientY) to Canvas position * @param x * @param y * @returns */ screenToPos(x: number, y: number) { // the rendered dimentions in the browser const rect = this.canvas.getBoundingClientRect(); Loading packages/client/src/lib/keybinds.ts +23 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,12 @@ const KEYBINDS = enforceObjectType({ }, { key: "LONG_PRESS" }, ], TEMPLATE_MOVE: [ { key: "LCLICK", alt: true, }, ], }); class KeybindManager_ extends EventEmitter<{ Loading @@ -34,6 +40,9 @@ class KeybindManager_ extends EventEmitter<{ super(); // setup listeners document.addEventListener("keydown", this.handleKeydown, { passive: false, }); document.addEventListener("keyup", this.handleKeyup); document.addEventListener("click", this.handleClick); } Loading @@ -43,6 +52,20 @@ class KeybindManager_ extends EventEmitter<{ // this is global and doesn't depend on any elements, so this shouldn't need to be called } handleKeydown = (e: KeyboardEvent) => { const blacklistedElements = ["INPUT"]; if (e.target instanceof HTMLElement) { if (blacklistedElements.indexOf(e.target.tagName) > -1) { return; } } if (e.key === "Alt") e.preventDefault(); if (e.key === "Control") e.preventDefault(); if (e.key === "Shift") e.preventDefault(); }; handleKeyup = (e: KeyboardEvent) => { // discard if in an input element Loading packages/lib/src/renderer/PanZoom.ts +10 −20 Original line number Diff line number Diff line Loading @@ -343,7 +343,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _touch_touchmove = (event: TouchEvent) => { if (this.panning.enabled && event.touches.length === 1) { if (this.panning.active && event.touches.length === 1) { event.preventDefault(); event.stopPropagation(); Loading @@ -362,7 +362,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _touch_touchend = (event: TouchEvent) => { if (this.touch.lastTouch && this.panning.enabled) { if (this.touch.lastTouch && this.panning.active) { const touch = event.changedTouches[0]; const dx = Math.abs(this.panning.x - touch.clientX); const dy = Math.abs(this.panning.y - touch.clientY); Loading @@ -372,8 +372,8 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { } } if (this.panning.enabled) { this.panning.enabled = false; if (this.panning.active) { this.panning.active = false; const touch = event.changedTouches[0]; Loading @@ -391,7 +391,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { this.touch.pinchStartDistance = distance; this.touch.lastDistance = distance; this.touch.pinchStartScale = this.transform.scale; this.panning.enabled = false; this.panning.active = false; } onPinch(event: TouchEvent) { Loading Loading @@ -560,7 +560,9 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { this.mouse.mouseDown = Date.now(); if (this.panning.enabled) { this.panning.start(e.clientX, e.clientY); } }; /** Loading @@ -570,19 +572,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _mouse_mousemove = (e: MouseEvent) => { if (this.panning.enabled) { e.preventDefault(); e.stopPropagation(); this.panning.move(e.clientX, e.clientY); } else { // not panning this.emit("hover", { clientX: e.clientX, clientY: e.clientY, }); } if (this.panning.enabled) { if (this.panning.active) { e.preventDefault(); e.stopPropagation(); Loading Loading @@ -629,7 +619,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { } } if (this.panning.enabled) { if (this.panning.active) { // currently panning e.preventDefault(); e.stopPropagation(); Loading packages/lib/src/renderer/lib/panning.utils.ts +11 −3 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ import { PanZoom } from "../PanZoom"; export class Panning { private instance: PanZoom; public enabled: boolean = false; public active: boolean = false; public enabled: boolean = true; public x: number = 0; public y: number = 0; Loading @@ -11,13 +12,20 @@ export class Panning { this.instance = instance; } public setEnabled(enabled: boolean) { this.enabled = enabled; this.active = false; this.instance.update(); } /** * trigger panning start * @param x clientX * @param y clientY */ public start(x: number, y: number) { this.enabled = true; this.active = true; this.x = x; this.y = y; } Loading Loading @@ -45,7 +53,7 @@ export class Panning { * @param y clientY */ public end(x: number, y: number) { this.enabled = false; this.active = false; const deltaX = (x - this.x) / this.instance.transform.scale; const deltaY = (y - this.y) / this.instance.transform.scale; Loading Loading
packages/client/src/components/Template.tsx +60 −2 Original line number Diff line number Diff line Loading @@ -2,10 +2,12 @@ import { useEffect, useRef } from "react"; import { Template as TemplateCl } from "../lib/template"; import { useAppContext } from "../contexts/AppContext"; import { useTemplateContext } from "../contexts/TemplateContext"; import { Canvas } from "../lib/canvas"; export const Template = () => { const { config } = useAppContext(); const { enable, url, width, setWidth, x, y, opacity } = useTemplateContext(); const { enable, url, width, setWidth, x, y, opacity, setX, setY } = useTemplateContext(); const templateHolder = useRef<HTMLDivElement>(null); const instance = useRef<TemplateCl>(); Loading @@ -15,15 +17,71 @@ export const Template = () => { return; } const templateHolderRef = templateHolder.current; instance.current = new TemplateCl(config!, templateHolder.current); instance.current.on("autoDetectWidth", (width) => { console.log("autodetectwidth", width); setWidth(width); }); let startLocation: { clientX: number; clientY: number } | undefined; let offset: [x: number, y: number] = [0, 0]; const handleMouseDown = (e: MouseEvent) => { if (!e.altKey) return; startLocation = { clientX: e.clientX, clientY: e.clientY }; offset = [e.offsetX, e.offsetY]; Canvas.instance?.getPanZoom().panning.setEnabled(false); }; const handleMouseMove = (e: MouseEvent) => { if (!startLocation) return; if (!Canvas.instance) { console.warn( "[Template#handleMouseMove] Canvas.instance is not defined" ); return; } const deltaX = e.clientX - startLocation.clientX; const deltaY = e.clientY - startLocation.clientY; const newX = startLocation.clientX + deltaX; const newY = startLocation.clientY + deltaY; const [canvasX, canvasY] = Canvas.instance.screenToPos(newX, newY); templateHolderRef.style.setProperty("left", canvasX - offset[0] + "px"); templateHolderRef.style.setProperty("top", canvasY - offset[1] + "px"); }; const handleMouseUp = (e: MouseEvent) => { startLocation = undefined; Canvas.instance?.getPanZoom().panning.setEnabled(true); const x = parseInt( templateHolderRef.style.getPropertyValue("left").replace("px", "") || "0" ); const y = parseInt( templateHolderRef.style.getPropertyValue("top").replace("px", "") || "0" ); setX(x); setY(y); }; templateHolder.current.addEventListener("mousedown", handleMouseDown); document.addEventListener("mousemove", handleMouseMove); document.addEventListener("mouseup", handleMouseUp); return () => { instance.current?.destroy(); templateHolderRef?.removeEventListener("mousedown", handleMouseDown); document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); }; }, []); Loading
packages/client/src/lib/canvas.ts +10 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,10 @@ export class Canvas extends EventEmitter<CanvasEvents> { return this.config; } getPanZoom() { return this.PanZoom; } /** * Get nearby pixels * @param x Loading Loading @@ -325,6 +329,12 @@ export class Canvas extends EventEmitter<CanvasEvents> { document.body.appendChild(el); } /** * Screen (clientX, clientY) to Canvas position * @param x * @param y * @returns */ screenToPos(x: number, y: number) { // the rendered dimentions in the browser const rect = this.canvas.getBoundingClientRect(); Loading
packages/client/src/lib/keybinds.ts +23 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,12 @@ const KEYBINDS = enforceObjectType({ }, { key: "LONG_PRESS" }, ], TEMPLATE_MOVE: [ { key: "LCLICK", alt: true, }, ], }); class KeybindManager_ extends EventEmitter<{ Loading @@ -34,6 +40,9 @@ class KeybindManager_ extends EventEmitter<{ super(); // setup listeners document.addEventListener("keydown", this.handleKeydown, { passive: false, }); document.addEventListener("keyup", this.handleKeyup); document.addEventListener("click", this.handleClick); } Loading @@ -43,6 +52,20 @@ class KeybindManager_ extends EventEmitter<{ // this is global and doesn't depend on any elements, so this shouldn't need to be called } handleKeydown = (e: KeyboardEvent) => { const blacklistedElements = ["INPUT"]; if (e.target instanceof HTMLElement) { if (blacklistedElements.indexOf(e.target.tagName) > -1) { return; } } if (e.key === "Alt") e.preventDefault(); if (e.key === "Control") e.preventDefault(); if (e.key === "Shift") e.preventDefault(); }; handleKeyup = (e: KeyboardEvent) => { // discard if in an input element Loading
packages/lib/src/renderer/PanZoom.ts +10 −20 Original line number Diff line number Diff line Loading @@ -343,7 +343,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _touch_touchmove = (event: TouchEvent) => { if (this.panning.enabled && event.touches.length === 1) { if (this.panning.active && event.touches.length === 1) { event.preventDefault(); event.stopPropagation(); Loading @@ -362,7 +362,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _touch_touchend = (event: TouchEvent) => { if (this.touch.lastTouch && this.panning.enabled) { if (this.touch.lastTouch && this.panning.active) { const touch = event.changedTouches[0]; const dx = Math.abs(this.panning.x - touch.clientX); const dy = Math.abs(this.panning.y - touch.clientY); Loading @@ -372,8 +372,8 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { } } if (this.panning.enabled) { this.panning.enabled = false; if (this.panning.active) { this.panning.active = false; const touch = event.changedTouches[0]; Loading @@ -391,7 +391,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { this.touch.pinchStartDistance = distance; this.touch.lastDistance = distance; this.touch.pinchStartScale = this.transform.scale; this.panning.enabled = false; this.panning.active = false; } onPinch(event: TouchEvent) { Loading Loading @@ -560,7 +560,9 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { this.mouse.mouseDown = Date.now(); if (this.panning.enabled) { this.panning.start(e.clientX, e.clientY); } }; /** Loading @@ -570,19 +572,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { * @param e */ private _mouse_mousemove = (e: MouseEvent) => { if (this.panning.enabled) { e.preventDefault(); e.stopPropagation(); this.panning.move(e.clientX, e.clientY); } else { // not panning this.emit("hover", { clientX: e.clientX, clientY: e.clientY, }); } if (this.panning.enabled) { if (this.panning.active) { e.preventDefault(); e.stopPropagation(); Loading Loading @@ -629,7 +619,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> { } } if (this.panning.enabled) { if (this.panning.active) { // currently panning e.preventDefault(); e.stopPropagation(); Loading
packages/lib/src/renderer/lib/panning.utils.ts +11 −3 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ import { PanZoom } from "../PanZoom"; export class Panning { private instance: PanZoom; public enabled: boolean = false; public active: boolean = false; public enabled: boolean = true; public x: number = 0; public y: number = 0; Loading @@ -11,13 +12,20 @@ export class Panning { this.instance = instance; } public setEnabled(enabled: boolean) { this.enabled = enabled; this.active = false; this.instance.update(); } /** * trigger panning start * @param x clientX * @param y clientY */ public start(x: number, y: number) { this.enabled = true; this.active = true; this.x = x; this.y = y; } Loading Loading @@ -45,7 +53,7 @@ export class Panning { * @param y clientY */ public end(x: number, y: number) { this.enabled = false; this.active = false; const deltaX = (x - this.x) / this.instance.transform.scale; const deltaY = (y - this.y) / this.instance.transform.scale; Loading