Commit e69f5bf6 authored by Grant's avatar Grant
Browse files

allow templates to be moved via cursor + alt (related #28)

parent 5d2ef898
Loading
Loading
Loading
Loading
+60 −2
Original line number Diff line number Diff line
@@ -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>();

@@ -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);
    };
  }, []);

+10 −0
Original line number Diff line number Diff line
@@ -95,6 +95,10 @@ export class Canvas extends EventEmitter<CanvasEvents> {
    return this.config;
  }

  getPanZoom() {
    return this.PanZoom;
  }

  /**
   * Get nearby pixels
   * @param x
@@ -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();
+23 −0
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@ const KEYBINDS = enforceObjectType({
    },
    { key: "LONG_PRESS" },
  ],
  TEMPLATE_MOVE: [
    {
      key: "LCLICK",
      alt: true,
    },
  ],
});

class KeybindManager_ extends EventEmitter<{
@@ -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);
  }
@@ -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

+10 −20
Original line number Diff line number Diff line
@@ -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();

@@ -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);
@@ -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];

@@ -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) {
@@ -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);
    }
  };

  /**
@@ -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();

@@ -629,7 +619,7 @@ export class PanZoom extends EventEmitter<PanZoomEvents> {
      }
    }

    if (this.panning.enabled) {
    if (this.panning.active) {
      // currently panning
      e.preventDefault();
      e.stopPropagation();
+11 −3
Original line number Diff line number Diff line
@@ -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;

@@ -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;
  }
@@ -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;