@neta-art/cohub 5.3.3 → 5.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/board/codec.d.ts +2 -0
- package/dist/board/codec.js +18 -13
- package/dist/board/core/arrow-geometry.d.ts +23 -0
- package/dist/board/core/arrow-geometry.js +109 -0
- package/dist/board/core/connections.d.ts +91 -0
- package/dist/board/core/connections.js +414 -0
- package/dist/board/core/export-plan.d.ts +15 -4
- package/dist/board/core/export-plan.js +49 -16
- package/dist/board/core/shape-definition.js +1 -1
- package/dist/board/core/shape-types.d.ts +8 -2
- package/dist/board/core/shape-types.js +1 -1
- package/dist/board/core/tool-styles.d.ts +9 -3
- package/dist/board/core/tool-styles.js +10 -6
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +3 -0
- package/dist/board/export/scene.js +18 -1
- package/dist/board/index.d.ts +8 -5
- package/dist/board/index.js +8 -5
- package/dist/board/render/connection-layer.d.ts +48 -0
- package/dist/board/render/connection-layer.js +223 -0
- package/dist/board/render/index.d.ts +2 -1
- package/dist/board/render/index.js +3 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +35 -48
- package/dist/chunks/http.d.ts +53 -1
- package/dist/chunks/http.js +287 -1
- package/dist/chunks/websocket.d.ts +296 -57
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -56
- package/dist/protocol/dist/board-connection.d.ts +310 -0
- package/dist/protocol/dist/board-connection.js +215 -0
- package/dist/protocol/dist/board-constants.d.ts +11 -1
- package/dist/protocol/dist/board-constants.js +15 -1
- package/dist/protocol/dist/board-document.d.ts +106 -60
- package/dist/protocol/dist/board-document.js +57 -17
- package/dist/protocol/dist/board.d.ts +1 -0
- package/dist/protocol/dist/board.js +3 -0
- package/dist/protocol/dist/index.d.ts +2 -1
- package/dist/protocol/dist/index.js +2 -1
- package/dist/protocol/dist/realtime/board-awareness.js +15 -15
- package/package.json +1 -1
- package/dist/board/core/bindings.d.ts +0 -45
- package/dist/board/core/bindings.js +0 -162
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { BOARD_ARROW_STROKE_SIZE } from "../../protocol/dist/board-constants.js";
|
|
1
|
+
import { BOARD_ARROW_STROKE_SIZE, BOARD_CONNECTION_STROKE_SIZE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
|
|
2
2
|
import { isBoardColorId } from "./palette.js";
|
|
3
3
|
import { isGeoKind } from "./shape-types.js";
|
|
4
4
|
//#region src/board/core/tool-styles.ts
|
|
5
|
-
const BOARD_STROKE_MIN_SIZE = 1;
|
|
6
|
-
const BOARD_STROKE_MAX_SIZE = 64;
|
|
7
5
|
const DEFAULT_BOARD_TOOL_STYLES = {
|
|
8
6
|
text: { color: "neutral" },
|
|
9
7
|
geo: {
|
|
@@ -18,18 +16,20 @@ const DEFAULT_BOARD_TOOL_STYLES = {
|
|
|
18
16
|
color: "brand",
|
|
19
17
|
size: BOARD_ARROW_STROKE_SIZE
|
|
20
18
|
},
|
|
19
|
+
connection: {
|
|
20
|
+
color: "neutral",
|
|
21
|
+
size: BOARD_CONNECTION_STROKE_SIZE
|
|
22
|
+
},
|
|
21
23
|
frame: { color: "neutral" }
|
|
22
24
|
};
|
|
23
25
|
function finiteOr(value, fallback) {
|
|
24
26
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
25
27
|
}
|
|
26
|
-
function clampBoardStrokeSize(size) {
|
|
27
|
-
return Math.min(64, Math.max(1, size));
|
|
28
|
-
}
|
|
29
28
|
/** Return a mutable, validated style map for an editor or another Board client. */
|
|
30
29
|
function createBoardToolStyles(patch = {}) {
|
|
31
30
|
const drawSize = clampBoardStrokeSize(finiteOr(patch.draw?.size, DEFAULT_BOARD_TOOL_STYLES.draw.size));
|
|
32
31
|
const arrowSize = clampBoardStrokeSize(finiteOr(patch.arrow?.size, DEFAULT_BOARD_TOOL_STYLES.arrow.size));
|
|
32
|
+
const connectionSize = clampBoardStrokeSize(finiteOr(patch.connection?.size, DEFAULT_BOARD_TOOL_STYLES.connection.size));
|
|
33
33
|
return {
|
|
34
34
|
text: { color: isBoardColorId(patch.text?.color) ? patch.text.color : DEFAULT_BOARD_TOOL_STYLES.text.color },
|
|
35
35
|
geo: {
|
|
@@ -44,6 +44,10 @@ function createBoardToolStyles(patch = {}) {
|
|
|
44
44
|
color: isBoardColorId(patch.arrow?.color) ? patch.arrow.color : DEFAULT_BOARD_TOOL_STYLES.arrow.color,
|
|
45
45
|
size: arrowSize
|
|
46
46
|
},
|
|
47
|
+
connection: {
|
|
48
|
+
color: isBoardColorId(patch.connection?.color) ? patch.connection.color : DEFAULT_BOARD_TOOL_STYLES.connection.color,
|
|
49
|
+
size: connectionSize
|
|
50
|
+
},
|
|
47
51
|
frame: { color: isBoardColorId(patch.frame?.color) ? patch.frame.color : DEFAULT_BOARD_TOOL_STYLES.frame.color }
|
|
48
52
|
};
|
|
49
53
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BoardConnection } from "../../protocol/dist/board-connection.js";
|
|
1
2
|
import { BoardDocument, BoardItem } from "../../protocol/dist/board-document.js";
|
|
2
3
|
import { Rect } from "../geometry.js";
|
|
3
4
|
import { BoardShapeColors } from "../core/palette.js";
|
|
@@ -9,6 +10,8 @@ type BoardExportSceneInput = {
|
|
|
9
10
|
document: BoardDocument;
|
|
10
11
|
/** Items to draw, in document (z) order. */
|
|
11
12
|
items: BoardItem[];
|
|
13
|
+
/** Connections to draw. Rendered beneath the cards, as in the editor. */
|
|
14
|
+
connections?: readonly BoardConnection[];
|
|
12
15
|
/** World rect being captured; content is translated so it starts at 0,0. */
|
|
13
16
|
world: Rect;
|
|
14
17
|
/** Output pixels per world unit. Drives text rasterisation resolution. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { imageAssetKey } from "../image-key.js";
|
|
2
2
|
import { buildFallbackShapeColors } from "../core/palette.js";
|
|
3
|
+
import { createConnectionLayer } from "../render/connection-layer.js";
|
|
3
4
|
import { defaultBoardPalette } from "../render/palette.js";
|
|
4
5
|
import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
|
|
5
6
|
import { Container, Graphics } from "pixi.js";
|
|
@@ -54,6 +55,19 @@ function createBoardExportScene(input) {
|
|
|
54
55
|
});
|
|
55
56
|
world.scale.set(input.scale);
|
|
56
57
|
world.position.set(-input.world.x * input.scale, -input.world.y * input.scale);
|
|
58
|
+
const connections = input.connections ?? input.document.connections;
|
|
59
|
+
let connectionLayer = null;
|
|
60
|
+
if (connections.length > 0) {
|
|
61
|
+
const frames = new Map(input.document.items.map((item) => [item.id, item.frame]));
|
|
62
|
+
connectionLayer = createConnectionLayer({ parent: world });
|
|
63
|
+
connectionLayer.sync({
|
|
64
|
+
connections,
|
|
65
|
+
getFrame: (id) => frames.get(id),
|
|
66
|
+
colors: context.colors,
|
|
67
|
+
colorScheme: input.colorScheme,
|
|
68
|
+
zoom: input.scale
|
|
69
|
+
});
|
|
70
|
+
}
|
|
57
71
|
for (const item of input.items) {
|
|
58
72
|
const renderer = getBoardCardRenderer(item, context);
|
|
59
73
|
world.addChild(renderer.create(item, context));
|
|
@@ -62,7 +76,10 @@ function createBoardExportScene(input) {
|
|
|
62
76
|
return {
|
|
63
77
|
root,
|
|
64
78
|
missingImageKeys: [...missing],
|
|
65
|
-
destroy: () =>
|
|
79
|
+
destroy: () => {
|
|
80
|
+
connectionLayer?.destroy();
|
|
81
|
+
root.destroy({ children: true });
|
|
82
|
+
}
|
|
66
83
|
};
|
|
67
84
|
}
|
|
68
85
|
//#endregion
|
package/dist/board/index.d.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../protocol/dist/board-constants.js";
|
|
2
|
+
import { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnection, BoardConnectionAnchor, BoardConnectionAnchorSchema, BoardConnectionDirection, BoardConnectionEndpoint, BoardConnectionEndpointSchema, BoardConnectionInput, BoardConnectionLine, BoardConnectionPatch, BoardConnectionPatchSchema, BoardConnectionRecord, BoardConnectionRouting, BoardConnectionRoutingConfig, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionSide, BoardConnectionStyle, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle } from "../protocol/dist/board-connection.js";
|
|
1
3
|
import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardManifest, BoardNodeRecord, BoardRecord, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
|
|
2
4
|
import { BoardExtensionDefinition, BoardExtensionRegistry, BoardPresetDefinition, CompiledSequence, DEFAULT_BOARD_LIMITS, QualityProfile, RenderBounds, TimelineClipInput, TimelineInput, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
|
|
3
|
-
import {
|
|
5
|
+
import { BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardPoint, BoardPointSchema, BoardTextItem, BoardTextItemSchema, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, DrawPoint, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, SpaceFileRef, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardDocument, parseBoardItemLoose, unknownRealType, withResolvedConnections } from "../protocol/dist/board-document.js";
|
|
4
6
|
import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, WireBackedBoardItem, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
|
|
5
7
|
import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CornerResizeHandle, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, ResizeHandle, ScreenPoint, Size, VIEWPORT_MARGIN_RATIO, WorldPoint, angleFromCenter, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
|
|
6
|
-
import {
|
|
8
|
+
import { ResolvedArrow, arrowBounds, arrowFrame, distanceToArrow, resolveArrow, sampleArrow, translateArrow } from "./core/arrow-geometry.js";
|
|
9
|
+
import { CONNECTION_ENDPOINT_GAP, ConnectionIndex, FrameLookup, ResolvedConnection, ResolvedConnectionEndpoint, anchorPointOnFrame, anchorToWorld, autoConnectionSide, connectionArrowheads, connectionBounds, connectionHitTest, createConnectionIndex, distanceToConnection, pathMidpoint, resolveConnection, worldToAnchor } from "./core/connections.js";
|
|
7
10
|
import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
|
|
8
11
|
import { BOARD_EXPORT_MAX_TEXTURES, BoardExportAssetSelection, selectBoardExportAssets } from "./core/export-assets.js";
|
|
9
|
-
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
12
|
+
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, boardFrameLookup, exportConnectionBounds, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
10
13
|
import { BoardFileSnapshotFacts, BuildSnapshotInput, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FileAvailability, FilePreviewKind, ResolvedCover, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
|
|
11
14
|
import { BOARD_COLORS, BoardColorEntry, BoardColorId, BoardColorValue, BoardShapeColors, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
|
|
12
15
|
import { ArrowShapeProps, DrawShapeProps, FULL_CAPABILITIES, GEO_KINDS, GeoKind, GeoShapeProps, HandleDragResult, ImageShapeProps, ShapeCapabilities, ShapeGeometry, ShapeHandle, ShapeHandleId, ShapeResizeMode, TextShapeProps, VideoShapeProps, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
|
|
13
16
|
import { ShapeDefinition, definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
|
|
14
17
|
import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
|
|
15
|
-
import {
|
|
18
|
+
import { BoardStyledToolId, BoardToolStyleMap, BoardToolStylePatch, DEFAULT_BOARD_TOOL_STYLES, createBoardToolStyles } from "./core/tool-styles.js";
|
|
16
19
|
import { boardImageKeySource, imageAssetKey } from "./image-key.js";
|
|
17
|
-
export {
|
|
20
|
+
export { AUTO_BOARD_CONNECTION_ANCHOR, type ArrowShapeProps, BOARD_COLORS, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardColorEntry, BoardColorId, BoardColorValue, BoardConnection, BoardConnectionAnchor, BoardConnectionAnchorSchema, BoardConnectionDirection, BoardConnectionEndpoint, BoardConnectionEndpointSchema, BoardConnectionInput, BoardConnectionLine, BoardConnectionPatch, BoardConnectionPatchSchema, BoardConnectionRecord, BoardConnectionRouting, BoardConnectionRoutingConfig, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionSide, BoardConnectionStyle, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardExportAssetSelection, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, BoardExtensionDefinition, BoardExtensionRegistry, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotFacts, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, type BoardManifest, BoardMediaSnapshot, BoardMediaSnapshotSchema, type BoardNodeRecord, BoardPoint, BoardPointSchema, BoardPresetDefinition, type BoardRecord, BoardRelationSchema, BoardShapeColors, BoardStyledToolId, BoardTextItem, BoardTextItemSchema, BoardToolStyleMap, BoardToolStylePatch, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, BuildSnapshotInput, CONNECTION_ENDPOINT_GAP, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CompiledSequence, ConnectionIndex, CornerResizeHandle, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_RELATION, DEFAULT_BOARD_TOOL_STYLES, DrawPoint, DrawPointSchema, type DrawShapeProps, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, FileAvailability, FilePreviewKind, FrameLookup, GEO_KINDS, type GeoKind, type GeoShapeProps, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, type HandleDragResult, ITEM_BASE_KEYS, type ImageShapeProps, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, QualityProfile, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, RenderBounds, ResizeHandle, ResolvedArrow, ResolvedConnection, ResolvedConnectionEndpoint, ResolvedCover, ScreenPoint, type ShapeCapabilities, ShapeDefinition, type ShapeGeometry, type ShapeHandle, type ShapeHandleId, type ShapeResizeMode, Size, SpaceFileRef, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, type TextShapeProps, TimelineClipInput, TimelineInput, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, type VideoShapeProps, WireBackedBoardItem, WorldPoint, anchorPointOnFrame, anchorToWorld, angleFromCenter, arrowBounds, arrowFrame, autoConnectionSide, availabilityFromError, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, connectionArrowheads, connectionBounds, connectionHitTest, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, createBoardExtensionRegistry, createBoardToolStyles, createConnectionIndex, definitionForItem, degToRad, distanceToArrow, distanceToConnection, distanceToStroke, expandRect, exportConnectionBounds, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, flipBoardConnection, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardConnectionStyle, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardDocument, parseBoardItemLoose, parseBoardManifest, pathMidpoint, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveConnection, resolveCoverRef, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleArrow, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, withResolvedConnections, worldPoint, worldToAnchor, worldToScreen, zoomAround };
|
package/dist/board/index.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../protocol/dist/board-constants.js";
|
|
1
2
|
import { BoardExtensionRegistry, DEFAULT_BOARD_LIMITS, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
|
|
3
|
+
import { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnectionAnchorSchema, BoardConnectionEndpointSchema, BoardConnectionPatchSchema, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle } from "../protocol/dist/board-connection.js";
|
|
2
4
|
import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
|
|
3
|
-
import {
|
|
5
|
+
import { BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardPointSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardDocument, parseBoardItemLoose, unknownRealType, withResolvedConnections } from "../protocol/dist/board-document.js";
|
|
4
6
|
import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
|
|
5
7
|
import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
|
|
6
8
|
import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, VIEWPORT_MARGIN_RATIO, angleFromCenter, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
|
|
7
9
|
import { boardImageKeySource, imageAssetKey } from "./image-key.js";
|
|
8
|
-
import {
|
|
10
|
+
import { arrowBounds, arrowFrame, distanceToArrow, resolveArrow, sampleArrow, translateArrow } from "./core/arrow-geometry.js";
|
|
11
|
+
import { CONNECTION_ENDPOINT_GAP, anchorPointOnFrame, anchorToWorld, autoConnectionSide, connectionArrowheads, connectionBounds, connectionHitTest, createConnectionIndex, distanceToConnection, pathMidpoint, resolveConnection, worldToAnchor } from "./core/connections.js";
|
|
9
12
|
import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
|
|
10
13
|
import { BOARD_EXPORT_MAX_TEXTURES, selectBoardExportAssets } from "./core/export-assets.js";
|
|
11
|
-
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
14
|
+
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, boardFrameLookup, exportConnectionBounds, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
12
15
|
import { FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
|
|
13
16
|
import { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
|
|
14
17
|
import { FULL_CAPABILITIES, GEO_KINDS, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
|
|
15
18
|
import { definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
|
|
16
|
-
import {
|
|
17
|
-
export {
|
|
19
|
+
import { DEFAULT_BOARD_TOOL_STYLES, createBoardToolStyles } from "./core/tool-styles.js";
|
|
20
|
+
export { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_COLORS, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearanceSchema, BoardArrowItemSchema, BoardConnectionAnchorSchema, BoardConnectionEndpointSchema, BoardConnectionPatchSchema, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardExtensionRegistry, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardPointSchema, BoardRelationSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, CONNECTION_ENDPOINT_GAP, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_RELATION, DEFAULT_BOARD_TOOL_STYLES, DrawPointSchema, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, GEO_KINDS, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, ITEM_BASE_KEYS, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, anchorPointOnFrame, anchorToWorld, angleFromCenter, arrowBounds, arrowFrame, autoConnectionSide, availabilityFromError, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, connectionArrowheads, connectionBounds, connectionHitTest, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, createBoardExtensionRegistry, createBoardToolStyles, createConnectionIndex, definitionForItem, degToRad, distanceToArrow, distanceToConnection, distanceToStroke, expandRect, exportConnectionBounds, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, flipBoardConnection, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardConnectionStyle, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardDocument, parseBoardItemLoose, parseBoardManifest, pathMidpoint, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveConnection, resolveCoverRef, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleArrow, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, withResolvedConnections, worldPoint, worldToAnchor, worldToScreen, zoomAround };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { BoardConnection } from "../../protocol/dist/board-connection.js";
|
|
2
|
+
import { BoardFrame } from "../../protocol/dist/board-document.js";
|
|
3
|
+
import { FrameLookup, ResolvedConnection } from "../core/connections.js";
|
|
4
|
+
import { BoardShapeColors } from "../core/palette.js";
|
|
5
|
+
import { Container } from "pixi.js";
|
|
6
|
+
//#region src/board/render/connection-layer.d.ts
|
|
7
|
+
type ConnectionRenderInput = {
|
|
8
|
+
connections: readonly BoardConnection[];
|
|
9
|
+
getFrame: FrameLookup;
|
|
10
|
+
colors: BoardShapeColors;
|
|
11
|
+
colorScheme: "dark" | "light";
|
|
12
|
+
zoom: number;
|
|
13
|
+
/** Connections drawn in their selected state. */
|
|
14
|
+
selectedIds?: ReadonlySet<string>;
|
|
15
|
+
/** Connection under the pointer, if any. */
|
|
16
|
+
hoveredId?: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Ids to skip because the host is drawing them itself this frame (e.g. a live
|
|
19
|
+
* drag preview on the interaction overlay). Skipping avoids the doubled stroke
|
|
20
|
+
* of a preview drawn over its own committed geometry.
|
|
21
|
+
*/
|
|
22
|
+
skipIds?: ReadonlySet<string>;
|
|
23
|
+
};
|
|
24
|
+
type ConnectionLayer = {
|
|
25
|
+
/** Redraw every connection. Cheap: one Graphics, batched. */
|
|
26
|
+
sync: (input: ConnectionRenderInput) => void;
|
|
27
|
+
/** Resolved geometry from the last sync, for hit testing and overlays. */
|
|
28
|
+
resolved: (connectionId: string) => ResolvedConnection | null;
|
|
29
|
+
/**
|
|
30
|
+
* The display objects this layer owns, so a host can place them in its own
|
|
31
|
+
* z-ordering scheme without the layer needing to know about it.
|
|
32
|
+
*/
|
|
33
|
+
readonly children: readonly Container[];
|
|
34
|
+
destroy: () => void;
|
|
35
|
+
};
|
|
36
|
+
declare function createConnectionLayer(options: {
|
|
37
|
+
/** World-space container the layer attaches to. */
|
|
38
|
+
parent: Container;
|
|
39
|
+
/** zIndex applied to the layer's display objects once they exist. */
|
|
40
|
+
zIndex?: number;
|
|
41
|
+
}): ConnectionLayer;
|
|
42
|
+
/** Frame lookup over a plain item list, for hosts without an index. */
|
|
43
|
+
declare function framesFromItems(items: readonly {
|
|
44
|
+
id: string;
|
|
45
|
+
frame: BoardFrame;
|
|
46
|
+
}[]): FrameLookup;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems };
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { BOARD_FONT_STACK } from "../../protocol/dist/board-constants.js";
|
|
2
|
+
import { connectionArrowheads, resolveConnection } from "../core/connections.js";
|
|
3
|
+
import { pickBoardColor } from "../core/palette.js";
|
|
4
|
+
import { syncTextResolution, textResolutionForZoom } from "./text-resolution.js";
|
|
5
|
+
import { Container, Graphics, Text } from "pixi.js";
|
|
6
|
+
//#region src/board/render/connection-layer.ts
|
|
7
|
+
/**
|
|
8
|
+
* Connection drawing.
|
|
9
|
+
*
|
|
10
|
+
* Connections render into one shared layer beneath the cards rather than as a
|
|
11
|
+
* container per relation. A connection is a thin stroke with no texture and no
|
|
12
|
+
* interactive chrome of its own, so a per-connection container would add a
|
|
13
|
+
* transform, a render group and a draw call each for geometry that batches
|
|
14
|
+
* perfectly — on a densely connected board that is the difference between a few
|
|
15
|
+
* draw calls and a few thousand.
|
|
16
|
+
*
|
|
17
|
+
* Labels are the exception: text needs its own object to rasterise, so a `Text`
|
|
18
|
+
* is materialised only for connections that actually carry one and is pooled by
|
|
19
|
+
* connection id.
|
|
20
|
+
*/
|
|
21
|
+
/** Arrowhead length relative to stroke width, and its floor in world units. */
|
|
22
|
+
const HEAD_SCALE = 5.5;
|
|
23
|
+
const HEAD_MIN = 11;
|
|
24
|
+
const HEAD_SPREAD = Math.PI / 6;
|
|
25
|
+
/** Dash pattern for `dashed` connections, in world units. */
|
|
26
|
+
const DASH_LENGTH = 10;
|
|
27
|
+
const DASH_GAP = 7;
|
|
28
|
+
/** Draw an open chevron arrowhead aimed along `angle`. */
|
|
29
|
+
function drawArrowhead(graphics, tip, angle, size, color, width, alpha) {
|
|
30
|
+
graphics.moveTo(tip.x - size * Math.cos(angle - HEAD_SPREAD), tip.y - size * Math.sin(angle - HEAD_SPREAD)).lineTo(tip.x, tip.y).lineTo(tip.x - size * Math.cos(angle + HEAD_SPREAD), tip.y - size * Math.sin(angle + HEAD_SPREAD)).stroke({
|
|
31
|
+
color,
|
|
32
|
+
width,
|
|
33
|
+
alpha,
|
|
34
|
+
cap: "round",
|
|
35
|
+
join: "round"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Trace a polyline as a dashed path, walking segment by segment. */
|
|
39
|
+
function traceDashed(graphics, path) {
|
|
40
|
+
let penDown = true;
|
|
41
|
+
let remaining = DASH_LENGTH;
|
|
42
|
+
let current = path[0];
|
|
43
|
+
if (!current) return;
|
|
44
|
+
graphics.moveTo(current.x, current.y);
|
|
45
|
+
for (let index = 1; index < path.length; index += 1) {
|
|
46
|
+
const next = path[index];
|
|
47
|
+
if (!next) continue;
|
|
48
|
+
let segmentRemaining = Math.hypot(next.x - current.x, next.y - current.y);
|
|
49
|
+
let from = current;
|
|
50
|
+
while (segmentRemaining > 1e-4) {
|
|
51
|
+
const step = Math.min(segmentRemaining, remaining);
|
|
52
|
+
const ratio = step / segmentRemaining;
|
|
53
|
+
const to = {
|
|
54
|
+
x: from.x + (next.x - from.x) * ratio,
|
|
55
|
+
y: from.y + (next.y - from.y) * ratio
|
|
56
|
+
};
|
|
57
|
+
if (penDown) graphics.lineTo(to.x, to.y);
|
|
58
|
+
else graphics.moveTo(to.x, to.y);
|
|
59
|
+
remaining -= step;
|
|
60
|
+
segmentRemaining -= step;
|
|
61
|
+
from = to;
|
|
62
|
+
if (remaining <= 1e-4) {
|
|
63
|
+
penDown = !penDown;
|
|
64
|
+
remaining = penDown ? DASH_LENGTH : DASH_GAP;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
current = next;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function createConnectionLayer(options) {
|
|
71
|
+
let graphics = null;
|
|
72
|
+
let labelLayer = null;
|
|
73
|
+
const labels = /* @__PURE__ */ new Map();
|
|
74
|
+
let resolvedById = /* @__PURE__ */ new Map();
|
|
75
|
+
function ensureAttached() {
|
|
76
|
+
if (graphics && labelLayer) return {
|
|
77
|
+
graphics,
|
|
78
|
+
labelLayer
|
|
79
|
+
};
|
|
80
|
+
const nextGraphics = new Graphics({ label: "board-connections" });
|
|
81
|
+
const nextLabels = new Container({ label: "board-connection-labels" });
|
|
82
|
+
if (options.zIndex !== void 0) {
|
|
83
|
+
nextGraphics.zIndex = options.zIndex;
|
|
84
|
+
nextLabels.zIndex = options.zIndex;
|
|
85
|
+
}
|
|
86
|
+
options.parent.addChild(nextGraphics, nextLabels);
|
|
87
|
+
graphics = nextGraphics;
|
|
88
|
+
labelLayer = nextLabels;
|
|
89
|
+
return {
|
|
90
|
+
graphics: nextGraphics,
|
|
91
|
+
labelLayer: nextLabels
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function releaseLabel(connectionId) {
|
|
95
|
+
const entry = labels.get(connectionId);
|
|
96
|
+
if (!entry) return;
|
|
97
|
+
labelLayer?.removeChild(entry.text);
|
|
98
|
+
entry.text.destroy();
|
|
99
|
+
labels.delete(connectionId);
|
|
100
|
+
}
|
|
101
|
+
function syncLabel(connection, resolved, input, color, host) {
|
|
102
|
+
const value = connection.label.trim();
|
|
103
|
+
if (!value) {
|
|
104
|
+
releaseLabel(connection.id);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let entry = labels.get(connection.id);
|
|
108
|
+
if (!entry) {
|
|
109
|
+
const resolution = textResolutionForZoom(input.zoom);
|
|
110
|
+
const text = new Text({
|
|
111
|
+
text: value,
|
|
112
|
+
style: {
|
|
113
|
+
fill: color,
|
|
114
|
+
fontFamily: BOARD_FONT_STACK,
|
|
115
|
+
fontSize: 12,
|
|
116
|
+
fontWeight: "500"
|
|
117
|
+
},
|
|
118
|
+
resolution,
|
|
119
|
+
roundPixels: true
|
|
120
|
+
});
|
|
121
|
+
text.anchor.set(.5);
|
|
122
|
+
host.addChild(text);
|
|
123
|
+
entry = {
|
|
124
|
+
text,
|
|
125
|
+
resolution,
|
|
126
|
+
sig: ""
|
|
127
|
+
};
|
|
128
|
+
labels.set(connection.id, entry);
|
|
129
|
+
}
|
|
130
|
+
syncTextResolution(entry.text, entry, input.zoom);
|
|
131
|
+
const sig = `${value}|${color}`;
|
|
132
|
+
if (sig !== entry.sig) {
|
|
133
|
+
entry.sig = sig;
|
|
134
|
+
entry.text.text = value;
|
|
135
|
+
entry.text.style.fill = color;
|
|
136
|
+
}
|
|
137
|
+
entry.text.position.set(resolved.mid.x, resolved.mid.y);
|
|
138
|
+
}
|
|
139
|
+
function sync(input) {
|
|
140
|
+
if (input.connections.length === 0 && !graphics) {
|
|
141
|
+
resolvedById = /* @__PURE__ */ new Map();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const host = ensureAttached();
|
|
145
|
+
host.graphics.clear();
|
|
146
|
+
const next = /* @__PURE__ */ new Map();
|
|
147
|
+
const selected = input.selectedIds ?? /* @__PURE__ */ new Set();
|
|
148
|
+
const skip = input.skipIds;
|
|
149
|
+
const minWidth = 1 / Math.max(input.zoom, 1e-4);
|
|
150
|
+
for (const connection of input.connections) {
|
|
151
|
+
const resolved = resolveConnection(connection, input.getFrame);
|
|
152
|
+
if (!resolved) continue;
|
|
153
|
+
next.set(connection.id, resolved);
|
|
154
|
+
if (skip?.has(connection.id)) {
|
|
155
|
+
releaseLabel(connection.id);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const isSelected = selected.has(connection.id);
|
|
159
|
+
const isHovered = input.hoveredId === connection.id;
|
|
160
|
+
const color = pickBoardColor(input.colors, connection.style.color, input.colorScheme);
|
|
161
|
+
const width = Math.max(connection.style.size + (isSelected ? 1 : 0), minWidth);
|
|
162
|
+
const alpha = isSelected || isHovered ? 1 : .9;
|
|
163
|
+
if (connection.style.line === "dashed") traceDashed(host.graphics, resolved.path);
|
|
164
|
+
else {
|
|
165
|
+
const first = resolved.path[0];
|
|
166
|
+
if (!first) continue;
|
|
167
|
+
host.graphics.moveTo(first.x, first.y);
|
|
168
|
+
for (let index = 1; index < resolved.path.length; index += 1) {
|
|
169
|
+
const point = resolved.path[index];
|
|
170
|
+
if (point) host.graphics.lineTo(point.x, point.y);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
host.graphics.stroke({
|
|
174
|
+
color: color.stroke,
|
|
175
|
+
width,
|
|
176
|
+
alpha,
|
|
177
|
+
cap: "round",
|
|
178
|
+
join: "round"
|
|
179
|
+
});
|
|
180
|
+
const heads = connectionArrowheads(connection);
|
|
181
|
+
const headSize = Math.max(HEAD_MIN, connection.style.size * HEAD_SCALE);
|
|
182
|
+
if (heads.atTarget) {
|
|
183
|
+
const tip = resolved.path[resolved.path.length - 1];
|
|
184
|
+
const previous = resolved.path[resolved.path.length - 2];
|
|
185
|
+
if (tip && previous) drawArrowhead(host.graphics, tip, Math.atan2(tip.y - previous.y, tip.x - previous.x), headSize, color.stroke, width, alpha);
|
|
186
|
+
}
|
|
187
|
+
if (heads.atSource) {
|
|
188
|
+
const tip = resolved.path[0];
|
|
189
|
+
const next2 = resolved.path[1];
|
|
190
|
+
if (tip && next2) drawArrowhead(host.graphics, tip, Math.atan2(tip.y - next2.y, tip.x - next2.x), headSize, color.stroke, width, alpha);
|
|
191
|
+
}
|
|
192
|
+
syncLabel(connection, resolved, input, color.label, host.labelLayer);
|
|
193
|
+
}
|
|
194
|
+
for (const connectionId of [...labels.keys()]) if (!next.has(connectionId)) releaseLabel(connectionId);
|
|
195
|
+
resolvedById = next;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
sync,
|
|
199
|
+
resolved: (connectionId) => resolvedById.get(connectionId) ?? null,
|
|
200
|
+
get children() {
|
|
201
|
+
const list = [];
|
|
202
|
+
if (graphics) list.push(graphics);
|
|
203
|
+
if (labelLayer) list.push(labelLayer);
|
|
204
|
+
return list;
|
|
205
|
+
},
|
|
206
|
+
destroy: () => {
|
|
207
|
+
for (const entry of labels.values()) entry.text.destroy();
|
|
208
|
+
labels.clear();
|
|
209
|
+
graphics?.destroy();
|
|
210
|
+
labelLayer?.destroy({ children: true });
|
|
211
|
+
graphics = null;
|
|
212
|
+
labelLayer = null;
|
|
213
|
+
resolvedById = /* @__PURE__ */ new Map();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/** Frame lookup over a plain item list, for hosts without an index. */
|
|
218
|
+
function framesFromItems(items) {
|
|
219
|
+
const frames = new Map(items.map((item) => [item.id, item.frame]));
|
|
220
|
+
return (id) => frames.get(id);
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
export { createConnectionLayer, framesFromItems };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems } from "./connection-layer.js";
|
|
1
2
|
import { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
2
3
|
import { defaultBoardPalette } from "./palette.js";
|
|
3
4
|
import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
4
5
|
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
5
6
|
import { BoardThemeContext, BoardThemeRenderer, getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
|
|
6
|
-
export { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardThemeContext, BoardThemeRenderer, boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
7
|
+
export { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardThemeContext, BoardThemeRenderer, ConnectionLayer, ConnectionRenderInput, boardCardRenderersForTest, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
2
|
+
import { createConnectionLayer, framesFromItems } from "./connection-layer.js";
|
|
1
3
|
import { defaultBoardPalette } from "./palette.js";
|
|
2
4
|
import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
3
|
-
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
4
5
|
import { boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
5
6
|
import { getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
|
|
6
|
-
export { boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
7
|
+
export { boardCardRenderersForTest, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
-
import { resolveArrow,
|
|
2
|
+
import { resolveArrow, sampleArrow } from "../../core/arrow-geometry.js";
|
|
3
3
|
import { pickBoardColor } from "../../core/palette.js";
|
|
4
4
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
5
|
import { drawFarStroke } from "./far-plate.js";
|
|
6
6
|
import { Container, Graphics, Text } from "pixi.js";
|
|
7
7
|
//#region src/board/render/renderers/arrow-card-renderer.ts
|
|
8
8
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
/**
|
|
10
|
-
* Frame lookup for resolving bindings.
|
|
11
|
-
*
|
|
12
|
-
* Routed through the context's id index rather than scanning the document: an
|
|
13
|
-
* arrow re-resolves its endpoints on every sync, and a per-arrow O(items) scan
|
|
14
|
-
* would make a board with many arrows quadratic per frame.
|
|
15
|
-
*/
|
|
16
|
-
function frameLookup(context) {
|
|
17
|
-
return (id) => context.getItem(id)?.frame;
|
|
18
|
-
}
|
|
19
9
|
/** Open chevron arrowhead — clearly directional, not a tiny filled nub. */
|
|
20
10
|
function drawArrowhead(graphics, tip, angle, size, color, strokeWidth) {
|
|
21
11
|
const spread = Math.PI / 6;
|
|
@@ -44,8 +34,8 @@ function sync(container, item, context) {
|
|
|
44
34
|
const hovered = context.hoveredId === item.id;
|
|
45
35
|
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
46
36
|
syncTextResolution(parts.label, parts, context.zoom);
|
|
47
|
-
const resolved = resolveArrow(item
|
|
48
|
-
const lineSig =
|
|
37
|
+
const resolved = resolveArrow(item);
|
|
38
|
+
const lineSig = [
|
|
49
39
|
resolved.start.x,
|
|
50
40
|
resolved.start.y,
|
|
51
41
|
resolved.end.x,
|
|
@@ -58,39 +48,37 @@ function sync(container, item, context) {
|
|
|
58
48
|
item.size,
|
|
59
49
|
item.arrowStart,
|
|
60
50
|
item.arrowEnd
|
|
61
|
-
].join("|")
|
|
51
|
+
].join("|");
|
|
62
52
|
if (lineSig !== parts.lineSig) {
|
|
63
53
|
parts.lineSig = lineSig;
|
|
64
54
|
parts.line.clear();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (next) drawArrowhead(parts.line, head, Math.atan2(head.y - next.y, head.x - next.x), headSize, strokeColor, width);
|
|
93
|
-
}
|
|
55
|
+
const strokeColor = color.stroke;
|
|
56
|
+
const width = selected ? item.size + 1 : item.size;
|
|
57
|
+
const samples = sampleArrow(resolved, 24);
|
|
58
|
+
const head = samples[0];
|
|
59
|
+
const tail = samples[samples.length - 1];
|
|
60
|
+
if (head && tail) {
|
|
61
|
+
parts.line.moveTo(head.x, head.y);
|
|
62
|
+
for (let i = 1; i < samples.length; i += 1) {
|
|
63
|
+
const point = samples[i];
|
|
64
|
+
if (point) parts.line.lineTo(point.x, point.y);
|
|
65
|
+
}
|
|
66
|
+
parts.line.stroke({
|
|
67
|
+
color: strokeColor,
|
|
68
|
+
width,
|
|
69
|
+
alpha: selected || hovered ? 1 : .92,
|
|
70
|
+
cap: "round",
|
|
71
|
+
join: "round"
|
|
72
|
+
});
|
|
73
|
+
const span = Math.hypot(tail.x - head.x, tail.y - head.y);
|
|
74
|
+
const headSize = Math.min(Math.max(14, item.size * 5.5), Math.max(10, span * .28));
|
|
75
|
+
if (item.arrowEnd) {
|
|
76
|
+
const prev = samples[samples.length - 2];
|
|
77
|
+
if (prev) drawArrowhead(parts.line, tail, Math.atan2(tail.y - prev.y, tail.x - prev.x), headSize, strokeColor, width);
|
|
78
|
+
}
|
|
79
|
+
if (item.arrowStart) {
|
|
80
|
+
const next = samples[1];
|
|
81
|
+
if (next) drawArrowhead(parts.line, head, Math.atan2(head.y - next.y, head.x - next.x), headSize, strokeColor, width);
|
|
94
82
|
}
|
|
95
83
|
}
|
|
96
84
|
}
|
|
@@ -100,8 +88,8 @@ function sync(container, item, context) {
|
|
|
100
88
|
parts.label.text = item.label;
|
|
101
89
|
parts.label.style.fill = color.label;
|
|
102
90
|
}
|
|
103
|
-
parts.label.visible =
|
|
104
|
-
|
|
91
|
+
parts.label.visible = item.label.length > 0;
|
|
92
|
+
parts.label.position.copyFrom(resolved.control);
|
|
105
93
|
}
|
|
106
94
|
const arrowCardRenderer = {
|
|
107
95
|
id: "arrow-card",
|
|
@@ -139,10 +127,9 @@ const arrowCardRenderer = {
|
|
|
139
127
|
},
|
|
140
128
|
renderFar: (graphics, item, context) => {
|
|
141
129
|
if (item.type !== "arrow") return;
|
|
142
|
-
const resolved = resolveArrow(item
|
|
143
|
-
if (!resolved) return;
|
|
130
|
+
const resolved = resolveArrow(item);
|
|
144
131
|
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
145
|
-
drawFarStroke(graphics,
|
|
132
|
+
drawFarStroke(graphics, sampleArrow(resolved, 12), {
|
|
146
133
|
color: color.stroke,
|
|
147
134
|
width: item.size,
|
|
148
135
|
alpha: .85
|