UNPKG

tldraw

Version:

A tiny little drawing editor.

169 lines (168 loc) 4.94 kB
import { Vec, compact, createShapeId, toRichText } from "@tldraw/editor"; const CLONE_HANDLE_MARGIN = 0; const NOTE_SIZE = 200; const NOTE_CENTER_OFFSET = new Vec(NOTE_SIZE / 2, NOTE_SIZE / 2); const NOTE_ADJACENT_POSITION_SNAP_RADIUS = 10; const BASE_NOTE_POSITIONS = (editor) => [ [ ["a1"], new Vec(NOTE_SIZE * 0.5, NOTE_SIZE * -0.5 - editor.options.adjacentShapeMargin) ], // t [ ["a2"], new Vec(NOTE_SIZE * 1.5 + editor.options.adjacentShapeMargin, NOTE_SIZE * 0.5) ], // r [ ["a3"], new Vec(NOTE_SIZE * 0.5, NOTE_SIZE * 1.5 + editor.options.adjacentShapeMargin) ], // b [ ["a4"], new Vec(NOTE_SIZE * -0.5 - editor.options.adjacentShapeMargin, NOTE_SIZE * 0.5) ] // l ]; function getBaseAdjacentNotePositions(editor, scale) { if (scale === 1) return BASE_NOTE_POSITIONS(editor); const s = NOTE_SIZE * scale; const m = editor.options.adjacentShapeMargin * scale; return [ [["a1"], new Vec(s * 0.5, s * -0.5 - m)], // t [["a2"], new Vec(s * 1.5 + m, s * 0.5)], // r [["a3"], new Vec(s * 0.5, s * 1.5 + m)], // b [["a4"], new Vec(s * -0.5 - m, s * 0.5)] // l ]; } function getNoteAdjacentPositions(editor, pagePoint, pageRotation, growY, extraHeight, scale) { return Object.fromEntries( getBaseAdjacentNotePositions(editor, scale).map(([id, v], i) => { const point = v.clone(); if (i === 0 && extraHeight) { point.y -= extraHeight; } else if (i === 2 && growY) { point.y += growY; } return [id, point.rot(pageRotation).add(pagePoint)]; }) ); } function getAvailableNoteAdjacentPositions(editor, rotation, scale, extraHeight) { const selectedShapeIds = new Set(editor.getSelectedShapeIds()); const minSize = (NOTE_SIZE + editor.options.adjacentShapeMargin + extraHeight) ** 2; const allCenters = /* @__PURE__ */ new Map(); const positions = []; for (const shape of editor.getCurrentPageShapes()) { if (!editor.isShapeOfType(shape, "note") || scale !== shape.props.scale || selectedShapeIds.has(shape.id)) { continue; } const transform = editor.getShapePageTransform(shape.id); if (rotation !== transform.rotation()) continue; allCenters.set(shape, editor.getShapePageBounds(shape).center); positions.push( ...Object.values( getNoteAdjacentPositions( editor, transform.point(), rotation, shape.props.growY, extraHeight, scale ) ) ); } const len = positions.length; let position; for (const [shape, center] of allCenters) { for (let i = 0; i < len; i++) { position = positions[i]; if (!position) continue; if (Vec.Dist2(center, position) > minSize) continue; if (editor.isPointInShape(shape, position)) { positions[i] = void 0; } } } return compact(positions); } function getNoteShapeForAdjacentPosition(editor, shape, center, pageRotation, forceNew = false) { let nextNote; const allShapesOnPage = editor.getCurrentPageShapesSorted(); const minDistance = (NOTE_SIZE + editor.options.adjacentShapeMargin ** 2) ** shape.props.scale; for (let i = allShapesOnPage.length - 1; i >= 0; i--) { const otherNote = allShapesOnPage[i]; if (otherNote.type === "note" && otherNote.id !== shape.id) { const otherBounds = editor.getShapePageBounds(otherNote); if (otherBounds && Vec.Dist2(otherBounds.center, center) < minDistance && editor.isPointInShape(otherNote, center)) { nextNote = otherNote; break; } } } editor.complete(); if (!nextNote || forceNew) { editor.markHistoryStoppingPoint("creating note shape"); const id = createShapeId(); editor.createShape({ id, type: "note", x: center.x, y: center.y, rotation: pageRotation, opacity: shape.opacity, props: { // Use the props of the shape we're cloning ...shape.props, richText: toRichText(""), growY: 0, fontSizeAdjustment: 0, url: "" } }); const createdShape = editor.getShape(id); if (!createdShape) return; const topLeft = editor.getPointInParentSpace( createdShape, Vec.Sub( center, Vec.Rot(NOTE_CENTER_OFFSET.clone().mul(createdShape.props.scale), pageRotation) ) ); editor.updateShape({ id, type: "note", x: topLeft.x, y: topLeft.y }); nextNote = editor.getShape(id); } editor.zoomToSelectionIfOffscreen(16, { animation: { duration: editor.options.animationMediumMs }, inset: 0 }); return nextNote; } export { CLONE_HANDLE_MARGIN, NOTE_ADJACENT_POSITION_SNAP_RADIUS, NOTE_CENTER_OFFSET, NOTE_SIZE, getAvailableNoteAdjacentPositions, getNoteAdjacentPositions, getNoteShapeForAdjacentPosition }; //# sourceMappingURL=noteHelpers.mjs.map