@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
110 lines (109 loc) • 4.04 kB
JavaScript
import { Vec } from "../../../primitives/Vec.mjs";
import { EASINGS } from "../../../primitives/easings.mjs";
class EdgeScrollManager {
constructor(editor) {
this.editor = editor;
}
_isEdgeScrolling = false;
_edgeScrollDuration = -1;
/**
* Update the camera position when the mouse is close to the edge of the screen.
* Run this on every tick when in a state where edge scrolling is enabled.
*
* @public
*/
updateEdgeScrolling(elapsed) {
const { editor } = this;
const edgeScrollProximityFactor = this.getEdgeScroll();
if (edgeScrollProximityFactor.x === 0 && edgeScrollProximityFactor.y === 0) {
if (this._isEdgeScrolling) {
this._isEdgeScrolling = false;
this._edgeScrollDuration = 0;
}
} else {
if (!this._isEdgeScrolling) {
this._isEdgeScrolling = true;
this._edgeScrollDuration = 0;
}
this._edgeScrollDuration += elapsed;
if (this._edgeScrollDuration > editor.options.edgeScrollDelay) {
const eased = editor.options.edgeScrollEaseDuration > 0 ? EASINGS.easeInCubic(
Math.min(
1,
this._edgeScrollDuration / (editor.options.edgeScrollDelay + editor.options.edgeScrollEaseDuration)
)
) : 1;
this.moveCameraWhenCloseToEdge({
x: edgeScrollProximityFactor.x * eased,
y: edgeScrollProximityFactor.y * eased
});
}
}
}
/**
* Helper function to get the scroll proximity factor for a given position.
* @param position - The mouse position on the axis.
* @param dimension - The component dimension on the axis.
* @param isCoarse - Whether the pointer is coarse.
* @param insetStart - Whether the pointer is inset at the start of the axis.
* @param insetEnd - Whether the pointer is inset at the end of the axis.
* @internal
*/
getEdgeProximityFactors(position, dimension, isCoarse, insetStart, insetEnd) {
const { editor } = this;
const dist = editor.options.edgeScrollDistance;
const pw = isCoarse ? editor.options.coarsePointerWidth : 0;
const pMin = position - pw;
const pMax = position + pw;
const min = insetStart ? 0 : dist;
const max = insetEnd ? dimension : dimension - dist;
if (pMin < min) {
return Math.min(1, (min - pMin) / dist);
} else if (pMax > max) {
return -Math.min(1, (pMax - max) / dist);
}
return 0;
}
getEdgeScroll() {
const { editor } = this;
const {
inputs: {
currentScreenPoint: { x, y }
}
} = editor;
const screenBounds = editor.getViewportScreenBounds();
const {
isCoarsePointer,
insets: [t, r, b, l]
} = editor.getInstanceState();
const proximityFactorX = this.getEdgeProximityFactors(x, screenBounds.w, isCoarsePointer, l, r);
const proximityFactorY = this.getEdgeProximityFactors(y, screenBounds.h, isCoarsePointer, t, b);
return {
x: proximityFactorX,
y: proximityFactorY
};
}
/**
* Moves the camera when the mouse is close to the edge of the screen.
* @public
*/
moveCameraWhenCloseToEdge(proximityFactor) {
const { editor } = this;
if (!editor.inputs.isDragging || editor.inputs.isPanning || editor.getCameraOptions().isLocked)
return;
if (proximityFactor.x === 0 && proximityFactor.y === 0) return;
const screenBounds = editor.getViewportScreenBounds();
const screenSizeFactorX = screenBounds.w < 1e3 ? 0.612 : 1;
const screenSizeFactorY = screenBounds.h < 1e3 ? 0.612 : 1;
const zoomLevel = editor.getZoomLevel();
const pxSpeed = editor.user.getEdgeScrollSpeed() * editor.options.edgeScrollSpeed;
const scrollDeltaX = pxSpeed * proximityFactor.x * screenSizeFactorX / zoomLevel;
const scrollDeltaY = pxSpeed * proximityFactor.y * screenSizeFactorY / zoomLevel;
const { x, y, z } = editor.getCamera();
editor.setCamera(new Vec(x + scrollDeltaX, y + scrollDeltaY, z));
}
}
export {
EdgeScrollManager
};
//# sourceMappingURL=EdgeScrollManager.mjs.map