@logicflow/core 2.0.7 → 2.0.9

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 (70) hide show
  1. package/.turbo/turbo-build$colon$dev.log +10 -10
  2. package/.turbo/turbo-build.log +33 -33
  3. package/CHANGELOG.md +18 -2
  4. package/__tests__/algorithm/egde.test.ts +4 -4
  5. package/dist/index.css +3 -0
  6. package/dist/index.min.js +1 -1
  7. package/dist/index.min.js.map +1 -1
  8. package/es/LogicFlow.d.ts +3 -0
  9. package/es/LogicFlow.js +4 -0
  10. package/es/algorithm/edge.js +3 -5
  11. package/es/constant/index.d.ts +4 -0
  12. package/es/constant/index.js +4 -0
  13. package/es/event/eventArgs.d.ts +27 -1
  14. package/es/index.css +3 -0
  15. package/es/model/GraphModel.d.ts +3 -0
  16. package/es/model/GraphModel.js +84 -7
  17. package/es/model/edge/LineEdgeModel.d.ts +2 -0
  18. package/es/model/edge/LineEdgeModel.js +8 -0
  19. package/es/model/edge/PolylineEdgeModel.d.ts +1 -0
  20. package/es/model/edge/PolylineEdgeModel.js +4 -3
  21. package/es/model/node/HtmlNodeModel.d.ts +2 -2
  22. package/es/style/index.css +3 -0
  23. package/es/style/index.less +5 -0
  24. package/es/style/raw.d.ts +1 -1
  25. package/es/style/raw.js +1 -1
  26. package/es/view/edge/BaseEdge.d.ts +2 -0
  27. package/es/view/edge/BaseEdge.js +13 -1
  28. package/es/view/node/BaseNode.d.ts +2 -0
  29. package/es/view/node/BaseNode.js +14 -2
  30. package/es/view/overlay/BackgroundOverlay.js +2 -1
  31. package/lib/LogicFlow.d.ts +3 -0
  32. package/lib/LogicFlow.js +4 -0
  33. package/lib/algorithm/edge.js +3 -5
  34. package/lib/constant/index.d.ts +4 -0
  35. package/lib/constant/index.js +4 -0
  36. package/lib/event/eventArgs.d.ts +27 -1
  37. package/lib/index.css +3 -0
  38. package/lib/model/GraphModel.d.ts +3 -0
  39. package/lib/model/GraphModel.js +83 -6
  40. package/lib/model/edge/LineEdgeModel.d.ts +2 -0
  41. package/lib/model/edge/LineEdgeModel.js +8 -0
  42. package/lib/model/edge/PolylineEdgeModel.d.ts +1 -0
  43. package/lib/model/edge/PolylineEdgeModel.js +4 -3
  44. package/lib/model/node/HtmlNodeModel.d.ts +2 -2
  45. package/lib/style/index.css +3 -0
  46. package/lib/style/index.less +5 -0
  47. package/lib/style/raw.d.ts +1 -1
  48. package/lib/style/raw.js +1 -1
  49. package/lib/view/edge/BaseEdge.d.ts +2 -0
  50. package/lib/view/edge/BaseEdge.js +13 -1
  51. package/lib/view/node/BaseNode.d.ts +2 -0
  52. package/lib/view/node/BaseNode.js +14 -2
  53. package/lib/view/overlay/BackgroundOverlay.js +2 -1
  54. package/package.json +1 -1
  55. package/src/LogicFlow.tsx +6 -0
  56. package/src/algorithm/edge.ts +1 -1
  57. package/src/algorithm/outline.ts +1 -1
  58. package/src/constant/index.ts +4 -0
  59. package/src/event/eventArgs.ts +27 -1
  60. package/src/model/GraphModel.ts +111 -3
  61. package/src/model/edge/LineEdgeModel.ts +8 -0
  62. package/src/model/edge/PolylineEdgeModel.ts +5 -3
  63. package/src/style/index.less +5 -0
  64. package/src/style/raw.ts +3 -0
  65. package/src/view/Graph.tsx +3 -4
  66. package/src/view/edge/BaseEdge.tsx +16 -0
  67. package/src/view/node/BaseNode.tsx +17 -1
  68. package/src/view/overlay/BackgroundOverlay.tsx +11 -16
  69. package/src/view/overlay/OutlineOverlay.tsx +1 -1
  70. package/stats.html +1 -1
