diff --git a/core/dragging/dragger.ts b/core/dragging/dragger.ts new file mode 100644 index 000000000..2a65e5ac7 --- /dev/null +++ b/core/dragging/dragger.ts @@ -0,0 +1,77 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {IDragger} from '../interfaces/i_dragger.js'; +import {IDraggable} from '../interfaces/i_draggable.js'; +import {Coordinate} from '../utils/coordinate.js'; +import {WorkspaceSvg} from '../workspace_svg.js'; + +export class Dragger implements IDragger { + /** Starting location of the draggable, in workspace coordinates. */ + private startLoc: Coordinate; + + constructor( + private draggable: IDraggable, + private workspace: WorkspaceSvg, + ) { + this.startLoc = draggable.getLocation(); + } + + /** + * Handles any drag startup. + * + * @param e PointerEvent that started the drag. + */ + onDragStart(e: PointerEvent) { + this.draggable.startDrag(e); + } + + /** + * Handles dragging, including calculating where the element should + * actually be moved to. + * + * @param e PointerEvent that continued the drag. + * @param totalDelta The total distance, in pixels, that the mouse + * has moved since the start of the drag. + */ + onDrag(e: PointerEvent, totalDelta: Coordinate) { + this.draggable.drag(this.newLoc(totalDelta), e); + } + + /** + * Handles any drag cleanup. + * + * @param e PointerEvent that finished the drag. + * @param totalDelta The total distance, in pixels, that the mouse + * has moved since the start of the drag. + */ + onDragEnd(e: PointerEvent, totalDelta: Coordinate) { + this.draggable.endDrag(this.newLoc(totalDelta), e); + } + + /** + * Calculates where the IDraggable should actually be moved to. + * + * @param totalDelta The total distance, in pixels, that the mouse + * has moved since the start of the drag. + * @returns The new location, in workspace coordinates. + */ + protected newLoc(totalDelta: Coordinate): Coordinate { + const result = new Coordinate( + totalDelta.x / this.workspace.scale, + totalDelta.y / this.workspace.scale, + ); + if (this.workspace.isMutator) { + // If we're in a mutator, its scale is always 1, purely because of some + // oddities in our rendering optimizations. The actual scale is the same + // as the scale on the parent workspace. Fix that for dragging. + const mainScale = this.workspace.options.parentWorkspace!.scale; + result.scale(1 / mainScale); + } + result.translate(this.startLoc.x, this.startLoc.y); + return result; + } +}