@yuzhouu/canvas-kit 0.1.2

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.
Files changed (263) hide show
  1. package/README.md +145 -0
  2. package/_vendor/canvas-core/bindings/BindingUtil.ts +92 -0
  3. package/_vendor/canvas-core/bindings/BindingUtilRegistry.ts +22 -0
  4. package/_vendor/canvas-core/bindings/arrow/arrowBindingHelpers.ts +52 -0
  5. package/_vendor/canvas-core/contextMenu.ts +85 -0
  6. package/_vendor/canvas-core/editor/Editor.ts +2614 -0
  7. package/_vendor/canvas-core/editor/HistoryManager.ts +83 -0
  8. package/_vendor/canvas-core/editor/StateNode.ts +162 -0
  9. package/_vendor/canvas-core/editor/camera.ts +6 -0
  10. package/_vendor/canvas-core/editor/clipboard.ts +478 -0
  11. package/_vendor/canvas-core/editor/commands.ts +833 -0
  12. package/_vendor/canvas-core/editor/edgeScroll.ts +37 -0
  13. package/_vendor/canvas-core/editor/editorComputedHelpers.ts +257 -0
  14. package/_vendor/canvas-core/editor/editorSelectionTransforms.ts +116 -0
  15. package/_vendor/canvas-core/editor/events.ts +93 -0
  16. package/_vendor/canvas-core/editor/index.ts +12 -0
  17. package/_vendor/canvas-core/editor/interactions.ts +101 -0
  18. package/_vendor/canvas-core/editor/internal.ts +22 -0
  19. package/_vendor/canvas-core/editor/managers/BindingManager.ts +262 -0
  20. package/_vendor/canvas-core/editor/managers/CameraManager.ts +147 -0
  21. package/_vendor/canvas-core/editor/managers/ClipboardManager.ts +32 -0
  22. package/_vendor/canvas-core/editor/managers/DocumentSnapshotManager.ts +256 -0
  23. package/_vendor/canvas-core/editor/managers/InputsManager.ts +319 -0
  24. package/_vendor/canvas-core/editor/managers/InteractionTransientManager.ts +218 -0
  25. package/_vendor/canvas-core/editor/managers/QueryManager.ts +837 -0
  26. package/_vendor/canvas-core/editor/managers/RenderWindowManager.ts +347 -0
  27. package/_vendor/canvas-core/editor/managers/SelectionLayoutManager.ts +196 -0
  28. package/_vendor/canvas-core/editor/managers/SelectionManager.ts +98 -0
  29. package/_vendor/canvas-core/editor/managers/SelectionOverlayManager.ts +308 -0
  30. package/_vendor/canvas-core/editor/managers/ShapeEditingManager.ts +226 -0
  31. package/_vendor/canvas-core/editor/managers/ShapeGeometryManager.ts +162 -0
  32. package/_vendor/canvas-core/editor/managers/ShapeHierarchyManager.ts +797 -0
  33. package/_vendor/canvas-core/editor/managers/SideEffectManager.ts +83 -0
  34. package/_vendor/canvas-core/editor/managers/SnapManager.ts +433 -0
  35. package/_vendor/canvas-core/editor/managers/SnapSnapshotBuilder.ts +430 -0
  36. package/_vendor/canvas-core/editor/managers/SpatialIndexManager.ts +354 -0
  37. package/_vendor/canvas-core/editor/managers/ToolManager.ts +81 -0
  38. package/_vendor/canvas-core/editor/managers/queryState.ts +583 -0
  39. package/_vendor/canvas-core/editor/managers/selectionGeometry.ts +287 -0
  40. package/_vendor/canvas-core/editor/managers/shapeOrder.ts +350 -0
  41. package/_vendor/canvas-core/editor/managers/shapeReparenting.ts +160 -0
  42. package/_vendor/canvas-core/editor/managers/snapCalculations.ts +412 -0
  43. package/_vendor/canvas-core/editor/managers/snapGeometry.ts +202 -0
  44. package/_vendor/canvas-core/editor/managers/snapIndicators.ts +403 -0
  45. package/_vendor/canvas-core/editor/managers/snapTypes.ts +122 -0
  46. package/_vendor/canvas-core/editor/queries/shapeTransforms.ts +171 -0
  47. package/_vendor/canvas-core/editor/renderWindow.ts +439 -0
  48. package/_vendor/canvas-core/editor/resizeGeometry.ts +654 -0
  49. package/_vendor/canvas-core/editor/selection.ts +489 -0
  50. package/_vendor/canvas-core/editor/selectionHandleInteractions.ts +43 -0
  51. package/_vendor/canvas-core/editor/selectionOverlay.ts +567 -0
  52. package/_vendor/canvas-core/exports/integrity.ts +174 -0
  53. package/_vendor/canvas-core/exports/svg.ts +494 -0
  54. package/_vendor/canvas-core/geometry/Box.ts +80 -0
  55. package/_vendor/canvas-core/geometry/Ellipse2d.ts +67 -0
  56. package/_vendor/canvas-core/geometry/Geometry2d.ts +52 -0
  57. package/_vendor/canvas-core/geometry/Mat.ts +92 -0
  58. package/_vendor/canvas-core/geometry/Polyline2d.ts +63 -0
  59. package/_vendor/canvas-core/geometry/Rectangle2d.ts +64 -0
  60. package/_vendor/canvas-core/geometry/Vec.ts +123 -0
  61. package/_vendor/canvas-core/geometry/index.ts +13 -0
  62. package/_vendor/canvas-core/geometry/segments.ts +65 -0
  63. package/_vendor/canvas-core/index.ts +391 -0
  64. package/_vendor/canvas-core/plugins/index.ts +5 -0
  65. package/_vendor/canvas-core/plugins/types.ts +53 -0
  66. package/_vendor/canvas-core/reactivity.ts +16 -0
  67. package/_vendor/canvas-core/schema/records.ts +221 -0
  68. package/_vendor/canvas-core/schema/snapshots.ts +527 -0
  69. package/_vendor/canvas-core/shapes/ShapeUtil.ts +516 -0
  70. package/_vendor/canvas-core/shapes/ShapeUtilRegistry.ts +26 -0
  71. package/_vendor/canvas-core/shapes/capabilities.ts +67 -0
  72. package/_vendor/canvas-core/shapes/types.ts +20 -0
  73. package/_vendor/canvas-core/toolbar.ts +148 -0
  74. package/_vendor/canvas-core/tools/hand/HandTool.ts +75 -0
  75. package/_vendor/canvas-core/tools/index.ts +2 -0
  76. package/_vendor/canvas-core/tools/select/SelectTool.ts +33 -0
  77. package/_vendor/canvas-core/tools/select/selectContainment.ts +104 -0
  78. package/_vendor/canvas-core/tools/select/selectToolHelpers.ts +801 -0
  79. package/_vendor/canvas-core/tools/select/states/BrushingState.ts +145 -0
  80. package/_vendor/canvas-core/tools/select/states/DraggingSelectionHandleInteractionState.ts +116 -0
  81. package/_vendor/canvas-core/tools/select/states/IdleState.ts +159 -0
  82. package/_vendor/canvas-core/tools/select/states/PointingCanvasState.ts +41 -0
  83. package/_vendor/canvas-core/tools/select/states/PointingResizeHandleState.ts +78 -0
  84. package/_vendor/canvas-core/tools/select/states/PointingRotateHandleState.ts +64 -0
  85. package/_vendor/canvas-core/tools/select/states/PointingSelectionHandleInteractionState.ts +34 -0
  86. package/_vendor/canvas-core/tools/select/states/PointingShapeState.ts +140 -0
  87. package/_vendor/canvas-core/tools/select/states/ResizingState.ts +171 -0
  88. package/_vendor/canvas-core/tools/select/states/RotatingState.ts +124 -0
  89. package/_vendor/canvas-core/tools/select/states/SelectStateNode.ts +128 -0
  90. package/_vendor/canvas-core/tools/select/states/TranslatingState.ts +139 -0
  91. package/_vendor/canvas-core/tools/select/states/index.ts +11 -0
  92. package/_vendor/canvas-plugin-api/feature.ts +204 -0
  93. package/_vendor/canvas-plugin-api/index.ts +142 -0
  94. package/_vendor/canvas-product-react/api/apiRegistry.ts +35 -0
  95. package/_vendor/canvas-product-react/api/canvasProductApi.ts +422 -0
  96. package/_vendor/canvas-product-react/api/index.ts +31 -0
  97. package/_vendor/canvas-product-react/capabilities/clipboard/clipboardService.ts +36 -0
  98. package/_vendor/canvas-product-react/capabilities/clipboard/systemClipboard.ts +245 -0
  99. package/_vendor/canvas-product-react/capabilities/context-menu/systemContextMenu.ts +396 -0
  100. package/_vendor/canvas-product-react/capabilities/context-menu/useContextMenuSurface.ts +59 -0
  101. package/_vendor/canvas-product-react/capabilities/export/useSvgExport.ts +156 -0
  102. package/_vendor/canvas-product-react/capabilities/history/useHistoryControls.ts +23 -0
  103. package/_vendor/canvas-product-react/capabilities/pages/usePageControls.ts +41 -0
  104. package/_vendor/canvas-product-react/capabilities/toolbar/systemToolbar.ts +490 -0
  105. package/_vendor/canvas-product-react/capabilities/toolbar/useToolbarSurfaces.ts +92 -0
  106. package/_vendor/canvas-product-react/capabilities/zoom/useZoomControls.ts +27 -0
  107. package/_vendor/canvas-product-react/index.ts +84 -0
  108. package/_vendor/canvas-product-react/persistence/index.ts +18 -0
  109. package/_vendor/canvas-product-react/persistence/localSnapshotPersistence.ts +294 -0
  110. package/_vendor/canvas-product-react/runtime/CanvasProductRoot.tsx +250 -0
  111. package/_vendor/canvas-product-react/runtime/productDefinition.ts +72 -0
  112. package/_vendor/canvas-product-react/runtime/productServices.ts +96 -0
  113. package/_vendor/canvas-react/components/CanvasView.tsx +796 -0
  114. package/_vendor/canvas-react/components/OverlayLayer.tsx +879 -0
  115. package/_vendor/canvas-react/components/PageSpace.tsx +34 -0
  116. package/_vendor/canvas-react/components/ShapeLayer.tsx +428 -0
  117. package/_vendor/canvas-react/components/index.ts +4 -0
  118. package/_vendor/canvas-react/hooks/useEditor.ts +11 -0
  119. package/_vendor/canvas-react/hooks/useValue.ts +14 -0
  120. package/_vendor/canvas-react/host/CanvasRendererRegistryContext.tsx +14 -0
  121. package/_vendor/canvas-react/host/contextMenuRegistry.ts +61 -0
  122. package/_vendor/canvas-react/host/domEventGuards.ts +61 -0
  123. package/_vendor/canvas-react/host/index.ts +38 -0
  124. package/_vendor/canvas-react/host/pluginHost.ts +635 -0
  125. package/_vendor/canvas-react/host/rendererRegistry.tsx +58 -0
  126. package/_vendor/canvas-react/host/toolbarRegistry.ts +100 -0
  127. package/_vendor/canvas-react/index.ts +3 -0
  128. package/_vendor/plugin-arrow/ArrowBindingUtil.ts +239 -0
  129. package/_vendor/plugin-arrow/ArrowShapeUtil.ts +311 -0
  130. package/_vendor/plugin-arrow/ArrowTool.ts +208 -0
  131. package/_vendor/plugin-arrow/arrowGeometry.ts +441 -0
  132. package/_vendor/plugin-arrow/arrowTerminalBindingResolver.ts +253 -0
  133. package/_vendor/plugin-arrow/arrowTerminalCommands.ts +230 -0
  134. package/_vendor/plugin-arrow/canvas.tsx +92 -0
  135. package/_vendor/plugin-arrow/core.ts +409 -0
  136. package/_vendor/plugin-arrow/feature.ts +20 -0
  137. package/_vendor/plugin-arrow/index.ts +28 -0
  138. package/_vendor/plugin-arrow/selectionHandleInteractions.ts +154 -0
  139. package/_vendor/plugin-arrow/types.ts +63 -0
  140. package/_vendor/plugin-draw/DrawShapeRenderer.tsx +60 -0
  141. package/_vendor/plugin-draw/DrawShapeUtil.ts +372 -0
  142. package/_vendor/plugin-draw/DrawTool.ts +444 -0
  143. package/_vendor/plugin-draw/canvas.tsx +24 -0
  144. package/_vendor/plugin-draw/core.ts +515 -0
  145. package/_vendor/plugin-draw/drawGeometry.ts +491 -0
  146. package/_vendor/plugin-draw/drawHitTest.ts +271 -0
  147. package/_vendor/plugin-draw/drawInterpolation.ts +250 -0
  148. package/_vendor/plugin-draw/drawPath.ts +550 -0
  149. package/_vendor/plugin-draw/drawSegments.ts +106 -0
  150. package/_vendor/plugin-draw/drawSelectionTransform.ts +67 -0
  151. package/_vendor/plugin-draw/drawShapeGeometry.ts +307 -0
  152. package/_vendor/plugin-draw/drawStrokeGeometry.ts +454 -0
  153. package/_vendor/plugin-draw/feature.ts +20 -0
  154. package/_vendor/plugin-draw/index.ts +31 -0
  155. package/_vendor/plugin-draw/types.ts +36 -0
  156. package/_vendor/plugin-eraser/EraserTool.ts +297 -0
  157. package/_vendor/plugin-eraser/canvas.tsx +616 -0
  158. package/_vendor/plugin-eraser/core.ts +49 -0
  159. package/_vendor/plugin-eraser/feature.ts +20 -0
  160. package/_vendor/plugin-eraser/index.ts +4 -0
  161. package/_vendor/plugin-frame/FrameShapeUtil.ts +173 -0
  162. package/_vendor/plugin-frame/FrameTool.ts +225 -0
  163. package/_vendor/plugin-frame/canvas.tsx +75 -0
  164. package/_vendor/plugin-frame/core.ts +534 -0
  165. package/_vendor/plugin-frame/feature.ts +20 -0
  166. package/_vendor/plugin-frame/index.ts +6 -0
  167. package/_vendor/plugin-geo/GeoShapeUtil.ts +463 -0
  168. package/_vendor/plugin-geo/GeoTools.ts +247 -0
  169. package/_vendor/plugin-geo/canvas.tsx +90 -0
  170. package/_vendor/plugin-geo/core.ts +495 -0
  171. package/_vendor/plugin-geo/feature.ts +20 -0
  172. package/_vendor/plugin-geo/index.ts +7 -0
  173. package/_vendor/plugin-geo/types.ts +27 -0
  174. package/_vendor/plugin-group/GroupShapeUtil.ts +59 -0
  175. package/_vendor/plugin-group/canvas.tsx +59 -0
  176. package/_vendor/plugin-group/core.ts +40 -0
  177. package/_vendor/plugin-group/feature.ts +20 -0
  178. package/_vendor/plugin-group/index.ts +5 -0
  179. package/_vendor/plugin-image/ImageShapeUtil.ts +95 -0
  180. package/_vendor/plugin-image/canvas.tsx +212 -0
  181. package/_vendor/plugin-image/core.ts +542 -0
  182. package/_vendor/plugin-image/crop.ts +770 -0
  183. package/_vendor/plugin-image/cropInteractions.ts +350 -0
  184. package/_vendor/plugin-image/cropSession.ts +38 -0
  185. package/_vendor/plugin-image/feature.ts +20 -0
  186. package/_vendor/plugin-image/index.ts +29 -0
  187. package/_vendor/plugin-image/types.ts +55 -0
  188. package/_vendor/plugin-image-product-react/ImageImportController.tsx +143 -0
  189. package/_vendor/plugin-image-product-react/imageAssetService.ts +52 -0
  190. package/_vendor/plugin-image-product-react/imageBlobStore.ts +315 -0
  191. package/_vendor/plugin-image-product-react/imageHostActions.ts +438 -0
  192. package/_vendor/plugin-image-product-react/imageProductApi.ts +88 -0
  193. package/_vendor/plugin-image-product-react/imageToolbarHostBridge.ts +48 -0
  194. package/_vendor/plugin-image-product-react/imageToolbarRuntime.ts +21 -0
  195. package/_vendor/plugin-image-product-react/index.ts +60 -0
  196. package/_vendor/plugin-image-product-react/snapshotGuards.ts +33 -0
  197. package/_vendor/plugin-image-product-react/svgImageAssetInliner.ts +54 -0
  198. package/_vendor/plugin-image-product-react/useImageImport.ts +64 -0
  199. package/_vendor/plugin-laser/LaserTool.ts +154 -0
  200. package/_vendor/plugin-laser/canvas.tsx +645 -0
  201. package/_vendor/plugin-laser/core.ts +49 -0
  202. package/_vendor/plugin-laser/feature.ts +20 -0
  203. package/_vendor/plugin-laser/index.ts +4 -0
  204. package/_vendor/plugin-text/ArrowLabelBindingUtil.ts +336 -0
  205. package/_vendor/plugin-text/GeoLabelBindingUtil.ts +391 -0
  206. package/_vendor/plugin-text/TextShapeSvgExporter.ts +101 -0
  207. package/_vendor/plugin-text/TextShapeUtil.ts +284 -0
  208. package/_vendor/plugin-text/TextTool.ts +228 -0
  209. package/_vendor/plugin-text/canvas.tsx +115 -0
  210. package/_vendor/plugin-text/core.ts +422 -0
  211. package/_vendor/plugin-text/feature.ts +20 -0
  212. package/_vendor/plugin-text/host/RichTextEditingBox.tsx +144 -0
  213. package/_vendor/plugin-text/host/RichTextToolbar.tsx +266 -0
  214. package/_vendor/plugin-text/host/TiptapTextEditor.tsx +191 -0
  215. package/_vendor/plugin-text/host/richTextRendering.tsx +49 -0
  216. package/_vendor/plugin-text/host/textDomSelection.ts +93 -0
  217. package/_vendor/plugin-text/host/textEditingBoxStyle.ts +36 -0
  218. package/_vendor/plugin-text/host/textEntryFocus.ts +307 -0
  219. package/_vendor/plugin-text/host/textFontLoader.ts +149 -0
  220. package/_vendor/plugin-text/host/textMeasurement.ts +258 -0
  221. package/_vendor/plugin-text/host/textMeasurementSync.ts +77 -0
  222. package/_vendor/plugin-text/host/textRangeSelection.ts +134 -0
  223. package/_vendor/plugin-text/host/textShapeRendererRuntime.tsx +89 -0
  224. package/_vendor/plugin-text/host/textShapeSync.ts +173 -0
  225. package/_vendor/plugin-text/host/tiptapTextEditorController.ts +148 -0
  226. package/_vendor/plugin-text/index.ts +18 -0
  227. package/_vendor/plugin-text/richTextUtils.ts +259 -0
  228. package/_vendor/plugin-text/textInteractions.ts +366 -0
  229. package/_vendor/plugin-text/textLabelHelpers.ts +235 -0
  230. package/_vendor/plugin-text/textShapeHelpers.ts +123 -0
  231. package/_vendor/plugin-text/textStyle.ts +96 -0
  232. package/_vendor/plugin-text/textTypes.ts +48 -0
  233. package/_vendor/signals/atom.ts +74 -0
  234. package/_vendor/signals/computed.ts +132 -0
  235. package/_vendor/signals/core.ts +130 -0
  236. package/_vendor/signals/effect.ts +117 -0
  237. package/_vendor/signals/index.ts +9 -0
  238. package/_vendor/signals/types.ts +17 -0
  239. package/_vendor/store/Store.ts +171 -0
  240. package/_vendor/store/diff.ts +229 -0
  241. package/_vendor/store/history.ts +177 -0
  242. package/_vendor/store/index.ts +32 -0
  243. package/_vendor/store/types.ts +37 -0
  244. package/api/canvasKitApi.d.ts +29 -0
  245. package/index.css +3 -0
  246. package/index.d.ts +16 -0
  247. package/index.mjs +1 -0
  248. package/internal-modules.d.ts +187 -0
  249. package/package.json +48 -0
  250. package/product/Shell.d.ts +19 -0
  251. package/product/chromeContext.d.ts +70 -0
  252. package/product/createCanvasKitEditor.d.ts +6 -0
  253. package/product/index.d.ts +7 -0
  254. package/product/persistence.d.ts +3 -0
  255. package/product/product.d.ts +22 -0
  256. package/product/useCanvasClipboardShortcuts.d.ts +6 -0
  257. package/product-iyBbEPIs.mjs +4 -0
  258. package/product.mjs +1 -0
  259. package/standard/extensions.d.ts +1 -0
  260. package/standard/index.d.ts +3 -0
  261. package/standard/standardApi.d.ts +91 -0
  262. package/standard-BmrxwqpJ.mjs +44 -0
  263. package/standard.mjs +1 -0
