@flowgram.ai/free-layout-core 0.1.0-alpha.36 → 0.1.0-alpha.38

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/index.d.mts CHANGED
@@ -2,8 +2,8 @@ import { PlaygroundConfigEntity, CommandService, PlaygroundDragEvent, EntityData
2
2
  export { bindConfigEntity, useConfigEntity, useEntities, useEntityDataFromContext, useEntityFromContext, useListenEvents, usePlayground, usePlaygroundContainer, usePlaygroundContext, useRefresh, useService } from '@flowgram.ai/core';
3
3
  import { NodeFormProps } from '@flowgram.ai/node';
4
4
  import { FlowNodeType, FlowOperationBaseServiceImpl, FlowNodeEntityOrId, FlowNodeEntity } from '@flowgram.ai/document';
5
- import { W as WorkflowJSON, L as LineCenterPoint, a as WorkflowDocument, b as WorkflowNodeEntity, c as WorkflowHoverService, d as WorkflowLinesManager, e as WorkflowSelectService, f as WorkflowDocumentOptions, g as LineEventProps, N as NodesDragEvent, h as WorkflowNodeJSON, i as WorkflowPortEntity, j as WorkflowLineEntity, O as OnDragLineEnd, k as LineRenderType, l as WorkflowLineRenderContribution, m as LinePosition } from './workflow-node-entity-DcXjib68.mjs';
6
- export { Y as HoverPosition, G as LINE_HOVER_DISTANCE, y as LineColor, z as LineColors, x as LinePoint, w as LinePointLocation, v as LineType, D as NodesDragEndEvent, C as NodesDragStartEvent, E as NodesDraggingEvent, P as POINT_RADIUS, M as PORT_SIZE, q as WORKFLOW_LINE_ENTITY, Z as WorkfloEntityHoverable, t as WorkflowContentChangeEvent, s as WorkflowContentChangeType, $ as WorkflowDocumentOptionsDefault, _ as WorkflowDocumentProvider, X as WorkflowEntityHoverable, I as WorkflowLineEntityOpts, J as WorkflowLineInfo, H as WorkflowLinePortInfo, A as WorkflowLineRenderContributionFactory, K as WorkflowLineUIState, U as WorkflowNodeLines, V as WorkflowNodeLinesData, u as WorkflowNodeMeta, T as WorkflowNodePortsData, Q as WorkflowPort, S as WorkflowPortEntityOpts, n as WorkflowPortType, R as WorkflowPorts, B as WorkflowSubCanvas, r as domReactToBounds, p as getPortEntityId, o as getPortEntityIdByNodeId, F as onDragLineEndParams } from './workflow-node-entity-DcXjib68.mjs';
5
+ import { W as WorkflowJSON, L as LineCenterPoint, a as WorkflowDocument, b as WorkflowNodeEntity, c as WorkflowHoverService, d as WorkflowLinesManager, e as WorkflowSelectService, f as WorkflowDocumentOptions, g as LineEventProps, N as NodesDragEvent, h as WorkflowNodeJSON, i as WorkflowPortEntity, j as WorkflowLineEntity, O as OnDragLineEnd, k as LineRenderType, l as WorkflowLineRenderContribution, m as LinePosition } from './workflow-node-entity-BQBXdOoa.mjs';
6
+ export { Y as HoverPosition, G as LINE_HOVER_DISTANCE, y as LineColor, z as LineColors, x as LinePoint, w as LinePointLocation, v as LineType, D as NodesDragEndEvent, C as NodesDragStartEvent, E as NodesDraggingEvent, P as POINT_RADIUS, M as PORT_SIZE, q as WORKFLOW_LINE_ENTITY, Z as WorkfloEntityHoverable, t as WorkflowContentChangeEvent, s as WorkflowContentChangeType, $ as WorkflowDocumentOptionsDefault, _ as WorkflowDocumentProvider, X as WorkflowEntityHoverable, I as WorkflowLineEntityOpts, J as WorkflowLineInfo, H as WorkflowLinePortInfo, A as WorkflowLineRenderContributionFactory, K as WorkflowLineUIState, U as WorkflowNodeLines, V as WorkflowNodeLinesData, u as WorkflowNodeMeta, T as WorkflowNodePortsData, Q as WorkflowPort, S as WorkflowPortEntityOpts, n as WorkflowPortType, R as WorkflowPorts, B as WorkflowSubCanvas, r as domReactToBounds, p as getPortEntityId, o as getPortEntityIdByNodeId, F as onDragLineEndParams } from './workflow-node-entity-BQBXdOoa.mjs';
7
7
  import * as _flowgram_ai_utils from '@flowgram.ai/utils';
8
8
  import { IPoint, Rectangle, DisposableCollection, Disposable } from '@flowgram.ai/utils';
9
9
  export { compose, composeAsync, delay } from '@flowgram.ai/utils';
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ import { PlaygroundConfigEntity, CommandService, PlaygroundDragEvent, EntityData
2
2
  export { bindConfigEntity, useConfigEntity, useEntities, useEntityDataFromContext, useEntityFromContext, useListenEvents, usePlayground, usePlaygroundContainer, usePlaygroundContext, useRefresh, useService } from '@flowgram.ai/core';
3
3
  import { NodeFormProps } from '@flowgram.ai/node';
4
4
  import { FlowNodeType, FlowOperationBaseServiceImpl, FlowNodeEntityOrId, FlowNodeEntity } from '@flowgram.ai/document';
5
- import { W as WorkflowJSON, L as LineCenterPoint, a as WorkflowDocument, b as WorkflowNodeEntity, c as WorkflowHoverService, d as WorkflowLinesManager, e as WorkflowSelectService, f as WorkflowDocumentOptions, g as LineEventProps, N as NodesDragEvent, h as WorkflowNodeJSON, i as WorkflowPortEntity, j as WorkflowLineEntity, O as OnDragLineEnd, k as LineRenderType, l as WorkflowLineRenderContribution, m as LinePosition } from './workflow-node-entity-_7O7-wJE.js';
6
- export { Y as HoverPosition, G as LINE_HOVER_DISTANCE, y as LineColor, z as LineColors, x as LinePoint, w as LinePointLocation, v as LineType, D as NodesDragEndEvent, C as NodesDragStartEvent, E as NodesDraggingEvent, P as POINT_RADIUS, M as PORT_SIZE, q as WORKFLOW_LINE_ENTITY, Z as WorkfloEntityHoverable, t as WorkflowContentChangeEvent, s as WorkflowContentChangeType, $ as WorkflowDocumentOptionsDefault, _ as WorkflowDocumentProvider, X as WorkflowEntityHoverable, I as WorkflowLineEntityOpts, J as WorkflowLineInfo, H as WorkflowLinePortInfo, A as WorkflowLineRenderContributionFactory, K as WorkflowLineUIState, U as WorkflowNodeLines, V as WorkflowNodeLinesData, u as WorkflowNodeMeta, T as WorkflowNodePortsData, Q as WorkflowPort, S as WorkflowPortEntityOpts, n as WorkflowPortType, R as WorkflowPorts, B as WorkflowSubCanvas, r as domReactToBounds, p as getPortEntityId, o as getPortEntityIdByNodeId, F as onDragLineEndParams } from './workflow-node-entity-_7O7-wJE.js';
5
+ import { W as WorkflowJSON, L as LineCenterPoint, a as WorkflowDocument, b as WorkflowNodeEntity, c as WorkflowHoverService, d as WorkflowLinesManager, e as WorkflowSelectService, f as WorkflowDocumentOptions, g as LineEventProps, N as NodesDragEvent, h as WorkflowNodeJSON, i as WorkflowPortEntity, j as WorkflowLineEntity, O as OnDragLineEnd, k as LineRenderType, l as WorkflowLineRenderContribution, m as LinePosition } from './workflow-node-entity-Da9FrkWn.js';
6
+ export { Y as HoverPosition, G as LINE_HOVER_DISTANCE, y as LineColor, z as LineColors, x as LinePoint, w as LinePointLocation, v as LineType, D as NodesDragEndEvent, C as NodesDragStartEvent, E as NodesDraggingEvent, P as POINT_RADIUS, M as PORT_SIZE, q as WORKFLOW_LINE_ENTITY, Z as WorkfloEntityHoverable, t as WorkflowContentChangeEvent, s as WorkflowContentChangeType, $ as WorkflowDocumentOptionsDefault, _ as WorkflowDocumentProvider, X as WorkflowEntityHoverable, I as WorkflowLineEntityOpts, J as WorkflowLineInfo, H as WorkflowLinePortInfo, A as WorkflowLineRenderContributionFactory, K as WorkflowLineUIState, U as WorkflowNodeLines, V as WorkflowNodeLinesData, u as WorkflowNodeMeta, T as WorkflowNodePortsData, Q as WorkflowPort, S as WorkflowPortEntityOpts, n as WorkflowPortType, R as WorkflowPorts, B as WorkflowSubCanvas, r as domReactToBounds, p as getPortEntityId, o as getPortEntityIdByNodeId, F as onDragLineEndParams } from './workflow-node-entity-Da9FrkWn.js';
7
7
  import * as _flowgram_ai_utils from '@flowgram.ai/utils';
8
8
  import { IPoint, Rectangle, DisposableCollection, Disposable } from '@flowgram.ai/utils';
9
9
  export { compose, composeAsync, delay } from '@flowgram.ai/utils';
package/dist/index.js CHANGED
@@ -606,7 +606,7 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
606
606
  * 获取输出点位置
607
607
  */
608
608
  get outputPoints() {
609
- return this.inputPorts.map((port) => port.point);
609
+ return this.outputPorts.map((port) => port.point);
610
610
  }
611
611
  /**
612
612
  * 根据 key 获取 输入点位置
@@ -1642,6 +1642,12 @@ var WorkflowDocumentOptionsDefault = {
1642
1642
  };
1643
1643
 
1644
1644
  // src/workflow-lines-manager.ts
1645
+ var NODE_HIT_CELL_SIZE = 512;
1646
+ var LINE_HIT_CELL_SIZE = 512;
1647
+ var PORT_NODE_BOUNDS_PADDING = 96;
1648
+ var NODE_INDEX_MIN_SIZE = 128;
1649
+ var LINE_INDEX_MIN_SIZE = 128;
1650
+ var MAX_SPATIAL_CELLS_PER_ITEM = 64;
1645
1651
  var WorkflowLinesManager = class {
1646
1652
  constructor() {
1647
1653
  this.toDispose = new import_utils12.DisposableCollection();
@@ -1665,7 +1671,26 @@ var WorkflowLinesManager = class {
1665
1671
  this.isDrawing = false;
1666
1672
  }
1667
1673
  init(doc) {
1674
+ if (this.document === doc) {
1675
+ return;
1676
+ }
1668
1677
  this.document = doc;
1678
+ this.toDispose.pushAll([
1679
+ this.entityManager.onEntityChange((entityType) => {
1680
+ if (entityType === WorkflowNodeEntity.type) {
1681
+ this.invalidateNodeHitCaches();
1682
+ }
1683
+ if (entityType === WorkflowLineEntity.type || entityType === WorkflowPortEntity.type) {
1684
+ this.invalidateLineHitCache();
1685
+ this.outsidePortNodesCache = void 0;
1686
+ }
1687
+ }),
1688
+ this.entityManager.onEntityDataChange(({ entityDataType }) => {
1689
+ if (entityDataType === import_document6.FlowNodeTransformData.type) {
1690
+ this.invalidateSpatialHitCaches();
1691
+ }
1692
+ })
1693
+ ]);
1669
1694
  }
1670
1695
  forceUpdate() {
1671
1696
  this.onForceUpdateEmitter.fire();
@@ -1673,6 +1698,7 @@ var WorkflowLinesManager = class {
1673
1698
  invalidateSortedNodesCache() {
1674
1699
  this.sortedNodesCache = void 0;
1675
1700
  this.sortedNodesCacheVersion = void 0;
1701
+ this.invalidateNodeHitCaches();
1676
1702
  }
1677
1703
  get lineType() {
1678
1704
  return this._lineType;
@@ -1702,6 +1728,7 @@ var WorkflowLinesManager = class {
1702
1728
  }
1703
1729
  if (newType !== this._lineType) {
1704
1730
  this._lineType = newType;
1731
+ this.lineSpatialCache = void 0;
1705
1732
  this.getAllLines().forEach((line) => {
1706
1733
  line.getData(WorkflowLineRenderData).update();
1707
1734
  });
@@ -1860,7 +1887,7 @@ var WorkflowLinesManager = class {
1860
1887
  */
1861
1888
  getCloseInLineFromMousePos(mousePos, minDistance = LINE_HOVER_DISTANCE) {
1862
1889
  let targetLine, targetLineDist;
1863
- const lines = this.getAllLines();
1890
+ const lines = this.getLineHitCandidates(mousePos, minDistance);
1864
1891
  for (let i = 0; i < lines.length; i++) {
1865
1892
  const line = lines[i];
1866
1893
  if (!this.isPointInBounds(mousePos, line.bounds, minDistance)) {
@@ -1876,6 +1903,10 @@ var WorkflowLinesManager = class {
1876
1903
  }
1877
1904
  dispose() {
1878
1905
  this.portLineMap.clear();
1906
+ this.sortedNodeSpatialCache = void 0;
1907
+ this.hoverNodeSpatialCache = void 0;
1908
+ this.lineSpatialCache = void 0;
1909
+ this.outsidePortNodesCache = void 0;
1879
1910
  this.toDispose.dispose();
1880
1911
  }
1881
1912
  get disposed() {
@@ -2014,8 +2045,9 @@ var WorkflowLinesManager = class {
2014
2045
  }
2015
2046
  getHoverNodeFromMousePos(pos) {
2016
2047
  const nodes = this.getHoverNodes();
2017
- for (let i = 0; i < nodes.length; i++) {
2018
- const node = nodes[i];
2048
+ const candidates = this.getHoverNodeHitCandidates(pos, nodes);
2049
+ for (let i = 0; i < candidates.length; i++) {
2050
+ const node = candidates[i];
2019
2051
  const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2020
2052
  if (this.isPointInBounds(pos, bounds)) {
2021
2053
  return node;
@@ -2045,8 +2077,22 @@ var WorkflowLinesManager = class {
2045
2077
  (a, b) => this.getNodeIndex(a) - this.getNodeIndex(b)
2046
2078
  );
2047
2079
  this.sortedNodesCacheVersion = nodeVersion;
2080
+ this.sortedNodeSpatialCache = void 0;
2081
+ this.outsidePortNodesCache = void 0;
2048
2082
  return this.sortedNodesCache;
2049
2083
  }
2084
+ invalidateNodeHitCaches() {
2085
+ this.sortedNodeSpatialCache = void 0;
2086
+ this.hoverNodeSpatialCache = void 0;
2087
+ this.outsidePortNodesCache = void 0;
2088
+ }
2089
+ invalidateLineHitCache() {
2090
+ this.lineSpatialCache = void 0;
2091
+ }
2092
+ invalidateSpatialHitCaches() {
2093
+ this.invalidateNodeHitCaches();
2094
+ this.invalidateLineHitCache();
2095
+ }
2050
2096
  getHoveredPortFromSortedNodes(pos, sortedNodes, portType) {
2051
2097
  return this.getHoveredPortsFromSortedNodes(pos, sortedNodes, portType).port;
2052
2098
  }
@@ -2055,21 +2101,54 @@ var WorkflowLinesManager = class {
2055
2101
  let outputPort;
2056
2102
  let anyPort;
2057
2103
  const { collectBoth = false } = options;
2058
- for (let i = sortedNodes.length - 1; i >= 0; i--) {
2059
- const node = sortedNodes[i];
2060
- if (!portType && !anyPort) {
2061
- anyPort = this.findHoveredPort(node.ports.allPorts, pos);
2062
- }
2063
- if ((!portType || portType === "output") && !outputPort) {
2064
- outputPort = this.findHoveredPort(node.ports.outputPorts, pos);
2065
- }
2066
- if ((!portType || portType === "input") && !inputPort) {
2067
- inputPort = this.findHoveredPort(node.ports.inputPorts, pos);
2104
+ const needInput = !portType || portType === "input";
2105
+ const needOutput = !portType || portType === "output";
2106
+ const needAny = !portType && !collectBoth;
2107
+ const candidates = this.getSortedNodeHitCandidates(pos, sortedNodes, PORT_NODE_BOUNDS_PADDING);
2108
+ const checkedNodes = candidates.length === sortedNodes.length ? void 0 : new Set(candidates);
2109
+ for (let i = candidates.length - 1; i >= 0; i--) {
2110
+ const node = candidates[i];
2111
+ if (!this.isPointNearNodePorts(pos, node)) {
2112
+ continue;
2068
2113
  }
2114
+ const result = this.collectHoveredPorts(node.ports.allPorts, pos, {
2115
+ needInput,
2116
+ needOutput,
2117
+ needAny,
2118
+ inputPort,
2119
+ outputPort,
2120
+ anyPort
2121
+ });
2122
+ inputPort = result.inputPort;
2123
+ outputPort = result.outputPort;
2124
+ anyPort = result.anyPort;
2069
2125
  if (portType === "input" && inputPort || portType === "output" && outputPort || !portType && (collectBoth ? inputPort && outputPort : anyPort)) {
2070
2126
  break;
2071
2127
  }
2072
2128
  }
2129
+ if (checkedNodes && !(portType === "input" && inputPort || portType === "output" && outputPort || !portType && (collectBoth ? inputPort && outputPort : anyPort))) {
2130
+ const outsidePortNodes = this.getOutsidePortNodes(sortedNodes);
2131
+ for (let i = outsidePortNodes.length - 1; i >= 0; i--) {
2132
+ const node = outsidePortNodes[i];
2133
+ if (checkedNodes.has(node)) {
2134
+ continue;
2135
+ }
2136
+ const result = this.collectHoveredPorts(node.ports.allPorts, pos, {
2137
+ needInput,
2138
+ needOutput,
2139
+ needAny,
2140
+ inputPort,
2141
+ outputPort,
2142
+ anyPort
2143
+ });
2144
+ inputPort = result.inputPort;
2145
+ outputPort = result.outputPort;
2146
+ anyPort = result.anyPort;
2147
+ if (portType === "input" && inputPort || portType === "output" && outputPort || !portType && (collectBoth ? inputPort && outputPort : anyPort)) {
2148
+ break;
2149
+ }
2150
+ }
2151
+ }
2073
2152
  const needCoverCheck = inputPort || outputPort || anyPort;
2074
2153
  const topCoverNode = needCoverCheck ? options.topCoverNode || this.getNodeHitInfoFromSortedNodes(pos, sortedNodes).topCoverNode : void 0;
2075
2154
  inputPort = this.filterCoveredPort(inputPort, topCoverNode);
@@ -2081,13 +2160,30 @@ var WorkflowLinesManager = class {
2081
2160
  port: portType === "input" ? inputPort : portType === "output" ? outputPort : anyPort
2082
2161
  };
2083
2162
  }
2084
- findHoveredPort(ports, pos) {
2163
+ collectHoveredPorts(ports, pos, options) {
2164
+ let { inputPort, outputPort, anyPort } = options;
2085
2165
  for (let i = 0; i < ports.length; i++) {
2086
2166
  const port = ports[i];
2167
+ if ((!options.needAny || anyPort) && (!options.needInput || inputPort) && (!options.needOutput || outputPort)) {
2168
+ break;
2169
+ }
2087
2170
  if (port.isHovered(pos.x, pos.y)) {
2088
- return port;
2171
+ if (!anyPort && options.needAny) {
2172
+ anyPort = port;
2173
+ }
2174
+ if (!inputPort && options.needInput && port.portType === "input") {
2175
+ inputPort = port;
2176
+ }
2177
+ if (!outputPort && options.needOutput && port.portType === "output") {
2178
+ outputPort = port;
2179
+ }
2089
2180
  }
2090
2181
  }
2182
+ return {
2183
+ inputPort,
2184
+ outputPort,
2185
+ anyPort
2186
+ };
2091
2187
  }
2092
2188
  filterCoveredPort(port, topCoverNode) {
2093
2189
  if (port && topCoverNode && topCoverNode !== port.node) {
@@ -2102,9 +2198,10 @@ var WorkflowLinesManager = class {
2102
2198
  const zoom = this.entityManager.getEntity(import_core12.PlaygroundConfigEntity)?.config?.zoom || 1;
2103
2199
  const padding = 4 / zoom;
2104
2200
  const selectedIDs = selection?.length ? new Set(selection.map((node) => node.id)) : void 0;
2201
+ const candidates = this.getSortedNodeHitCandidates(pos, sortedNodes, padding);
2105
2202
  let topCoverNode;
2106
- for (let i = sortedNodes.length - 1; i >= 0; i--) {
2107
- const node = sortedNodes[i];
2203
+ for (let i = candidates.length - 1; i >= 0; i--) {
2204
+ const node = candidates[i];
2108
2205
  const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2109
2206
  if (!this.isPointInBounds(pos, bounds, padding)) {
2110
2207
  continue;
@@ -2130,6 +2227,167 @@ var WorkflowLinesManager = class {
2130
2227
  topNode: topCoverNode
2131
2228
  };
2132
2229
  }
2230
+ getHoverNodeHitCandidates(pos, nodes) {
2231
+ if (nodes.length < NODE_INDEX_MIN_SIZE) {
2232
+ return nodes;
2233
+ }
2234
+ const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2235
+ const transformVersion = this.entityManager.getEntityDataVersion(import_document6.FlowNodeTransformData);
2236
+ const activatedID = this.selectService.activatedNode?.id;
2237
+ if (!this.hoverNodeSpatialCache || this.hoverNodeSpatialCache.nodeVersion !== nodeVersion || this.hoverNodeSpatialCache.transformVersion !== transformVersion || this.hoverNodeSpatialCache.activatedID !== activatedID || this.hoverNodeSpatialCache.nodes !== nodes) {
2238
+ this.hoverNodeSpatialCache = {
2239
+ nodeVersion,
2240
+ transformVersion,
2241
+ activatedID,
2242
+ nodes,
2243
+ index: this.createSpatialIndex(
2244
+ nodes,
2245
+ (node) => node.getData(import_document6.FlowNodeTransformData).bounds,
2246
+ NODE_HIT_CELL_SIZE
2247
+ )
2248
+ };
2249
+ }
2250
+ return this.querySpatialIndex(this.hoverNodeSpatialCache.index, pos);
2251
+ }
2252
+ getSortedNodeHitCandidates(pos, sortedNodes, padding = 0) {
2253
+ if (sortedNodes.length < NODE_INDEX_MIN_SIZE) {
2254
+ return sortedNodes;
2255
+ }
2256
+ const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2257
+ const transformVersion = this.entityManager.getEntityDataVersion(import_document6.FlowNodeTransformData);
2258
+ if (!this.sortedNodeSpatialCache || this.sortedNodeSpatialCache.nodeVersion !== nodeVersion || this.sortedNodeSpatialCache.transformVersion !== transformVersion || this.sortedNodeSpatialCache.nodes !== sortedNodes) {
2259
+ this.sortedNodeSpatialCache = {
2260
+ nodeVersion,
2261
+ transformVersion,
2262
+ nodes: sortedNodes,
2263
+ index: this.createSpatialIndex(
2264
+ sortedNodes,
2265
+ (node) => node.getData(import_document6.FlowNodeTransformData).bounds,
2266
+ NODE_HIT_CELL_SIZE
2267
+ )
2268
+ };
2269
+ }
2270
+ return this.querySpatialIndex(this.sortedNodeSpatialCache.index, pos, padding);
2271
+ }
2272
+ getLineHitCandidates(pos, padding) {
2273
+ const lines = this.getAllLines();
2274
+ if (lines.length < LINE_INDEX_MIN_SIZE) {
2275
+ return lines;
2276
+ }
2277
+ const lineVersion = this.entityManager.getEntityVersion(WorkflowLineEntity);
2278
+ const portVersion = this.entityManager.getEntityVersion(WorkflowPortEntity);
2279
+ const transformVersion = this.entityManager.getEntityDataVersion(import_document6.FlowNodeTransformData);
2280
+ if (!this.lineSpatialCache || this.lineSpatialCache.lineVersion !== lineVersion || this.lineSpatialCache.portVersion !== portVersion || this.lineSpatialCache.transformVersion !== transformVersion) {
2281
+ this.lineSpatialCache = {
2282
+ lineVersion,
2283
+ portVersion,
2284
+ transformVersion,
2285
+ index: this.createSpatialIndex(lines, (line) => line.bounds, LINE_HIT_CELL_SIZE)
2286
+ };
2287
+ }
2288
+ return this.querySpatialIndex(this.lineSpatialCache.index, pos, padding);
2289
+ }
2290
+ createSpatialIndex(items, getBounds, cellSize) {
2291
+ const index = {
2292
+ cellSize,
2293
+ cells: /* @__PURE__ */ new Map(),
2294
+ overflowItems: [],
2295
+ order: /* @__PURE__ */ new Map()
2296
+ };
2297
+ items.forEach((item, itemIndex) => {
2298
+ index.order.set(item, itemIndex);
2299
+ const bounds = getBounds(item);
2300
+ if (!this.canIndexBounds(bounds)) {
2301
+ index.overflowItems.push(item);
2302
+ return;
2303
+ }
2304
+ const minCellX = this.getSpatialCell(bounds.x, cellSize);
2305
+ const maxCellX = this.getSpatialCell(bounds.right, cellSize);
2306
+ const minCellY = this.getSpatialCell(bounds.y, cellSize);
2307
+ const maxCellY = this.getSpatialCell(bounds.bottom, cellSize);
2308
+ const cellCount = (maxCellX - minCellX + 1) * (maxCellY - minCellY + 1);
2309
+ if (cellCount > MAX_SPATIAL_CELLS_PER_ITEM) {
2310
+ index.overflowItems.push(item);
2311
+ return;
2312
+ }
2313
+ for (let x = minCellX; x <= maxCellX; x++) {
2314
+ for (let y = minCellY; y <= maxCellY; y++) {
2315
+ const key = this.getSpatialCellKey(x, y);
2316
+ let cellItems = index.cells.get(key);
2317
+ if (!cellItems) {
2318
+ cellItems = [];
2319
+ index.cells.set(key, cellItems);
2320
+ }
2321
+ cellItems.push(item);
2322
+ }
2323
+ }
2324
+ });
2325
+ return index;
2326
+ }
2327
+ querySpatialIndex(index, pos, padding = 0) {
2328
+ const minCellX = this.getSpatialCell(pos.x - padding, index.cellSize);
2329
+ const maxCellX = this.getSpatialCell(pos.x + padding, index.cellSize);
2330
+ const minCellY = this.getSpatialCell(pos.y - padding, index.cellSize);
2331
+ const maxCellY = this.getSpatialCell(pos.y + padding, index.cellSize);
2332
+ const candidates = [];
2333
+ const candidateSet = /* @__PURE__ */ new Set();
2334
+ const pushCandidate = (item) => {
2335
+ if (candidateSet.has(item)) {
2336
+ return;
2337
+ }
2338
+ candidateSet.add(item);
2339
+ candidates.push(item);
2340
+ };
2341
+ for (let x = minCellX; x <= maxCellX; x++) {
2342
+ for (let y = minCellY; y <= maxCellY; y++) {
2343
+ const cellItems = index.cells.get(this.getSpatialCellKey(x, y));
2344
+ if (cellItems) {
2345
+ cellItems.forEach(pushCandidate);
2346
+ }
2347
+ }
2348
+ }
2349
+ index.overflowItems.forEach(pushCandidate);
2350
+ return candidates.sort((a, b) => (index.order.get(a) ?? 0) - (index.order.get(b) ?? 0));
2351
+ }
2352
+ getSpatialCell(value, cellSize) {
2353
+ return Math.floor(value / cellSize);
2354
+ }
2355
+ getSpatialCellKey(x, y) {
2356
+ return `${x}:${y}`;
2357
+ }
2358
+ canIndexBounds(bounds) {
2359
+ return Number.isFinite(bounds.x) && Number.isFinite(bounds.y) && Number.isFinite(bounds.width) && Number.isFinite(bounds.height) && bounds.width > 0 && bounds.height > 0;
2360
+ }
2361
+ isPointNearNodePorts(pos, node) {
2362
+ const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2363
+ return this.isPointInBounds(pos, bounds, PORT_NODE_BOUNDS_PADDING);
2364
+ }
2365
+ hasPortOutsideNodeBounds(node) {
2366
+ const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2367
+ return node.ports.allPorts.some((port) => {
2368
+ if (port.targetElement) {
2369
+ return true;
2370
+ }
2371
+ return !this.isPointInBounds(port.point, bounds, PORT_NODE_BOUNDS_PADDING);
2372
+ });
2373
+ }
2374
+ getOutsidePortNodes(sortedNodes) {
2375
+ const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2376
+ const portVersion = this.entityManager.getEntityVersion(WorkflowPortEntity);
2377
+ const transformVersion = this.entityManager.getEntityDataVersion(import_document6.FlowNodeTransformData);
2378
+ if (this.outsidePortNodesCache && this.outsidePortNodesCache.nodeVersion === nodeVersion && this.outsidePortNodesCache.portVersion === portVersion && this.outsidePortNodesCache.transformVersion === transformVersion && this.outsidePortNodesCache.sortedNodes === sortedNodes) {
2379
+ return this.outsidePortNodesCache.outsideNodes;
2380
+ }
2381
+ const outsideNodes = sortedNodes.filter((node) => this.hasPortOutsideNodeBounds(node));
2382
+ this.outsidePortNodesCache = {
2383
+ nodeVersion,
2384
+ portVersion,
2385
+ transformVersion,
2386
+ sortedNodes,
2387
+ outsideNodes
2388
+ };
2389
+ return outsideNodes;
2390
+ }
2133
2391
  getHoverNodes() {
2134
2392
  const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2135
2393
  const activatedID = this.selectService.activatedNode?.id;
@@ -2149,6 +2407,7 @@ var WorkflowLinesManager = class {
2149
2407
  this.hoverNodesCache = nodes;
2150
2408
  this.hoverNodesCacheVersion = nodeVersion;
2151
2409
  this.hoverNodesCacheActivatedID = activatedID;
2410
+ this.hoverNodeSpatialCache = void 0;
2152
2411
  return this.hoverNodesCache;
2153
2412
  }
2154
2413
  isPointInBounds(pos, bounds, padding = 0) {