UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

162 lines (161 loc) • 5.76 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var ShapeIndicatorOverlayUtil_exports = {}; __export(ShapeIndicatorOverlayUtil_exports, { ShapeIndicatorOverlayUtil: () => ShapeIndicatorOverlayUtil, strokeShapeIndicators: () => strokeShapeIndicators }); module.exports = __toCommonJS(ShapeIndicatorOverlayUtil_exports); var import_state = require("@tldraw/state"); var import_store = require("@tldraw/store"); var import_OverlayUtil = require("./OverlayUtil"); const indicatorPathCache = (0, import_store.createComputedCache)( "shapeIndicatorPath", (editor, shape) => { const util = editor.getShapeUtil(shape); return util.getIndicatorPath(shape); }, { areRecordsEqual(a, b) { return a.props === b.props; } } ); function strokeShapeIndicators(editor, ctx, shapeIds) { if (shapeIds.length === 0) return; const batched = new Path2D(); for (const shapeId of shapeIds) { const shape = editor.getShape(shapeId); if (!shape || shape.isLocked) continue; const pageTransform = editor.getShapePageTransform(shape); if (!pageTransform) continue; const indicatorPath = indicatorPathCache.get(editor, shape.id); if (!indicatorPath) continue; if (indicatorPath instanceof Path2D) { batched.addPath(indicatorPath, pageTransform); continue; } const { path, clipPath, additionalPaths } = indicatorPath; if (!clipPath) { batched.addPath(path, pageTransform); if (additionalPaths) { for (const p of additionalPaths) batched.addPath(p, pageTransform); } continue; } ctx.save(); ctx.transform( pageTransform.a, pageTransform.b, pageTransform.c, pageTransform.d, pageTransform.e, pageTransform.f ); ctx.save(); ctx.clip(clipPath, "evenodd"); ctx.stroke(path); ctx.restore(); if (additionalPaths) { for (const p of additionalPaths) ctx.stroke(p); } ctx.restore(); } ctx.stroke(batched); } class ShapeIndicatorOverlayUtil extends import_OverlayUtil.OverlayUtil { static type = "shape_indicator"; options = { zIndex: 50, lineWidth: 1.5, hintedLineWidth: 2.5 }; // Narrow projection of instance state. Reading the full record would // re-fire getOverlays on every cursor move / brush update; gating on these // three booleans means we only re-fire when one of them actually flips. _instanceFlags$ = (0, import_state.computed)( "shape indicator instance flags", () => { const i = this.editor.getInstanceState(); return { isChangingStyle: i.isChangingStyle, isHoveringCanvas: i.isHoveringCanvas, isCoarsePointer: i.isCoarsePointer }; }, { isEqual: (a, b) => a.isChangingStyle === b.isChangingStyle && a.isHoveringCanvas === b.isHoveringCanvas && a.isCoarsePointer === b.isCoarsePointer } ); isActive() { return true; } getOverlays() { const editor = this.editor; const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id)); const idsToDisplay = []; const { isChangingStyle, isHoveringCanvas, isCoarsePointer } = this._instanceFlags$.get(); const isIdleOrEditing = editor.isInAny("select.idle", "select.editing_shape"); const isInSelectState = editor.isInAny( "select.brushing", "select.scribble_brushing", "select.pointing_shape", "select.pointing_selection", "select.pointing_handle" ); if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) { for (const id of editor.getSelectedShapeIds()) { if (renderingShapeIds.has(id)) idsToDisplay.push(id); } if (isIdleOrEditing && isHoveringCanvas && !isCoarsePointer) { const hovered = editor.getHoveredShapeId(); if (hovered && renderingShapeIds.has(hovered) && !idsToDisplay.includes(hovered)) { idsToDisplay.push(hovered); } } } const hintingShapeIds = []; for (const id of editor.getHintingShapeIds()) { if (renderingShapeIds.has(id)) hintingShapeIds.push(id); } if (idsToDisplay.length === 0 && hintingShapeIds.length === 0) { return []; } return [ { id: "shape_indicator", type: "shape_indicator", props: { idsToDisplay, hintingShapeIds } } ]; } render(ctx, overlays) { const overlay = overlays[0]; if (!overlay) return; const editor = this.editor; const zoom = editor.getZoomLevel(); const { idsToDisplay, hintingShapeIds } = overlay.props; ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.strokeStyle = editor.getCurrentTheme().colors[editor.getColorMode()].selectionStroke; ctx.lineWidth = this.options.lineWidth / zoom; strokeShapeIndicators(editor, ctx, idsToDisplay); if (hintingShapeIds.length > 0) { ctx.lineWidth = this.options.hintedLineWidth / zoom; strokeShapeIndicators(editor, ctx, hintingShapeIds); } } } //# sourceMappingURL=ShapeIndicatorOverlayUtil.js.map