@@ -0,0 +1,171 @@
1
+ import { Box } from "../../geometry/Box";
2
+ import { Mat } from "../../geometry/Mat";
3
+ import { Vec } from "../../geometry/Vec";
4
+ import type { ShapeRecord } from "../../schema/records";
5
+ import type { ShapeUtil } from "../../shapes/ShapeUtil";
6
+
7
+ export interface ShapeGeometry {
8
+ bounds: Box;
9
+ center: Vec;
10
+ corners: Vec[];
11
+ outlineVertices: Vec[];
12
+ }
13
+
14
+ export function getShapeLocalBounds<S extends ShapeRecord>(
15
+ shape: S,
16
+ util: ShapeUtil<S>,
17
+ ): Box {
18
+ return util.getLocalBounds(shape);
19
+ }
20
+
21
+ export function getShapeRenderBounds<S extends ShapeRecord>(
22
+ shape: S,
23
+ util: ShapeUtil<S>,
24
+ ): Box {
25
+ return util.getRenderBounds(shape);
26
+ }
27
+
28
+ export function getShapeExportBounds<S extends ShapeRecord>(
29
+ shape: S,
30
+ util: ShapeUtil<S>,
31
+ ): Box {
32
+ return util.getExportBounds(shape);
33
+ }
34
+
35
+ export function getShapeLocalToPageTransform<S extends ShapeRecord>(
36
+ shape: S,
37
+ util: ShapeUtil<S>,
38
+ ): Mat {
39
+ return util.getLocalToPageTransform(shape);
40
+ }
41
+
42
+ export function getShapePositionedToPageTransform<S extends ShapeRecord>(
43
+ shape: S,
44
+ util: ShapeUtil<S>,
45
+ ): Mat {
46
+ const center = getShapePageCenter(shape, util);
47
+ return Mat.Translate(center.x, center.y)
48
+ .compose(Mat.Rotate(shape.rotation))
49
+ .compose(Mat.Scale(shape.scaleX, shape.scaleY))
50
+ .compose(Mat.Translate(-center.x, -center.y));
51
+ }
52
+
53
+ export function getShapeRenderToPageTransform<S extends ShapeRecord>(
54
+ shape: S,
55
+ util: ShapeUtil<S>,
56
+ ): Mat {
57
+ return getShapeLocalToPageTransform(shape, util);
58
+ }
59
+
60
+ export function getShapeExportToPageTransform<S extends ShapeRecord>(
61
+ shape: S,
62
+ util: ShapeUtil<S>,
63
+ ): Mat {
64
+ return getShapeLocalToPageTransform(shape, util);
65
+ }
66
+
67
+ export function getShapePageCenter<S extends ShapeRecord>(
68
+ shape: S,
69
+ util: ShapeUtil<S>,
70
+ ): Vec {
71
+ return util.getBounds(shape).center;
72
+ }
73
+
74
+ export function positionedShapePointToPagePoint<S extends ShapeRecord>(
75
+ shape: S,
76
+ point: Vec,
77
+ util: ShapeUtil<S>,
78
+ ): Vec {
79
+ return getShapePositionedToPageTransform(shape, util).applyToPoint(point);
80
+ }
81
+
82
+ export function pagePointToShapePositionedPoint<S extends ShapeRecord>(
83
+ shape: S,
84
+ point: Vec,
85
+ util: ShapeUtil<S>,
86
+ ): Vec {
87
+ if (shape.scaleX === 0 || shape.scaleY === 0) {
88
+ const center = getShapePageCenter(shape, util);
89
+ const rotatedOffset = point.sub(center).rot(-shape.rotation);
90
+ return center.add(
91
+ new Vec(
92
+ shape.scaleX === 0 ? 0 : rotatedOffset.x / shape.scaleX,
93
+ shape.scaleY === 0 ? 0 : rotatedOffset.y / shape.scaleY,
94
+ ),
95
+ );
96
+ }
97
+ return getShapePositionedToPageTransform(shape, util)
98
+ .invert()
99
+ .applyToPoint(point);
100
+ }
101
+
102
+ export function getShapePositionedOutlineVertices<S extends ShapeRecord>(
103
+ shape: S,
104
+ util: ShapeUtil<S>,
105
+ ): Vec[] {
106
+ return util.getPositionedOutlineVertices(shape);
107
+ }
108
+
109
+ export function getShapePageCorners<S extends ShapeRecord>(
110
+ shape: S,
111
+ util: ShapeUtil<S>,
112
+ ): Vec[] {
113
+ const bounds = util.getBounds(shape);
114
+ const corners = [
115
+ new Vec(bounds.minX, bounds.minY),
116
+ new Vec(bounds.maxX, bounds.minY),
117
+ new Vec(bounds.maxX, bounds.maxY),
118
+ new Vec(bounds.minX, bounds.maxY),
119
+ ];
120
+
121
+ return corners.map((corner) =>
122
+ positionedShapePointToPagePoint(shape, corner, util),
123
+ );
124
+ }
125
+
126
+ export function getShapePageOutlineVertices<S extends ShapeRecord>(
127
+ shape: S,
128
+ util: ShapeUtil<S>,
129
+ ): Vec[] {
130
+ return getShapePositionedOutlineVertices(shape, util).map((point) =>
131
+ positionedShapePointToPagePoint(shape, point, util),
132
+ );
133
+ }
134
+
135
+ export function getShapePageBounds<S extends ShapeRecord>(
136
+ shape: S,
137
+ util: ShapeUtil<S>,
138
+ ): Box {
139
+ return Box.FromPoints(getShapePageOutlineVertices(shape, util));
140
+ }
141
+
142
+ export function getShapeExportPageBounds<S extends ShapeRecord>(
143
+ shape: S,
144
+ util: ShapeUtil<S>,
145
+ ): Box {
146
+ const bounds = getShapeExportBounds(shape, util);
147
+ const transform = getShapeExportToPageTransform(shape, util);
148
+ return Box.FromPoints(
149
+ [
150
+ new Vec(bounds.minX, bounds.minY),
151
+ new Vec(bounds.maxX, bounds.minY),
152
+ new Vec(bounds.maxX, bounds.maxY),
153
+ new Vec(bounds.minX, bounds.maxY),
154
+ ].map((point) => transform.applyToPoint(point)),
155
+ );
156
+ }
157
+
158
+ export function getShapeGeometry<S extends ShapeRecord>(
159
+ shape: S,
160
+ util: ShapeUtil<S>,
161
+ ): ShapeGeometry {
162
+ const outlineVertices = getShapePageOutlineVertices(shape, util);
163
+ const corners = getShapePageCorners(shape, util);
164
+ const bounds = Box.FromPoints(outlineVertices);
165
+ return {
166
+ bounds,
167
+ center: getShapePageCenter(shape, util),
168
+ corners,
169
+ outlineVertices,
170
+ };
171
+ }
@@ -0,0 +1,439 @@
1
+ import { Box } from "../geometry/Box";
2
+ import type { ShapeId } from "../schema/records";
3
+
4
+ export const RENDER_CULLING_OVERSCAN_SCREEN = 160;
5
+
6
+ const MAX_RETAINED_RENDER_WINDOW_BASE_EXTRA_SHAPES = 12;
7
+ const MAX_RETAINED_RENDER_WINDOW_BASE_EXTRA_SHAPES_PER_RANGE = 4;
8
+ const RETAINED_RENDER_WINDOW_BASE_PREVIOUS_RANGE_MERGE_GAP = 2;
9
+ const MIN_RETAINED_RENDER_WINDOW_EXTRA_SHAPES = 12;
10
+ const MAX_RETAINED_RENDER_WINDOW_EXTRA_SHAPES = 96;
11
+ const RETAINED_RENDER_WINDOW_EXTRA_VISIBLE_RATIO = 0.5;
12
+ const MIN_RETAINED_RENDER_WINDOW_CLUSTER_PADDING = 8;
13
+ const MAX_RETAINED_RENDER_WINDOW_CLUSTER_PADDING = 32;
14
+ const RETAINED_RENDER_WINDOW_CLUSTER_MERGE_GAP = 2;
15
+ const RETAINED_RENDER_WINDOW_RANGE_MERGE_GAP = 2;
16
+ const RETAINED_RENDER_WINDOW_PREVIOUS_RANGE_MERGE_GAP = 6;
17
+ const RETAINED_RENDER_WINDOW_FORWARD_CLUSTER_PADDING = 4;
18
+
19
+ export interface ShapeIndexRange {
20
+ start: number;
21
+ end: number;
22
+ }
23
+
24
+ export interface ShapeWindowSnapshot {
25
+ viewportReady: boolean;
26
+ ranges: ShapeIndexRange[];
27
+ shapeIds: ShapeId[];
28
+ }
29
+
30
+ function clamp(value: number, min: number, max: number): number {
31
+ return Math.min(max, Math.max(min, value));
32
+ }
33
+
34
+ export function doesBoxContainBox(outer: Box, inner: Box): boolean {
35
+ return (
36
+ inner.minX >= outer.minX &&
37
+ inner.maxX <= outer.maxX &&
38
+ inner.minY >= outer.minY &&
39
+ inner.maxY <= outer.maxY
40
+ );
41
+ }
42
+
43
+ export function formatShapeIndexRanges(ranges: ShapeIndexRange[]): string {
44
+ if (ranges.length === 0) {
45
+ return "none";
46
+ }
47
+
48
+ return ranges
49
+ .map((range) => `${range.start}-${range.end - 1}`)
50
+ .join(", ");
51
+ }
52
+
53
+ export function getRetainedRenderWindowExtraShapeBudget(
54
+ culledShapeCount: number,
55
+ ): number {
56
+ if (culledShapeCount <= 0) {
57
+ return 0;
58
+ }
59
+
60
+ return clamp(
61
+ Math.ceil(culledShapeCount * RETAINED_RENDER_WINDOW_EXTRA_VISIBLE_RATIO),
62
+ MIN_RETAINED_RENDER_WINDOW_EXTRA_SHAPES,
63
+ MAX_RETAINED_RENDER_WINDOW_EXTRA_SHAPES,
64
+ );
65
+ }
66
+
67
+ export function mergeShapeIndexRanges(
68
+ ranges: ShapeIndexRange[],
69
+ gapAllowance = 0,
70
+ ): ShapeIndexRange[] {
71
+ if (ranges.length === 0) {
72
+ return [];
73
+ }
74
+
75
+ const sortedRanges = [...ranges].sort((left, right) => left.start - right.start);
76
+ const mergedRanges: ShapeIndexRange[] = [];
77
+
78
+ for (const range of sortedRanges) {
79
+ const previous = mergedRanges[mergedRanges.length - 1];
80
+ if (!previous || range.start > previous.end + gapAllowance) {
81
+ mergedRanges.push({ ...range });
82
+ continue;
83
+ }
84
+
85
+ previous.end = Math.max(previous.end, range.end);
86
+ }
87
+
88
+ return mergedRanges;
89
+ }
90
+
91
+ function getGapConstrainedClusterPadding(
92
+ gap: number,
93
+ targetPadding: number,
94
+ ): number {
95
+ if (!Number.isFinite(gap)) {
96
+ return targetPadding;
97
+ }
98
+
99
+ const minRemainingGap = RETAINED_RENDER_WINDOW_RANGE_MERGE_GAP + 1;
100
+ const maxPaddingIntoGap = Math.max(
101
+ 0,
102
+ Math.floor((gap - minRemainingGap) / 2),
103
+ );
104
+ return Math.min(targetPadding, maxPaddingIntoGap);
105
+ }
106
+
107
+ export function doRangesContainRanges(
108
+ outerRanges: ShapeIndexRange[],
109
+ innerRanges: ShapeIndexRange[],
110
+ ): boolean {
111
+ if (innerRanges.length === 0) {
112
+ return true;
113
+ }
114
+
115
+ if (outerRanges.length === 0) {
116
+ return false;
117
+ }
118
+
119
+ let outerIndex = 0;
120
+ for (const innerRange of innerRanges) {
121
+ while (outerIndex < outerRanges.length) {
122
+ const outerRange = outerRanges[outerIndex];
123
+ if (
124
+ outerRange &&
125
+ innerRange.start >= outerRange.start &&
126
+ innerRange.end <= outerRange.end
127
+ ) {
128
+ break;
129
+ }
130
+
131
+ if (outerRange && innerRange.end > outerRange.end) {
132
+ outerIndex += 1;
133
+ continue;
134
+ }
135
+
136
+ return false;
137
+ }
138
+
139
+ if (outerIndex >= outerRanges.length) {
140
+ return false;
141
+ }
142
+ }
143
+
144
+ return true;
145
+ }
146
+
147
+ export function getShapeIndexRangeSpan(ranges: ShapeIndexRange[]): number {
148
+ return ranges.reduce((sum, range) => sum + (range.end - range.start), 0);
149
+ }
150
+
151
+ export function getExpandedRetainedShapeRanges(
152
+ previousRanges: ShapeIndexRange[],
153
+ nextRanges: ShapeIndexRange[],
154
+ extraShapeBudget: number,
155
+ ): ShapeIndexRange[] | null {
156
+ const minRemainingGap = RETAINED_RENDER_WINDOW_RANGE_MERGE_GAP + 1;
157
+ const expandedRanges = nextRanges.map((nextRange, index) => {
158
+ const expandedRange = { ...nextRange };
159
+ for (const previousRange of previousRanges) {
160
+ if (
161
+ previousRange.end + RETAINED_RENDER_WINDOW_PREVIOUS_RANGE_MERGE_GAP <
162
+ nextRange.start ||
163
+ previousRange.start >
164
+ nextRange.end + RETAINED_RENDER_WINDOW_PREVIOUS_RANGE_MERGE_GAP
165
+ ) {
166
+ continue;
167
+ }
168
+
169
+ expandedRange.start = Math.min(expandedRange.start, previousRange.start);
170
+ expandedRange.end = Math.max(expandedRange.end, previousRange.end);
171
+ }
172
+
173
+ const previousNextRange = index > 0 ? nextRanges[index - 1] : null;
174
+ const nextNextRange =
175
+ index < nextRanges.length - 1 ? nextRanges[index + 1] : null;
176
+ const leftLimit = previousNextRange
177
+ ? previousNextRange.end + minRemainingGap
178
+ : -Infinity;
179
+ const rightLimit = nextNextRange
180
+ ? nextNextRange.start - minRemainingGap
181
+ : Infinity;
182
+
183
+ return {
184
+ start: Math.min(
185
+ nextRange.start,
186
+ Math.max(leftLimit, expandedRange.start),
187
+ ),
188
+ end: Math.max(nextRange.end, Math.min(rightLimit, expandedRange.end)),
189
+ };
190
+ });
191
+
192
+ if (mergeShapeIndexRanges(expandedRanges).length !== nextRanges.length) {
193
+ return null;
194
+ }
195
+
196
+ const nextSpan = getShapeIndexRangeSpan(nextRanges);
197
+ const expandedSpan = getShapeIndexRangeSpan(expandedRanges);
198
+ if (expandedSpan > nextSpan + extraShapeBudget) {
199
+ return null;
200
+ }
201
+
202
+ return expandedRanges;
203
+ }
204
+
205
+ export function getExpandedRetainedBaseShapeRanges(
206
+ previousRanges: ShapeIndexRange[],
207
+ nextRanges: ShapeIndexRange[],
208
+ ): ShapeIndexRange[] | null {
209
+ if (previousRanges.length !== nextRanges.length || nextRanges.length === 0) {
210
+ return null;
211
+ }
212
+
213
+ const minRemainingGap =
214
+ RETAINED_RENDER_WINDOW_BASE_PREVIOUS_RANGE_MERGE_GAP + 1;
215
+ const expandedRanges = nextRanges.map((nextRange, index) => {
216
+ const previousRange = previousRanges[index];
217
+ if (!previousRange) {
218
+ return null;
219
+ }
220
+
221
+ if (
222
+ previousRange.end + RETAINED_RENDER_WINDOW_BASE_PREVIOUS_RANGE_MERGE_GAP <
223
+ nextRange.start ||
224
+ previousRange.start >
225
+ nextRange.end + RETAINED_RENDER_WINDOW_BASE_PREVIOUS_RANGE_MERGE_GAP
226
+ ) {
227
+ return null;
228
+ }
229
+
230
+ const previousNextRange = index > 0 ? nextRanges[index - 1] : null;
231
+ const nextNextRange =
232
+ index < nextRanges.length - 1 ? nextRanges[index + 1] : null;
233
+ const leftLimit = previousNextRange
234
+ ? previousNextRange.end + minRemainingGap
235
+ : -Infinity;
236
+ const rightLimit = nextNextRange
237
+ ? nextNextRange.start - minRemainingGap
238
+ : Infinity;
239
+ const expandedRange = {
240
+ start: Math.min(nextRange.start, Math.max(leftLimit, previousRange.start)),
241
+ end: Math.max(nextRange.end, Math.min(rightLimit, previousRange.end)),
242
+ };
243
+
244
+ if (
245
+ expandedRange.end - expandedRange.start >
246
+ nextRange.end -
247
+ nextRange.start +
248
+ MAX_RETAINED_RENDER_WINDOW_BASE_EXTRA_SHAPES_PER_RANGE
249
+ ) {
250
+ return null;
251
+ }
252
+
253
+ return expandedRange;
254
+ });
255
+
256
+ if (
257
+ expandedRanges.some(
258
+ (range): range is null => range === null,
259
+ )
260
+ ) {
261
+ return null;
262
+ }
263
+
264
+ const ranges = expandedRanges as ShapeIndexRange[];
265
+ if (mergeShapeIndexRanges(ranges).length !== nextRanges.length) {
266
+ return null;
267
+ }
268
+
269
+ const nextSpan = getShapeIndexRangeSpan(nextRanges);
270
+ const expandedSpan = getShapeIndexRangeSpan(ranges);
271
+ if (expandedSpan > nextSpan + MAX_RETAINED_RENDER_WINDOW_BASE_EXTRA_SHAPES) {
272
+ return null;
273
+ }
274
+
275
+ return ranges;
276
+ }
277
+
278
+ export function getShapeIndexRangesForShapeIds(
279
+ shapeIds: ShapeId[],
280
+ pageIndexById: Map<ShapeId, number>,
281
+ gapAllowance = 0,
282
+ ): ShapeIndexRange[] {
283
+ const indices = shapeIds
284
+ .map((shapeId) => pageIndexById.get(shapeId))
285
+ .filter((index): index is number => index !== undefined);
286
+
287
+ return mergeShapeIndexRanges(
288
+ indices.map((index) => ({ start: index, end: index + 1 })),
289
+ gapAllowance,
290
+ );
291
+ }
292
+
293
+ function getShapeIdsForRanges(
294
+ pageShapeIds: ShapeId[],
295
+ ranges: ShapeIndexRange[],
296
+ ): ShapeId[] {
297
+ const retainedShapeIds: ShapeId[] = [];
298
+ for (const range of ranges) {
299
+ retainedShapeIds.push(...pageShapeIds.slice(range.start, range.end));
300
+ }
301
+ return retainedShapeIds;
302
+ }
303
+
304
+ export function getShapeWindowSnapshot(
305
+ pageShapeIds: ShapeId[],
306
+ ranges: ShapeIndexRange[],
307
+ options?: { viewportReady?: boolean },
308
+ ): ShapeWindowSnapshot {
309
+ return {
310
+ viewportReady: options?.viewportReady ?? true,
311
+ ranges: ranges.map((range) => ({ ...range })),
312
+ shapeIds: getShapeIdsForRanges(pageShapeIds, ranges),
313
+ };
314
+ }
315
+
316
+ export function getShapeIdArrayChangeCounts(
317
+ previous: ShapeId[],
318
+ next: ShapeId[],
319
+ ): {
320
+ changed: number;
321
+ added: number;
322
+ removed: number;
323
+ } {
324
+ if (previous.length === 0) {
325
+ return {
326
+ changed: next.length,
327
+ added: next.length,
328
+ removed: 0,
329
+ };
330
+ }
331
+
332
+ if (next.length === 0) {
333
+ return {
334
+ changed: previous.length,
335
+ added: 0,
336
+ removed: previous.length,
337
+ };
338
+ }
339
+
340
+ const previousSet = new Set(previous);
341
+ const nextSet = new Set(next);
342
+ let added = 0;
343
+ let removed = 0;
344
+
345
+ for (const id of nextSet) {
346
+ if (!previousSet.has(id)) {
347
+ added += 1;
348
+ }
349
+ }
350
+
351
+ for (const id of previousSet) {
352
+ if (!nextSet.has(id)) {
353
+ removed += 1;
354
+ }
355
+ }
356
+
357
+ return {
358
+ changed: added + removed,
359
+ added,
360
+ removed,
361
+ };
362
+ }
363
+
364
+ export function collectRetainedShapeRanges(
365
+ pageShapeIds: ShapeId[],
366
+ culledShapeIds: ShapeId[],
367
+ selectedIds: Set<ShapeId>,
368
+ extraShapeBudget: number,
369
+ ): ShapeIndexRange[] {
370
+ if (pageShapeIds.length === 0) {
371
+ return [];
372
+ }
373
+
374
+ const pageIndexById = new Map<ShapeId, number>();
375
+ for (const [index, shapeId] of pageShapeIds.entries()) {
376
+ pageIndexById.set(shapeId, index);
377
+ }
378
+
379
+ const culledIndices = culledShapeIds
380
+ .map((shapeId) => pageIndexById.get(shapeId))
381
+ .filter((index): index is number => index !== undefined)
382
+ .sort((left, right) => left - right);
383
+
384
+ const culledRanges = mergeShapeIndexRanges(
385
+ culledIndices.map((index) => ({ start: index, end: index + 1 })),
386
+ RETAINED_RENDER_WINDOW_CLUSTER_MERGE_GAP,
387
+ );
388
+
389
+ const pendingRanges: ShapeIndexRange[] = [];
390
+ if (culledRanges.length > 0) {
391
+ const clusterPadding = clamp(
392
+ Math.ceil(extraShapeBudget / (culledRanges.length * 2)),
393
+ MIN_RETAINED_RENDER_WINDOW_CLUSTER_PADDING,
394
+ MAX_RETAINED_RENDER_WINDOW_CLUSTER_PADDING,
395
+ );
396
+
397
+ for (const [index, range] of culledRanges.entries()) {
398
+ const previousRange = index > 0 ? culledRanges[index - 1] : null;
399
+ const nextRange =
400
+ index < culledRanges.length - 1 ? culledRanges[index + 1] : null;
401
+ const leftGap = previousRange ? range.start - previousRange.end : Infinity;
402
+ const rightGap = nextRange ? nextRange.start - range.end : Infinity;
403
+ const leftPadding = getGapConstrainedClusterPadding(
404
+ leftGap,
405
+ clusterPadding,
406
+ );
407
+ const rightPadding = getGapConstrainedClusterPadding(
408
+ rightGap,
409
+ clusterPadding + RETAINED_RENDER_WINDOW_FORWARD_CLUSTER_PADDING,
410
+ );
411
+
412
+ pendingRanges.push({
413
+ start: Math.max(0, range.start - leftPadding),
414
+ end: Math.min(pageShapeIds.length, range.end + rightPadding),
415
+ });
416
+ }
417
+ }
418
+
419
+ for (const shapeId of selectedIds) {
420
+ const index = pageIndexById.get(shapeId);
421
+ if (index === undefined) {
422
+ continue;
423
+ }
424
+
425
+ pendingRanges.push({
426
+ start: index,
427
+ end: index + 1,
428
+ });
429
+ }
430
+
431
+ if (pendingRanges.length === 0) {
432
+ return [];
433
+ }
434
+
435
+ return mergeShapeIndexRanges(
436
+ pendingRanges,
437
+ RETAINED_RENDER_WINDOW_RANGE_MERGE_GAP,
438
+ );
439
+ }