@tldraw/editor
Version:
tldraw infinite canvas SDK (editor).
162 lines (161 loc) • 5.76 kB
JavaScript
;
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