@flowgram.ai/free-layout-core 0.1.0-alpha.37 → 0.1.0-alpha.39

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.js CHANGED
@@ -365,14 +365,7 @@ var WorkflowPortEntity = class extends import_core4.Entity {
365
365
  );
366
366
  }
367
367
  isHovered(x, y) {
368
- const { point } = this;
369
- const size = this._size || { width: PORT_SIZE, height: PORT_SIZE };
370
- const halfWidth = size.width / 2;
371
- const halfHeight = size.height / 2;
372
- if (size.width <= 0 || size.height <= 0) {
373
- return false;
374
- }
375
- return x >= point.x - halfWidth && x <= point.x + halfWidth && y >= point.y - halfHeight && y <= point.y + halfHeight;
368
+ return this.bounds.contains(x, y);
376
369
  }
377
370
  /**
378
371
  * 相对节点左上角的位置
@@ -473,7 +466,6 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
473
466
  this._staticPorts = [];
474
467
  /** 存储 port 实体的 id,用于判断 port 是否存在 */
475
468
  this._portIDSet = /* @__PURE__ */ new Set();
476
- this._portDisposeIDSet = /* @__PURE__ */ new Set();
477
469
  this.entity = entity;
478
470
  const meta = entity.getNodeMeta();
479
471
  const defaultPorts = meta.useDynamicPort ? [] : [{ type: "input" }, { type: "output" }];
@@ -560,7 +552,6 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
560
552
  });
561
553
  ports.forEach((port) => this.updatePortEntity(port));
562
554
  this._prePorts = ports;
563
- this.clearPortsCache();
564
555
  this.fireChange();
565
556
  }
566
557
  this.allPorts.forEach((port) => {
@@ -573,28 +564,19 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
573
564
  * 获取所有 port entities
574
565
  */
575
566
  get allPorts() {
576
- if (!this._allPortsCache) {
577
- this._allPortsCache = Array.from(this._portIDSet).map((portId) => this.getPortEntity(portId)).filter(Boolean);
578
- }
579
- return this._allPortsCache;
567
+ return Array.from(this._portIDSet).map((portId) => this.getPortEntity(portId)).filter(Boolean);
580
568
  }
581
569
  /**
582
570
  * 获取输入点位
583
571
  */
584
572
  get inputPorts() {
585
- if (!this._inputPortsCache) {
586
- this._inputPortsCache = this.allPorts.filter((port) => port.portType === "input");
587
- }
588
- return this._inputPortsCache;
573
+ return this.allPorts.filter((port) => port.portType === "input");
589
574
  }
590
575
  /**
591
576
  * 获取输出点位
592
577
  */
593
578
  get outputPorts() {
594
- if (!this._outputPortsCache) {
595
- this._outputPortsCache = this.allPorts.filter((port) => port.portType === "output");
596
- }
597
- return this._outputPortsCache;
579
+ return this.allPorts.filter((port) => port.portType === "output");
598
580
  }
599
581
  /**
600
582
  * 获取输入点位置
@@ -606,7 +588,7 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
606
588
  * 获取输出点位置
607
589
  */
608
590
  get outputPoints() {
609
- return this.outputPorts.map((port) => port.point);
591
+ return this.inputPorts.map((port) => port.point);
610
592
  }
611
593
  /**
612
594
  * 根据 key 获取 输入点位置
@@ -635,11 +617,6 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
635
617
  getPortId(portType, portKey = "") {
636
618
  return getPortEntityId(this.entity, portType, portKey);
637
619
  }
638
- clearPortsCache() {
639
- this._allPortsCache = void 0;
640
- this._inputPortsCache = void 0;
641
- this._outputPortsCache = void 0;
642
- }
643
620
  /**
644
621
  * 创建 port 实体
645
622
  */
@@ -653,18 +630,10 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
653
630
  ...portInfo
654
631
  });
655
632
  }