@@ -1,4 +1,4 @@
1
- import { find, forEach, map, merge } from 'lodash-es'
1
+ import { find, forEach, map, merge, isBoolean, debounce, isEqual } from 'lodash-es'
2
2
  import { action, computed, observable } from 'mobx'
3
3
  import {
4
4
  BaseEdgeModel,
@@ -41,6 +41,7 @@ import Position = LogicFlow.Position
41
41
  import PointTuple = LogicFlow.PointTuple
42
42
  import GraphData = LogicFlow.GraphData
43
43
  import NodeConfig = LogicFlow.NodeConfig
44
+ import AnchorConfig = Model.AnchorConfig
44
45
  import BaseNodeModelCtor = LogicFlow.BaseNodeModelCtor
45
46
  import BaseEdgeModelCtor = LogicFlow.BaseEdgeModelCtor
46
47
 
@@ -127,6 +128,8 @@ export class GraphModel {
127
128
  // 用户自定义属性
128
129
  [propName: string]: any
129
130
 
131
+ private waitCleanEffects: (() => void)[] = []
132
+
130
133
  constructor(options: LFOptions.Common) {
131
134
  const {
132
135
  container,
@@ -153,6 +156,27 @@ export class GraphModel {
153
156
  this.width = options.width || this.rootEl.getBoundingClientRect().width
154
157
  this.height = options.height || this.rootEl.getBoundingClientRect().height
155
158
 
159
+ const resizeObserver = new ResizeObserver(
160
+ debounce(
161
+ ((entries) => {
162
+ for (const entry of entries) {
163
+ if (entry.target === this.rootEl) {
164
+ this.resize()
165
+ this.eventCenter.emit('graph:resize', {
166
+ target: this.rootEl,
167
+ contentRect: entry.contentRect,
168
+ })
169
+ }
170
+ }
171
+ }) as ResizeObserverCallback,
172
+ 16,
173
+ ),
174
+ )
175
+ resizeObserver.observe(this.rootEl)
176
+ this.waitCleanEffects.push(() => {
177
+ resizeObserver.disconnect()
178
+ })
179
+
156
180
  this.eventCenter = new EventEmitter()
157
181
  this.editConfigModel = new EditConfigModel(options)
158
182
  this.transformModel = new TransformModel(this.eventCenter, options)
@@ -439,6 +463,58 @@ export class GraphModel {
439
463
  throw new Error(`找不到${edge.type}对应的边。`)
440
464
  }
441
465
  const edgeModel = new Model(edge, this)
466
+ // 根据edgeModel中存储的数据找到当前画布上的起终锚点坐标
467
+ // 判断当前起终锚点数据和Model中存储的起终点数据是否一致,不一致更新起终点信息
468
+ const {
469
+ sourceNodeId,
470
+ targetNodeId,
471
+ sourceAnchorId = '',
472
+ targetAnchorId = '',
473
+ startPoint,
474
+ endPoint,
475
+ text,
476
+ textPosition,
477
+ } = edgeModel
478
+ const updateAnchorPoint = (
479
+ node: BaseNodeModel | undefined,
480
+ anchorId: string,
481
+ point: Position,
482
+ updatePoint: (anchor: AnchorConfig) => void,
483
+ ) => {
484
+ const anchor = node?.anchors.find((anchor) => anchor.id === anchorId)
485
+ if (anchor && !isEqual(anchor, point)) {
486
+ updatePoint(anchor)
487
+ }
488
+ }
489
+
490
+ const sourceNode = this.getNodeModelById(sourceNodeId)
491
+ const targetNode = this.getNodeModelById(targetNodeId)
492
+
493
+ updateAnchorPoint(
494
+ sourceNode,
495
+ sourceAnchorId,
496
+ startPoint,
497
+ edgeModel.updateStartPoint.bind(edgeModel),
498
+ )
499
+ updateAnchorPoint(
500
+ targetNode,
501
+ targetAnchorId,
502
+ endPoint,
503
+ edgeModel.updateEndPoint.bind(edgeModel),
504
+ )
505
+
506
+ // 而文本需要先算一下文本与默认文本位置之间的相对位置差
507
+ // 再计算新路径的文本默认位置,加上相对位置差,得到调整后边的文本的位置
508
+ if (text) {
509
+ const { x, y } = text
510
+ const { x: defaultX, y: defaultY } = textPosition
511
+ if (x && y && defaultX && defaultY) {
512
+ const deltaX = x - defaultX
513
+ const deltaY = y - defaultY
514
+ edgeModel.resetTextPosition()
515
+ edgeModel.moveText(deltaX, deltaY)
516
+ }
517
+ }
442
518
  this.edgeModelMap.set(edgeModel.id, edgeModel)
443
519
  this.elementsModelMap.set(edgeModel.id, edgeModel)
444
520
 
@@ -749,11 +825,15 @@ export class GraphModel {
749
825
  */
750
826
  @action
751
827
  deleteNode(nodeId: string) {
752
- const nodeData = this.nodesMap[nodeId].model.getData()
828
+ const nodeModel = this.nodesMap[nodeId].model
829
+ const nodeData = nodeModel.getData()
753
830
  this.deleteEdgeBySource(nodeId)
754
831
  this.deleteEdgeByTarget(nodeId)
755
832
  this.nodes.splice(this.nodesMap[nodeId].index, 1)
756
- this.eventCenter.emit(EventType.NODE_DELETE, { data: nodeData })
833
+ this.eventCenter.emit(EventType.NODE_DELETE, {
834
+ data: nodeData,
835
+ model: nodeModel,
836
+ })
757
837
  }
758
838
 
759
839
  /**
@@ -1418,6 +1498,22 @@ export class GraphModel {
1418
1498
  merge(this.grid, options)
1419
1499
  }
1420
1500
 
1501
+ /**
1502
+ * 更新网格配置
1503
+ */
1504
+ updateBackgroundOptions(
1505
+ options: boolean | Partial<LFOptions.BackgroundConfig>,
1506
+ ) {
1507
+ if (isBoolean(options) || isBoolean(this.background)) {
1508
+ this.background = options
1509
+ } else {
1510
+ this.background = {
1511
+ ...this.background,
1512
+ ...options,
1513
+ }
1514
+ }
1515
+ }
1516
+
1421
1517
  /**
1422
1518
  * 重新设置画布的宽高
1423
1519
  */
@@ -1573,6 +1669,18 @@ export class GraphModel {
1573
1669
  @action setPartial(partial: boolean): void {
1574
1670
  this.partial = partial
1575
1671
  }
1672
+
1673
+ /** 销毁当前实例 */
1674
+ destroy() {
1675
+ try {
1676
+ this.waitCleanEffects.forEach((fn) => {
1677
+ fn()
1678
+ })
1679
+ } catch (err) {
1680
+ console.warn('error on destroy GraphModel', err)
1681
+ }
1682
+ this.waitCleanEffects.length = 0
1683
+ }
1576
1684
  }
1577
1685
 
1578
1686
  export namespace GraphModel {
@@ -17,6 +17,14 @@ export class LineEdgeModel extends BaseEdgeModel {
17
17
  ...cloneDeep(customStyle),
18
18
  }
19
19
  }
20
+ initEdgeData(data: LogicFlow.EdgeConfig): void {
21
+ super.initEdgeData(data)
22
+ this.points = this.getPath([this.startPoint, this.endPoint])
23
+ }
24
+ getPath(points: Point[]): string {
25
+ const [start, end] = points
26
+ return `${start.x},${start.y} ${end.x},${end.y}`
27
+ }
20
28
  getTextPosition(): Point {
21
29
  return {
22
30
  x: (this.startPoint.x + this.endPoint.x) / 2,
@@ -326,12 +326,14 @@ export class PolylineEdgeModel extends BaseEdgeModel {
326
326
  })
327
327
  }
328
328
 
329
+ getPath(points: Point[]): string {
330
+ return points.map((point) => `${point.x},${point.y}`).join(' ')
331
+ }
332
+
329
333
  @action
330
334
  initPoints() {
331
335
  if (this.pointsList.length > 0) {
332
- this.points = this.pointsList
333
- .map((point) => `${point.x},${point.y}`)
334
- .join(' ')
336
+ this.points = this.getPath(this.pointsList)
335
337
  } else {
336
338
  this.updatePoints()
337
339
  }
@@ -19,6 +19,11 @@
19
19
  cursor: move;
20
20
  }
21
21
 
22
+ // 在元素focus时浏览器会给元素outline设置一个5像素宽的默认样式,这里先全局禁用一下,后续再根据需要再做调整
23
+ *:focus {
24
+ outline: none;
25
+ }
26
+
22
27
  .lf-node-anchor {
23
28
  cursor: crosshair;
24
29
  }
package/src/style/raw.ts CHANGED
@@ -21,6 +21,9 @@ export const content = `.lf-graph {
21
21
  .lf-text-draggable {
22
22
  cursor: move;
23
23
  }
24
+ *:focus {
25
+ outline: none;
26
+ }
24
27
  .lf-node-anchor {
25
28
  cursor: crosshair;
26
29
  }
@@ -87,7 +87,7 @@ class Graph extends Component<IGraphProps> {
87
87
  if (options.height) {
88
88
  style.height = `${graphModel.height}px`
89
89
  }
90
- const { fakeNode, editConfigModel } = graphModel
90
+ const { fakeNode, editConfigModel, background } = graphModel
91
91
  const { adjustEdge } = editConfigModel
92
92
  return (
93
93
  <div className="lf-graph" flow-id={graphModel.flowId} style={style}>
@@ -112,9 +112,8 @@ class Graph extends Component<IGraphProps> {
112
112
  </ModificationOverlay>
113
113
  {/* 工具层:插件 */}
114
114
  <ToolOverlay graphModel={graphModel} tool={tool} />
115
- {options.background && (
116
- <BackgroundOverlay background={options.background} />
117
- )}
115
+ {/* 画布背景 */}
116
+ {background && <BackgroundOverlay background={background} />}
118
117
  {/* 画布网格 */}
119
118
  <Grid graphModel={graphModel} />
120
119
  </div>
@@ -459,6 +459,20 @@ export abstract class BaseEdge<P extends IProps> extends Component<
459
459
  this.toFront()
460
460
  }
461
461
 
462
+ handleFocus = () => {
463
+ const { model, graphModel } = this.props
464
+ graphModel.eventCenter.emit(EventType.EDGE_FOCUS, {
465
+ data: model.getData(),
466
+ })
467
+ }
468
+
469
+ handleBlur = () => {
470
+ const { model, graphModel } = this.props
471
+ graphModel.eventCenter.emit(EventType.EDGE_BLUR, {
472
+ data: model.getData(),
473
+ })
474
+ }
475
+
462
476
  /**
463
477
  * @overridable 支持重写, 此方法为获取边的形状,如果需要自定义边的形状,请重写此方法。
464
478
  * @example https://docs.logic-flow.cn/docs/#/zh/guide/basic/edge?id=%e5%9f%ba%e4%ba%8e-react-%e7%bb%84%e4%bb%b6%e8%87%aa%e5%ae%9a%e4%b9%89%e8%be%b9
@@ -499,6 +513,8 @@ export abstract class BaseEdge<P extends IProps> extends Component<
499
513
  onMouseOver={this.setHoverOn}
500
514
  onMouseEnter={this.setHoverOn}
501
515
  onMouseLeave={this.setHoverOff}
516
+ onFocus={this.handleFocus}
517
+ onBlur={this.handleBlur}
502
518
  >
503
519
  {this.getShape()}
504
520
  {this.getAppend()}
@@ -377,7 +377,7 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
377
377
  // 不是双击的,默认都是单击
378
378
  if (isDoubleClick) {
379
379
  if (editConfigModel.nodeTextEdit) {
380
- if (model.text.editable) {
380
+ if (model.text.editable && editConfigModel.textMode === TextMode.TEXT) {
381
381
  model.setSelected(false)
382
382
  graphModel.setElementStateById(model.id, ElementState.TEXT_EDIT)
383
383
  }
@@ -424,6 +424,20 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
424
424
  }
425
425
  }
426
426
 
427
+ handleFocus = () => {
428
+ const { model, graphModel } = this.props
429
+ graphModel.eventCenter.emit(EventType.NODE_FOCUS, {
430
+ data: model.getData(),
431
+ })
432
+ }
433
+
434
+ handleBlur = () => {
435
+ const { model, graphModel } = this.props
436
+ graphModel.eventCenter.emit(EventType.NODE_BLUR, {
437
+ data: model.getData(),
438
+ })
439
+ }
440
+
427
441
  // 因为自定义节点的时候,可能会基于hover状态自定义不同的样式。
428
442
  setHoverOn = (ev: MouseEvent) => {
429
443
  const { model, graphModel } = this.props
@@ -508,6 +522,8 @@ export abstract class BaseNode<P extends IProps = IProps> extends Component<
508
522
  onMouseLeave={this.setHoverOff}
509
523
  onMouseOut={this.onMouseOut}
510
524
  onContextMenu={this.handleContextMenu}
525
+ onFocus={this.handleFocus}
526
+ onBlur={this.handleBlur}
511
527
  {...restAttributes}
512
528
  >
513
529
  {nodeShapeInner}
@@ -1,36 +1,31 @@
1
1
  import { Component } from 'preact/compat'
2
+ import { isObject } from 'lodash-es'
3
+ import { Options as LFOptions } from '../../options'
4
+ import { observer } from '../..'
2
5
 
3
6
  /**
4
7
  * 背景配置, 支持css属性配置
5
8
  * https://developer.mozilla.org/zh-CN/docs/Web/CSS/background
6
9
  * @example
7
10
  * {
8
- * backgroundImage: "url('./img/grid.svg')",
9
- backgroundRepeat: 'repeat',
11
+ * backgroundImage: "url('./img/grid.svg')",
12
+ backgroundRepeat: 'repeat',
10
13
  * }
11
14
  */
12
- export type BackgroundConfig = {
13
- /**
14
- * 背景图片地址
15
- */
16
- backgroundImage?: string
17
- /**
18
- * 是否重复
19
- */
20
- backgroundRepeat?: string
21
- [key: string]: any
22
- }
23
-
24
15
  type IProps = {
25
- background: BackgroundConfig
16
+ background: boolean | LFOptions.BackgroundConfig
26
17
  }
27
18
 
19
+ @observer
28
20
  export class BackgroundOverlay extends Component<IProps> {
29
21
  render() {
30
22
  const { background } = this.props
31
23
  return (
32
24
  <div className="lf-background">
33
- <div style={background} className="lf-background-area" />
25
+ <div
26
+ style={isObject(background) ? background : {}}
27
+ className="lf-background-area"
28
+ />
34
29
  </div>
35
30
  )
36
31
  }
@@ -82,7 +82,7 @@ export class OutlineOverlay extends Component<IProps> {
82
82
  (hoverOutline && edge.isHovered)
83
83
  ) {
84
84
  if (edge.modelType === ModelType.LINE_EDGE) {
85
- edgeOutline.push(this.getLineOutline(edge))
85
+ edgeOutline.push(this.getLineOutline(edge as LineEdgeModel))
86
86
  } else if (edge.modelType === ModelType.POLYLINE_EDGE) {
87
87
  edgeOutline.push(this.getPolylineOutline(edge as PolylineEdgeModel))
88
88
  } else if (edge.modelType === ModelType.BEZIER_EDGE) {