allow templates to be moved via cursor + alt (related #28)
This commit is contained in:
parent
5d2ef8989e
commit
e69f5bf618
|
@ -2,10 +2,12 @@ import { useEffect, useRef } from "react";
|
||||||
import { Template as TemplateCl } from "../lib/template";
|
import { Template as TemplateCl } from "../lib/template";
|
||||||
import { useAppContext } from "../contexts/AppContext";
|
import { useAppContext } from "../contexts/AppContext";
|
||||||
import { useTemplateContext } from "../contexts/TemplateContext";
|
import { useTemplateContext } from "../contexts/TemplateContext";
|
||||||
|
import { Canvas } from "../lib/canvas";
|
||||||
|
|
||||||
export const Template = () => {
|
export const Template = () => {
|
||||||
const { config } = useAppContext();
|
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 templateHolder = useRef<HTMLDivElement>(null);
|
||||||
const instance = useRef<TemplateCl>();
|
const instance = useRef<TemplateCl>();
|
||||||
|
|
||||||
|
@ -15,15 +17,71 @@ export const Template = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const templateHolderRef = templateHolder.current;
|
||||||
|
|
||||||
instance.current = new TemplateCl(config!, templateHolder.current);
|
instance.current = new TemplateCl(config!, templateHolder.current);
|
||||||
|
|
||||||
instance.current.on("autoDetectWidth", (width) => {
|
instance.current.on("autoDetectWidth", (width) => {
|
||||||
console.log("autodetectwidth", width);
|
|
||||||
setWidth(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 () => {
|
return () => {
|
||||||
instance.current?.destroy();
|
instance.current?.destroy();
|
||||||
|
|
||||||
|
templateHolderRef?.removeEventListener("mousedown", handleMouseDown);
|
||||||
|
document.removeEventListener("mousemove", handleMouseMove);
|
||||||
|
document.removeEventListener("mouseup", handleMouseUp);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,10 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
||||||
return this.config;
|
return this.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPanZoom() {
|
||||||
|
return this.PanZoom;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get nearby pixels
|
* Get nearby pixels
|
||||||
* @param x
|
* @param x
|
||||||
|
@ -325,6 +329,12 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
||||||
document.body.appendChild(el);
|
document.body.appendChild(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen (clientX, clientY) to Canvas position
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
screenToPos(x: number, y: number) {
|
screenToPos(x: number, y: number) {
|
||||||
// the rendered dimentions in the browser
|
// the rendered dimentions in the browser
|
||||||
const rect = this.canvas.getBoundingClientRect();
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
|
|
|
@ -25,6 +25,12 @@ const KEYBINDS = enforceObjectType({
|
||||||
},
|
},
|
||||||
{ key: "LONG_PRESS" },
|
{ key: "LONG_PRESS" },
|
||||||
],
|
],
|
||||||
|
TEMPLATE_MOVE: [
|
||||||
|
{
|
||||||
|
key: "LCLICK",
|
||||||
|
alt: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
class KeybindManager_ extends EventEmitter<{
|
class KeybindManager_ extends EventEmitter<{
|
||||||
|
@ -34,6 +40,9 @@ class KeybindManager_ extends EventEmitter<{
|
||||||
super();
|
super();
|
||||||
// setup listeners
|
// setup listeners
|
||||||
|
|
||||||
|
document.addEventListener("keydown", this.handleKeydown, {
|
||||||
|
passive: false,
|
||||||
|
});
|
||||||
document.addEventListener("keyup", this.handleKeyup);
|
document.addEventListener("keyup", this.handleKeyup);
|
||||||
document.addEventListener("click", this.handleClick);
|
document.addEventListener("click", this.handleClick);
|
||||||
}
|
}
|
||||||
|
@ -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
|
// 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) => {
|
handleKeyup = (e: KeyboardEvent) => {
|
||||||
// discard if in an input element
|
// discard if in an input element
|
||||||
|
|
||||||
|
|
|
@ -343,7 +343,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
* @param e
|
* @param e
|
||||||
*/
|
*/
|
||||||
private _touch_touchmove = (event: TouchEvent) => {
|
private _touch_touchmove = (event: TouchEvent) => {
|
||||||
if (this.panning.enabled && event.touches.length === 1) {
|
if (this.panning.active && event.touches.length === 1) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
* @param e
|
* @param e
|
||||||
*/
|
*/
|
||||||
private _touch_touchend = (event: TouchEvent) => {
|
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 touch = event.changedTouches[0];
|
||||||
const dx = Math.abs(this.panning.x - touch.clientX);
|
const dx = Math.abs(this.panning.x - touch.clientX);
|
||||||
const dy = Math.abs(this.panning.y - touch.clientY);
|
const dy = Math.abs(this.panning.y - touch.clientY);
|
||||||
|
@ -372,8 +372,8 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.panning.enabled) {
|
if (this.panning.active) {
|
||||||
this.panning.enabled = false;
|
this.panning.active = false;
|
||||||
|
|
||||||
const touch = event.changedTouches[0];
|
const touch = event.changedTouches[0];
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
this.touch.pinchStartDistance = distance;
|
this.touch.pinchStartDistance = distance;
|
||||||
this.touch.lastDistance = distance;
|
this.touch.lastDistance = distance;
|
||||||
this.touch.pinchStartScale = this.transform.scale;
|
this.touch.pinchStartScale = this.transform.scale;
|
||||||
this.panning.enabled = false;
|
this.panning.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPinch(event: TouchEvent) {
|
onPinch(event: TouchEvent) {
|
||||||
|
@ -560,7 +560,9 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
|
|
||||||
this.mouse.mouseDown = Date.now();
|
this.mouse.mouseDown = Date.now();
|
||||||
|
|
||||||
this.panning.start(e.clientX, e.clientY);
|
if (this.panning.enabled) {
|
||||||
|
this.panning.start(e.clientX, e.clientY);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -570,19 +572,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
* @param e
|
* @param e
|
||||||
*/
|
*/
|
||||||
private _mouse_mousemove = (e: MouseEvent) => {
|
private _mouse_mousemove = (e: MouseEvent) => {
|
||||||
if (this.panning.enabled) {
|
if (this.panning.active) {
|
||||||
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) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
@ -629,7 +619,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.panning.enabled) {
|
if (this.panning.active) {
|
||||||
// currently panning
|
// currently panning
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { PanZoom } from "../PanZoom";
|
||||||
export class Panning {
|
export class Panning {
|
||||||
private instance: PanZoom;
|
private instance: PanZoom;
|
||||||
|
|
||||||
public enabled: boolean = false;
|
public active: boolean = false;
|
||||||
|
public enabled: boolean = true;
|
||||||
public x: number = 0;
|
public x: number = 0;
|
||||||
public y: number = 0;
|
public y: number = 0;
|
||||||
|
|
||||||
|
@ -11,13 +12,20 @@ export class Panning {
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setEnabled(enabled: boolean) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
|
||||||
|
this.active = false;
|
||||||
|
this.instance.update();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trigger panning start
|
* trigger panning start
|
||||||
* @param x clientX
|
* @param x clientX
|
||||||
* @param y clientY
|
* @param y clientY
|
||||||
*/
|
*/
|
||||||
public start(x: number, y: number) {
|
public start(x: number, y: number) {
|
||||||
this.enabled = true;
|
this.active = true;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +53,7 @@ export class Panning {
|
||||||
* @param y clientY
|
* @param y clientY
|
||||||
*/
|
*/
|
||||||
public end(x: number, y: number) {
|
public end(x: number, y: number) {
|
||||||
this.enabled = false;
|
this.active = false;
|
||||||
|
|
||||||
const deltaX = (x - this.x) / this.instance.transform.scale;
|
const deltaX = (x - this.x) / this.instance.transform.scale;
|
||||||
const deltaY = (y - this.y) / this.instance.transform.scale;
|
const deltaY = (y - this.y) / this.instance.transform.scale;
|
||||||
|
|
Loading…
Reference in New Issue