656
- if (!this._portDisposeIDSet.has(id)) {
657
- this._portDisposeIDSet.add(id);
658
- portEntity.onDispose(() => {
659
- this._portIDSet.delete(id);
660
- this._portDisposeIDSet.delete(id);
661
- this.clearPortsCache();
662
- });
663
- }
664
- if (!this._portIDSet.has(id)) {
665
- this._portIDSet.add(id);
666
- this.clearPortsCache();
667
- }
633
+ portEntity.onDispose(() => {
634
+ this._portIDSet.delete(id);
635
+ });
636
+ this._portIDSet.add(id);
668
637
  return portEntity;
669
638
  }
670
639
  /**
@@ -1522,6 +1491,7 @@ var import_document10 = require("@flowgram.ai/document");
1522
1491
  var import_core15 = require("@flowgram.ai/core");
1523
1492
 
1524
1493
  // src/workflow-lines-manager.ts
1494
+ var import_lodash_es3 = require("lodash-es");
1525
1495
  var import_inversify3 = require("inversify");
1526
1496
  var import_utils12 = require("@flowgram.ai/utils");
1527
1497
  var import_document6 = require("@flowgram.ai/document");
@@ -1642,12 +1612,6 @@ var WorkflowDocumentOptionsDefault = {
1642
1612
  };
1643
1613
 
1644
1614
  // 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;
1651
1615
  var WorkflowLinesManager = class {
1652
1616
  constructor() {
1653
1617
  this.toDispose = new import_utils12.DisposableCollection();
@@ -1671,35 +1635,11 @@ var WorkflowLinesManager = class {
1671
1635
  this.isDrawing = false;
1672
1636
  }
1673
1637
  init(doc) {
1674
- if (this.document === doc) {
1675
- return;
1676
- }
1677
1638
  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
- ]);
1694
1639
  }
1695
1640
  forceUpdate() {
1696
1641
  this.onForceUpdateEmitter.fire();
1697
1642
  }
1698
- invalidateSortedNodesCache() {
1699
- this.sortedNodesCache = void 0;
1700
- this.sortedNodesCacheVersion = void 0;
1701
- this.invalidateNodeHitCaches();
1702
- }
1703
1643
  get lineType() {
1704
1644
  return this._lineType;
1705
1645
  }
@@ -1728,7 +1668,6 @@ var WorkflowLinesManager = class {
1728
1668
  }
1729
1669
  if (newType !== this._lineType) {
1730
1670
  this._lineType = newType;
1731
- this.lineSpatialCache = void 0;
1732
1671
  this.getAllLines().forEach((line) => {
1733
1672
  line.getData(WorkflowLineRenderData).update();
1734
1673
  });
@@ -1887,26 +1826,17 @@ var WorkflowLinesManager = class {
1887
1826
  */
1888
1827
  getCloseInLineFromMousePos(mousePos, minDistance = LINE_HOVER_DISTANCE) {
1889
1828
  let targetLine, targetLineDist;
1890
- const lines = this.getLineHitCandidates(mousePos, minDistance);
1891
- for (let i = 0; i < lines.length; i++) {
1892
- const line = lines[i];
1893
- if (!this.isPointInBounds(mousePos, line.bounds, minDistance)) {
1894
- continue;
1895
- }
1829
+ this.getAllLines().forEach((line) => {
1896
1830
  const dist = line.getHoverDist(mousePos);
1897
- if (dist <= minDistance && (targetLineDist === void 0 || targetLineDist >= dist)) {
1831
+ if (dist <= minDistance && (!targetLineDist || targetLineDist >= dist)) {
1898
1832
  targetLineDist = dist;
1899
1833
  targetLine = line;
1900
1834
  }
1901
- }
1835
+ });
1902
1836
  return targetLine;
1903
1837
  }
1904
1838
  dispose() {
1905
1839
  this.portLineMap.clear();
1906
- this.sortedNodeSpatialCache = void 0;
1907
- this.hoverNodeSpatialCache = void 0;
1908
- this.lineSpatialCache = void 0;
1909
- this.outsidePortNodesCache = void 0;
1910
1840
  this.toDispose.dispose();
1911
1841
  }
1912
1842
  get disposed() {
@@ -2021,45 +1951,39 @@ var WorkflowLinesManager = class {
2021
1951
  * @param pos
2022
1952
  */
2023
1953
  getPortFromMousePos(pos, portType) {
2024
- return this.getHoveredPortFromSortedNodes(pos, this.getSortedNodes(), portType);
2025
- }
2026
- getPortsFromMousePos(pos) {
2027
- return this.getHoveredPortsFromSortedNodes(pos, this.getSortedNodes(), void 0, {
2028
- collectBoth: true
2029
- });
2030
- }
2031
- getNodeAndPortFromMousePos(pos, portType) {
2032
- const sortedNodes = this.getSortedNodes();
2033
- const nodeHitInfo = this.getNodeHitInfoFromSortedNodes(
2034
- pos,
2035
- sortedNodes,
2036
- this.selectService.selection
2037
- );
2038
- const ports = this.getHoveredPortsFromSortedNodes(pos, sortedNodes, portType, {
2039
- topCoverNode: nodeHitInfo.topCoverNode
2040
- });
2041
- return {
2042
- node: nodeHitInfo.topNode,
2043
- port: ports.port
2044
- };
2045
- }
2046
- getHoverNodeFromMousePos(pos) {
2047
- const nodes = this.getHoverNodes();
2048
- const candidates = this.getHoverNodeHitCandidates(pos, nodes);
2049
- for (let i = 0; i < candidates.length; i++) {
2050
- const node = candidates[i];
2051
- const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2052
- if (this.isPointInBounds(pos, bounds)) {
2053
- return node;
1954
+ const allNodes = this.getSortedNodes().reverse();
1955
+ const allPorts = allNodes.map((node) => {
1956
+ if (!portType) {
1957
+ return node.ports.allPorts;
1958
+ }
1959
+ return portType === "input" ? node.ports.inputPorts : node.ports.outputPorts;
1960
+ }).flat();
1961
+ const targetPort = allPorts.find((port) => port.isHovered(pos.x, pos.y));
1962
+ if (targetPort) {
1963
+ const containNodes = this.getContainNodesFromMousePos(pos);
1964
+ const targetNode = (0, import_lodash_es3.last)(containNodes);
1965
+ if (targetNode && targetNode !== targetPort.node) {
1966
+ return;
2054
1967
  }
2055
1968
  }
1969
+ return targetPort;
2056
1970
  }
2057
1971
  /**
2058
1972
  * 根据鼠标位置找到 node
2059
1973
  * @param pos - 鼠标位置
2060
1974
  */
2061
1975
  getNodeFromMousePos(pos) {
2062
- return this.getTopNodeFromSortedNodes(pos, this.getSortedNodes(), this.selectService.selection);
1976
+ const { selection } = this.selectService;
1977
+ const containNodes = this.getContainNodesFromMousePos(pos);
1978
+ if (selection?.length) {
1979
+ const filteredNodes = containNodes.filter(
1980
+ (node) => selection.some((_node) => node.id === _node.id)
1981
+ );
1982
+ if (filteredNodes?.length) {
1983
+ return (0, import_lodash_es3.last)(filteredNodes);
1984
+ }
1985
+ }
1986
+ return (0, import_lodash_es3.last)(containNodes);
2063
1987
  }
2064
1988
  registerContribution(factory) {
2065
1989
  this.contributionFactories.push(factory);
@@ -2069,352 +1993,19 @@ var WorkflowLinesManager = class {
2069
1993
  line.addData(WorkflowLineRenderData);
2070
1994
  }
2071
1995
  getSortedNodes() {
2072
- const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2073
- if (this.sortedNodesCache && this.sortedNodesCacheVersion === nodeVersion) {
2074
- return this.sortedNodesCache;
2075
- }
2076
- this.sortedNodesCache = [...this.document.getAllNodes()].sort(
2077
- (a, b) => this.getNodeIndex(a) - this.getNodeIndex(b)
2078
- );
2079
- this.sortedNodesCacheVersion = nodeVersion;
2080
- this.sortedNodeSpatialCache = void 0;
2081
- this.outsidePortNodesCache = void 0;
2082
- return this.sortedNodesCache;
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
- }
2096
- getHoveredPortFromSortedNodes(pos, sortedNodes, portType) {
2097
- return this.getHoveredPortsFromSortedNodes(pos, sortedNodes, portType).port;
2098
- }
2099
- getHoveredPortsFromSortedNodes(pos, sortedNodes, portType, options = {}) {
2100
- let inputPort;
2101
- let outputPort;
2102
- let anyPort;
2103
- const { collectBoth = false } = options;
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;
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;
2125
- if (portType === "input" && inputPort || portType === "output" && outputPort || !portType && (collectBoth ? inputPort && outputPort : anyPort)) {
2126
- break;
2127
- }
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
- }
2152
- const needCoverCheck = inputPort || outputPort || anyPort;
2153
- const topCoverNode = needCoverCheck ? options.topCoverNode || this.getNodeHitInfoFromSortedNodes(pos, sortedNodes).topCoverNode : void 0;
2154
- inputPort = this.filterCoveredPort(inputPort, topCoverNode);
2155
- outputPort = this.filterCoveredPort(outputPort, topCoverNode);
2156
- anyPort = this.filterCoveredPort(anyPort, topCoverNode);
2157
- return {
2158
- input: inputPort,
2159
- output: outputPort,
2160
- port: portType === "input" ? inputPort : portType === "output" ? outputPort : anyPort
2161
- };
1996
+ return this.document.getAllNodes().sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
2162
1997
  }
2163
- collectHoveredPorts(ports, pos, options) {
2164
- let { inputPort, outputPort, anyPort } = options;
2165
- for (let i = 0; i < ports.length; i++) {
2166
- const port = ports[i];
2167
- if ((!options.needAny || anyPort) && (!options.needInput || inputPort) && (!options.needOutput || outputPort)) {
2168
- break;
2169
- }
2170
- if (port.isHovered(pos.x, pos.y)) {
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
- }
2180
- }
2181
- }
2182
- return {
2183
- inputPort,
2184
- outputPort,
2185
- anyPort
2186
- };
2187
- }
2188
- filterCoveredPort(port, topCoverNode) {
2189
- if (port && topCoverNode && topCoverNode !== port.node) {
2190
- return void 0;
2191
- }
2192
- return port;
2193
- }
2194
- getTopNodeFromSortedNodes(pos, sortedNodes, selection) {
2195
- return this.getNodeHitInfoFromSortedNodes(pos, sortedNodes, selection).topNode;
2196
- }
2197
- getNodeHitInfoFromSortedNodes(pos, sortedNodes, selection) {
1998
+ /** 获取鼠标坐标位置的所有节点(stackIndex 从小到大排序) */
1999
+ getContainNodesFromMousePos(pos) {
2000
+ const allNodes = this.getSortedNodes();
2198
2001
  const zoom = this.entityManager.getEntity(import_core12.PlaygroundConfigEntity)?.config?.zoom || 1;
2199
- const padding = 4 / zoom;
2200
- const selectedIDs = selection?.length ? new Set(selection.map((node) => node.id)) : void 0;
2201
- const candidates = this.getSortedNodeHitCandidates(pos, sortedNodes, padding);
2202
- let topCoverNode;
2203
- for (let i = candidates.length - 1; i >= 0; i--) {
2204
- const node = candidates[i];
2002
+ const containNodes = allNodes.map((node) => {
2205
2003
  const { bounds } = node.getData(import_document6.FlowNodeTransformData);
2206
- if (!this.isPointInBounds(pos, bounds, padding)) {
2207
- continue;
2208
- }
2209
- if (!topCoverNode) {
2210
- topCoverNode = node;
2211
- }
2212
- if (!selectedIDs) {
2213
- return {
2214
- topCoverNode,
2215
- topNode: node
2216
- };
2217
- }
2218
- if (selectedIDs.has(node.id)) {
2219
- return {
2220
- topCoverNode,
2221
- topNode: node
2222
- };
2223
- }
2224
- }
2225
- return {
2226
- topCoverNode,
2227
- topNode: topCoverNode
2228
- };
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
- }
2391
- getHoverNodes() {
2392
- const nodeVersion = this.entityManager.getEntityVersion(WorkflowNodeEntity);
2393
- const activatedID = this.selectService.activatedNode?.id;
2394
- if (this.hoverNodesCache && this.hoverNodesCacheVersion === nodeVersion && this.hoverNodesCacheActivatedID === activatedID) {
2395
- return this.hoverNodesCache;
2396
- }
2397
- const nodes = this.document.getAllNodes().filter(
2398
- (node) => node.id !== "root" && node.flowNodeType !== import_document6.FlowNodeBaseType.ROOT && node.flowNodeType !== import_document6.FlowNodeBaseType.GROUP
2399
- ).reverse();
2400
- if (activatedID) {
2401
- const activatedIndex = nodes.findIndex((node) => node.id === activatedID);
2402
- if (activatedIndex > 0) {
2403
- const [activatedNode] = nodes.splice(activatedIndex, 1);
2404
- nodes.unshift(activatedNode);
2004
+ if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
2005
+ return node;
2405
2006
  }
2406
- }
2407
- this.hoverNodesCache = nodes;
2408
- this.hoverNodesCacheVersion = nodeVersion;
2409
- this.hoverNodesCacheActivatedID = activatedID;
2410
- this.hoverNodeSpatialCache = void 0;
2411
- return this.hoverNodesCache;
2412
- }
2413
- isPointInBounds(pos, bounds, padding = 0) {
2414
- if (bounds.width + padding * 2 <= 0 || bounds.height + padding * 2 <= 0) {
2415
- return false;
2416
- }
2417
- return pos.x >= bounds.x - padding && pos.x <= bounds.right + padding && pos.y >= bounds.y - padding && pos.y <= bounds.bottom + padding;
2007
+ }).filter(Boolean);
2008
+ return containNodes;
2418
2009
  }
2419
2010
  getNodeIndex(node) {
2420
2011
  const nodeRenderData = node.getData(import_document6.FlowNodeRenderData);
@@ -3816,15 +3407,15 @@ var WorkflowDragService = class {
3816
3407
  }
3817
3408
  updateDrawingLine(isDrawingTo, line, dragPos, originLine) {
3818
3409
  let hasError = false;
3410
+ const mouseNode = this.linesManager.getNodeFromMousePos(dragPos);
3819
3411
  let toNode;
3820
3412
  let toPort;
3821
3413
  let fromPort;
3822
3414
  let fromNode;
3823
3415
  if (isDrawingTo) {
3824
- const mouseHitInfo = this.linesManager.getNodeAndPortFromMousePos(dragPos, "input");
3825
3416
  fromPort = line.fromPort;
3826
- toNode = mouseHitInfo.node;
3827
- toPort = mouseHitInfo.port;
3417
+ toNode = mouseNode;
3418
+ toPort = this.linesManager.getPortFromMousePos(dragPos, "input");
3828
3419
  if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
3829
3420
  toPort = this.getNearestPort(toNode, dragPos, "input");
3830
3421
  hasError = this.checkDraggingPort(isDrawingTo, line, toNode, toPort, originLine).hasError;
@@ -3851,10 +3442,9 @@ var WorkflowDragService = class {
3851
3442
  };
3852
3443
  }
3853
3444
  } else {
3854
- const mouseHitInfo = this.linesManager.getNodeAndPortFromMousePos(dragPos, "output");
3855
3445
  toPort = line.toPort;
3856
- fromNode = mouseHitInfo.node;
3857
- fromPort = mouseHitInfo.port;
3446
+ fromNode = mouseNode;
3447
+ fromPort = this.linesManager.getPortFromMousePos(dragPos, "output");
3858
3448
  if (fromNode && this.canBuildContainerLine(fromNode, dragPos)) {
3859
3449
  fromPort = this.getNearestPort(fromNode, dragPos, "output");
3860
3450
  hasError = this.checkDraggingPort(