@logicflow/core 2.2.0-alpha.7 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/package.json +6 -1
  2. package/.turbo/turbo-build$colon$dev.log +0 -10
  3. package/.turbo/turbo-build.log +0 -33
  4. package/CHANGELOG.md +0 -1901
  5. package/__tests__/algorithm/egde.test.ts +0 -131
  6. package/__tests__/algorithm/index.test.ts +0 -74
  7. package/__tests__/algorithm/outline.test.ts +0 -43
  8. package/__tests__/bugs/1545-spec.test.ts +0 -42
  9. package/__tests__/event/event.test.ts +0 -22
  10. package/__tests__/history/history.test.ts +0 -28
  11. package/__tests__/logicflow.test.ts +0 -575
  12. package/__tests__/model/graphmodel.test.ts +0 -87
  13. package/__tests__/util/compatible.test.ts +0 -48
  14. package/__tests__/util/edge.test.ts +0 -224
  15. package/__tests__/util/geometry.test.ts +0 -14
  16. package/__tests__/util/graph.test.ts +0 -16
  17. package/__tests__/util/matrix.test.ts +0 -41
  18. package/__tests__/util/node.test.ts +0 -68
  19. package/__tests__/util/sampling.test.ts +0 -12
  20. package/__tests__/util/vector.test.ts +0 -50
  21. package/__tests__/util/zIndex.test.ts +0 -10
  22. package/src/LogicFlow.tsx +0 -2017
  23. package/src/algorithm/edge.ts +0 -67
  24. package/src/algorithm/index.ts +0 -70
  25. package/src/algorithm/outline.ts +0 -77
  26. package/src/algorithm/rotate.ts +0 -55
  27. package/src/common/drag.ts +0 -219
  28. package/src/common/history.ts +0 -108
  29. package/src/common/index.ts +0 -6
  30. package/src/common/keyboard.ts +0 -108
  31. package/src/common/matrix.ts +0 -122
  32. package/src/common/vector.ts +0 -93
  33. package/src/constant/index.ts +0 -179
  34. package/src/constant/theme.ts +0 -708
  35. package/src/event/event.md +0 -66
  36. package/src/event/eventArgs.ts +0 -643
  37. package/src/event/eventEmitter.ts +0 -156
  38. package/src/history/index.ts +0 -119
  39. package/src/index.less +0 -1
  40. package/src/index.ts +0 -26
  41. package/src/keyboard/index.ts +0 -112
  42. package/src/keyboard/shortcut.ts +0 -200
  43. package/src/model/BaseModel.ts +0 -250
  44. package/src/model/EditConfigModel.ts +0 -334
  45. package/src/model/GraphModel.ts +0 -1824
  46. package/src/model/NestedTransformModel.ts +0 -121
  47. package/src/model/SnaplineModel.ts +0 -256
  48. package/src/model/TransformModel.ts +0 -258
  49. package/src/model/edge/BaseEdgeModel.ts +0 -785
  50. package/src/model/edge/BezierEdgeModel.ts +0 -197
  51. package/src/model/edge/LineEdgeModel.ts +0 -36
  52. package/src/model/edge/PolylineEdgeModel.ts +0 -817
  53. package/src/model/edge/index.ts +0 -4
  54. package/src/model/index.ts +0 -9
  55. package/src/model/node/BaseNodeModel.ts +0 -959
  56. package/src/model/node/CircleNodeModel.ts +0 -91
  57. package/src/model/node/DiamondNodeModel.ts +0 -132
  58. package/src/model/node/EllipseNodeModel.ts +0 -98
  59. package/src/model/node/HtmlNodeModel.ts +0 -64
  60. package/src/model/node/PolygonNodeModel.ts +0 -152
  61. package/src/model/node/RectNodeModel.ts +0 -69
  62. package/src/model/node/TextNodeModel.ts +0 -54
  63. package/src/model/node/index.ts +0 -8
  64. package/src/options.ts +0 -150
  65. package/src/style/index.less +0 -262
  66. package/src/style/raw.ts +0 -221
  67. package/src/tool/MultipleSelectTool.tsx +0 -140
  68. package/src/tool/TextEditTool.tsx +0 -193
  69. package/src/tool/index.ts +0 -101
  70. package/src/typings.d.ts +0 -5
  71. package/src/util/animation.ts +0 -29
  72. package/src/util/browser.ts +0 -4
  73. package/src/util/compatible.ts +0 -15
  74. package/src/util/drag.ts +0 -219
  75. package/src/util/edge.ts +0 -1094
  76. package/src/util/geometry.ts +0 -154
  77. package/src/util/graph.ts +0 -46
  78. package/src/util/index.ts +0 -17
  79. package/src/util/matrix.ts +0 -129
  80. package/src/util/mobx.ts +0 -23
  81. package/src/util/node.ts +0 -543
  82. package/src/util/raf.ts +0 -28
  83. package/src/util/resize.ts +0 -606
  84. package/src/util/sampling.ts +0 -85
  85. package/src/util/theme.ts +0 -84
  86. package/src/util/uuid.ts +0 -26
  87. package/src/util/vector.ts +0 -93
  88. package/src/util/zIndex.ts +0 -6
  89. package/src/view/Anchor.tsx +0 -462
  90. package/src/view/Control.tsx +0 -510
  91. package/src/view/Graph.tsx +0 -141
  92. package/src/view/Rotate.tsx +0 -113
  93. package/src/view/behavior/dnd.ts +0 -162
  94. package/src/view/behavior/index.ts +0 -2
  95. package/src/view/behavior/snapline.ts +0 -16
  96. package/src/view/edge/AdjustPoint.tsx +0 -425
  97. package/src/view/edge/Arrow.tsx +0 -54
  98. package/src/view/edge/BaseEdge.tsx +0 -660
  99. package/src/view/edge/BezierEdge.tsx +0 -101
  100. package/src/view/edge/LineEdge.tsx +0 -81
  101. package/src/view/edge/PolylineEdge.tsx +0 -311
  102. package/src/view/edge/index.ts +0 -6
  103. package/src/view/index.ts +0 -8
  104. package/src/view/node/BaseNode.tsx +0 -585
  105. package/src/view/node/CircleNode.tsx +0 -21
  106. package/src/view/node/DiamondNode.tsx +0 -24
  107. package/src/view/node/EllipseNode.tsx +0 -22
  108. package/src/view/node/HtmlNode.tsx +0 -112
  109. package/src/view/node/PolygonNode.tsx +0 -28
  110. package/src/view/node/RectNode.tsx +0 -30
  111. package/src/view/node/TextNode.tsx +0 -39
  112. package/src/view/node/index.ts +0 -8
  113. package/src/view/overlay/BackgroundOverlay.tsx +0 -34
  114. package/src/view/overlay/BezierAdjustOverlay.tsx +0 -150
  115. package/src/view/overlay/CanvasOverlay.tsx +0 -290
  116. package/src/view/overlay/Grid.tsx +0 -319
  117. package/src/view/overlay/ModificationOverlay.tsx +0 -31
  118. package/src/view/overlay/OutlineOverlay.tsx +0 -158
  119. package/src/view/overlay/SnaplineOverlay.tsx +0 -44
  120. package/src/view/overlay/ToolOverlay.tsx +0 -65
  121. package/src/view/overlay/getTransformHoc.tsx +0 -50
  122. package/src/view/overlay/gridConfig.ts +0 -103
  123. package/src/view/overlay/index.ts +0 -8
  124. package/src/view/shape/Circle.tsx +0 -41
  125. package/src/view/shape/Ellipse.tsx +0 -42
  126. package/src/view/shape/Line.tsx +0 -39
  127. package/src/view/shape/Path.tsx +0 -22
  128. package/src/view/shape/Polygon.tsx +0 -54
  129. package/src/view/shape/Polyline.tsx +0 -31
  130. package/src/view/shape/Rect.tsx +0 -44
  131. package/src/view/shape/Text.tsx +0 -168
  132. package/src/view/shape/index.ts +0 -8
  133. package/src/view/text/BaseText.tsx +0 -134
  134. package/src/view/text/LineText.tsx +0 -168
  135. package/src/view/text/index.ts +0 -2
  136. package/stats.html +0 -4842
  137. package/tsconfig.json +0 -18
@@ -1,112 +0,0 @@
1
- import { createRef } from 'preact/compat'
2
- import BaseNode from './BaseNode'
3
- import { GraphModel, HtmlNodeModel } from '../../model'
4
-
5
- export type IHtmlNodeProps = {
6
- model: HtmlNodeModel
7
- graphModel: GraphModel
8
- }
9
-
10
- export class HtmlNode<
11
- P extends IHtmlNodeProps = IHtmlNodeProps,
12
- > extends BaseNode<P> {
13
- ref = createRef()
14
- currentProperties?: string
15
- preProperties?: string
16
-
17
- get rootEl() {
18
- return this.ref.current
19
- }
20
-
21
- /**
22
- * @overridable 支持重写
23
- * 自定义HTML节点内容
24
- * @param {HTMLElement} rootEl 自定义HTML节点内容可以挂载的dom节点
25
- * @example
26
- * class CustomHtmlNode extends HtmlNode {
27
- * setHtml(rootEl) {
28
- * const input = document.createElement('input');
29
- * rootEl.appendChild(input)
30
- * }
31
- * }
32
- */
33
- setHtml(rootEl: SVGForeignObjectElement) {
34
- rootEl.appendChild(document.createElement('div'))
35
- }
36
-
37
- // TODO: 1. 应该在什么时机进行更新呢?2. 如何精细化控制
38
- confirmUpdate(rootEl: SVGForeignObjectElement) {
39
- this.setHtml(rootEl)
40
- }
41
-
42
- /**
43
- * @overridable 支持重写
44
- * 和react的shouldComponentUpdate类似,都是为了避免出发不必要的render.
45
- * 但是这里不一样的地方在于,setHtml方法,我们只在properties发生变化了后再触发。
46
- * 而x,y等这些坐标相关的方法发生了变化,不会再重新触发setHtml.
47
- */
48
- shouldUpdate() {
49
- if (this.preProperties && this.preProperties === this.currentProperties) {
50
- return false
51
- }
52
- this.preProperties = this.currentProperties
53
- return true
54
- }
55
-
56
- componentDidMount() {
57
- if (this.shouldUpdate() && this.rootEl) {
58
- this.setHtml(this.rootEl)
59
- }
60
- }
61
-
62
- componentDidUpdate() {
63
- // DONE: 将 componentDidMount 和 componentDidUpdate 区分开,如果写在一次,渲染 React 组件会重复初始化,消耗过多资源
64
- // 为了保证历史兼容性,先将默认 HTML 节点的 setHtml 和 confirmUpdate 保持一直,用户可通过自定义的方式重新定义
65
- if (this.shouldUpdate() && this.rootEl) {
66
- this.confirmUpdate(this.rootEl)
67
- }
68
- }
69
-
70
- componentWillUnmount() {
71
- super.componentWillUnmount()
72
- this.rootEl.innerHTML = ''
73
- }
74
-
75
- getShape() {
76
- const { model } = this.props
77
- const { x, y, height, width } = model
78
- const style = model.getNodeStyle()
79
- this.currentProperties = JSON.stringify(model.properties)
80
- return (
81
- <g>
82
- {style.shadow && (
83
- <defs>
84
- <filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
85
- <feDropShadow {...style.shadow} />
86
- </filter>
87
- </defs>
88
- )}
89
- <rect
90
- x={x - width / 2}
91
- y={y - height / 2}
92
- width={width}
93
- height={height}
94
- rx={style.radius}
95
- ry={style.radius}
96
- {...style}
97
- filter="url(#shadow)"
98
- />
99
- <foreignObject
100
- {...style}
101
- x={x - width / 2}
102
- y={y - height / 2}
103
- width={width}
104
- height={height}
105
- ref={this.ref}
106
- />
107
- </g>
108
- )
109
- }
110
- }
111
-
112
- export default HtmlNode
@@ -1,28 +0,0 @@
1
- import BaseNode from './BaseNode'
2
- import { Polygon } from '../shape'
3
- import { GraphModel, PolygonNodeModel } from '../../model'
4
-
5
- export type IPolygonNodeProps = {
6
- model: PolygonNodeModel
7
- graphModel: GraphModel
8
- }
9
-
10
- export class PolygonNode<
11
- P extends IPolygonNodeProps = IPolygonNodeProps,
12
- > extends BaseNode<P> {
13
- getShape() {
14
- const { model } = this.props
15
- const { x, y, width, height, points } = model as PolygonNodeModel
16
- const style = model.getNodeStyle()
17
- const attr = {
18
- transform: `matrix(1 0 0 1 ${x - width / 2} ${y - height / 2})`,
19
- }
20
- return (
21
- <g {...attr}>
22
- <Polygon {...style} points={points} x={x} y={y} />
23
- </g>
24
- )
25
- }
26
- }
27
-
28
- export default PolygonNode
@@ -1,30 +0,0 @@
1
- import { createElement as h } from 'preact/compat'
2
- import BaseNode from './BaseNode'
3
- import { Rect } from '../shape'
4
- import { GraphModel, RectNodeModel } from '../../model'
5
-
6
- export type IRectNodeProps = {
7
- model: RectNodeModel
8
- graphModel: GraphModel
9
- }
10
-
11
- export class RectNode<
12
- P extends IRectNodeProps = IRectNodeProps,
13
- > extends BaseNode<P> {
14
- getShape(): h.JSX.Element | null {
15
- const { model } = this.props
16
- const style = model.getNodeStyle()
17
- return (
18
- <Rect
19
- {...style}
20
- x={model.x}
21
- y={model.y}
22
- width={model.width}
23
- height={model.height}
24
- radius={model.radius}
25
- />
26
- )
27
- }
28
- }
29
-
30
- export default RectNode
@@ -1,39 +0,0 @@
1
- import Rect from '../shape/Rect'
2
- import BaseNode from './BaseNode'
3
- import { GraphModel, TextNodeModel } from '../../model'
4
-
5
- export type ITextNodeProps = {
6
- model: TextNodeModel
7
- graphModel: GraphModel
8
- }
9
-
10
- export class TextNode<
11
- P extends ITextNodeProps = ITextNodeProps,
12
- > extends BaseNode<P> {
13
- getBackground() {
14
- const { model } = this.props
15
- const style = model.getTextStyle()
16
- // 背景框宽度,最长一行字节数/2 * fontsize + 2
17
- // 背景框宽度, 行数 * fontsize + 2
18
- // FIX: #1067
19
- const { width, height, x, y } = model
20
- const rectAttr = {
21
- ...style.background,
22
- x,
23
- y,
24
- width,
25
- height,
26
- }
27
- return <Rect {...rectAttr} />
28
- }
29
-
30
- getResizeControl() {
31
- return null
32
- }
33
-
34
- getShape() {
35
- return <g>{this.getBackground()}</g>
36
- }
37
- }
38
-
39
- export default TextNode
@@ -1,8 +0,0 @@
1
- export * from './BaseNode'
2
- export * from './RectNode'
3
- export * from './CircleNode'
4
- export * from './PolygonNode'
5
- export * from './DiamondNode'
6
- export * from './EllipseNode'
7
- export * from './TextNode'
8
- export * from './HtmlNode'
@@ -1,34 +0,0 @@
1
- import { Component } from 'preact/compat'
2
- import { isObject } from 'lodash-es'
3
- import { Options as LFOptions } from '../../options'
4
- import { observer } from '../..'
5
-
6
- /**
7
- * 背景配置, 支持css属性配置
8
- * https://developer.mozilla.org/zh-CN/docs/Web/CSS/background
9
- * @example
10
- * {
11
- * backgroundImage: "url('./img/grid.svg')",
12
- backgroundRepeat: 'repeat',
13
- * }
14
- */
15
- type IProps = {
16
- background: boolean | LFOptions.BackgroundConfig
17
- }
18
-
19
- @observer
20
- export class BackgroundOverlay extends Component<IProps> {
21
- render() {
22
- const { background } = this.props
23
- return (
24
- <div className="lf-background">
25
- <div
26
- style={isObject(background) ? background : {}}
27
- className="lf-background-area"
28
- />
29
- </div>
30
- )
31
- }
32
- }
33
-
34
- export default BackgroundOverlay
@@ -1,150 +0,0 @@
1
- import { Component } from 'preact/compat'
2
- import { Circle, Line } from '../shape'
3
- import { observer } from '../..'
4
- import LogicFlow from '../../LogicFlow'
5
- import { EventType, ModelType } from '../../constant'
6
- import { StepDrag, getBezierPoints, IDragParams } from '../../util'
7
- import { GraphModel, BezierEdgeModel } from '../../model'
8
-
9
- import Point = LogicFlow.Point
10
-
11
- type IProps = {
12
- graphModel: GraphModel
13
- }
14
-
15
- type IAnchorProps = {
16
- position: Point
17
- bezierModel: BezierEdgeModel
18
- graphModel: GraphModel
19
- type: string
20
- }
21
-
22
- type IState = {
23
- endX: number
24
- endY: number
25
- }
26
-
27
- // bezier曲线的可调整锚点
28
- export class BezierAdjustAnchor extends Component<IAnchorProps, IState> {
29
- dragHandler: StepDrag
30
-
31
- constructor() {
32
- super()
33
- this.dragHandler = new StepDrag({
34
- onDragging: this.onDragging,
35
- onDragEnd: this.onDragEnd,
36
- })
37
- }
38
-
39
- onDragging = ({ event }: IDragParams) => {
40
- const { graphModel, bezierModel, type } = this.props
41
- const {
42
- canvasOverlayPosition: { x, y },
43
- } = graphModel.getPointByClient({
44
- x: event!.clientX,
45
- y: event!.clientY,
46
- })
47
- bezierModel.updateAdjustAnchor(
48
- {
49
- x,
50
- y,
51
- },
52
- type,
53
- )
54
- graphModel.eventCenter.emit(EventType.EDGE_ADJUST, {
55
- data: bezierModel.getData(),
56
- })
57
- }
58
- onDragEnd = () => {
59
- const { bezierModel } = this.props
60
- bezierModel.isDragging = false
61
- }
62
-
63
- render() {
64
- const { position } = this.props
65
- const { x, y } = position
66
- const { bezierModel } = this.props
67
- const { adjustAnchor } = bezierModel.getEdgeStyle()
68
- return (
69
- <Circle
70
- className="lf-bezier-adjust-anchor"
71
- x={x}
72
- y={y}
73
- {...adjustAnchor}
74
- onPointerDown={(ev) => {
75
- // if (edgeAddable !== false) {
76
- this.dragHandler.handleMouseDown(ev)
77
- // }
78
- }}
79
- />
80
- )
81
- }
82
- }
83
-
84
- @observer
85
- export class BezierAdjustOverlay extends Component<IProps> {
86
- getBezierAdjust(bezier: BezierEdgeModel, graphModel: GraphModel) {
87
- const { path, id } = bezier
88
- const pointsList = getBezierPoints(path)
89
- const [start, sNext, ePre, end] = pointsList
90
- const { adjustLine } = bezier.getEdgeStyle()
91
- const result: any = [] // TODO: 类型定义
92
- result.push(
93
- <Line
94
- x1={start.x}
95
- y1={start.y}
96
- x2={sNext.x}
97
- y2={sNext.y}
98
- {...adjustLine}
99
- />,
100
- )
101
- result.push(
102
- <BezierAdjustAnchor
103
- position={sNext}
104
- bezierModel={bezier}
105
- graphModel={graphModel}
106
- key={`${id}_ePre`}
107
- type="sNext"
108
- />,
109
- )
110
- result.push(
111
- <Line x1={end.x} y1={end.y} x2={ePre.x} y2={ePre.y} {...adjustLine} />,
112
- )
113
- result.push(
114
- <BezierAdjustAnchor
115
- position={ePre}
116
- bezierModel={bezier}
117
- graphModel={graphModel}
118
- key={`${id}_sNext`}
119
- type="ePre"
120
- />,
121
- )
122
- return result
123
- }
124
-
125
- // 获取选中bezier曲线,调整操作线和锚点
126
- selectedBezierEdge() {
127
- const { graphModel } = this.props
128
- const edgeList = graphModel.edges
129
- const edgeAdjust: any = [] // TODO:类型定义
130
- for (let i = 0; i < edgeList.length; i++) {
131
- const edge = edgeList[i]
132
- if (
133
- edge.isSelected &&
134
- edge.modelType === ModelType.BEZIER_EDGE &&
135
- edge.draggable
136
- ) {
137
- edgeAdjust.push(
138
- this.getBezierAdjust(edge as BezierEdgeModel, graphModel),
139
- )
140
- }
141
- }
142
- return edgeAdjust
143
- }
144
-
145
- render() {
146
- return <g className="lf-bezier-adjust">{this.selectedBezierEdge()}</g>
147
- }
148
- }
149
-
150
- export default BezierAdjustOverlay
@@ -1,290 +0,0 @@
1
- import { Component } from 'preact/compat'
2
- import Dnd from '../behavior/dnd'
3
- import { observer } from '../..'
4
- import GraphModel from '../../model/GraphModel'
5
- import { EventType } from '../../constant'
6
- import { StepDrag, IDragParams } from '../../util'
7
-
8
- type IProps = {
9
- graphModel: GraphModel
10
- dnd: Dnd
11
- }
12
- type IState = {
13
- isDragging: boolean
14
- }
15
-
16
- @observer
17
- export class CanvasOverlay extends Component<IProps, IState> {
18
- stepDrag: StepDrag
19
- stepScrollX = 0
20
- stepScrollY = 0
21
- pointers = new Map<number, { x: number; y: number }>()
22
- pinchStartDistance?: number
23
- pinchStartScale?: number
24
- pinchLastCenterX?: number
25
- pinchLastCenterY?: number
26
- longPressTimer?: number
27
-
28
- constructor(props: IProps) {
29
- super()
30
- const {
31
- graphModel: { gridSize, eventCenter },
32
- } = props
33
- this.stepDrag = new StepDrag({
34
- onDragging: this.onDragging,
35
- onDragEnd: this.onDragEnd,
36
- step: gridSize,
37
- eventType: 'BLANK',
38
- isStopPropagation: false,
39
- eventCenter,
40
- model: undefined,
41
- })
42
- // 当 ctrl、cmd 键被按住的时候,可以放大缩小。
43
- this.state = {
44
- isDragging: false,
45
- }
46
- }
47
-
48
- // get InjectedProps() {
49
- // return this.props as InjectedProps;
50
- // }
51
- onDragging = ({ deltaX, deltaY }: IDragParams) => {
52
- if (this.longPressTimer) {
53
- clearTimeout(this.longPressTimer)
54
- this.longPressTimer = undefined
55
- }
56
- this.setState({
57
- isDragging: true,
58
- })
59
- const {
60
- graphModel: { transformModel, editConfigModel },
61
- } = this.props
62
- if (editConfigModel.stopMoveGraph === true) {
63
- return
64
- }
65
- transformModel.translate(deltaX, deltaY)
66
- }
67
- onDragEnd = () => {
68
- this.setState({
69
- isDragging: false,
70
- })
71
- }
72
- zoomHandler = (ev: WheelEvent) => {
73
- const {
74
- graphModel: { editConfigModel, transformModel, gridSize },
75
- graphModel,
76
- } = this.props
77
- const { deltaX: eX, deltaY: eY } = ev
78
- const { stopScrollGraph, stopZoomGraph } = editConfigModel
79
- // 如果没有禁止滚动移动画布, 并且当前触发的时候ctrl键、cmd键没有按住, 那么移动画布
80
- if (!stopScrollGraph && !ev.ctrlKey && !ev.metaKey) {
81
- ev.preventDefault()
82
- this.stepScrollX += eX
83
- this.stepScrollY += eY
84
- if (Math.abs(this.stepScrollX) >= gridSize) {
85
- const remainderX = this.stepScrollX % gridSize
86
- const moveDistance = this.stepScrollX - remainderX
87
- transformModel.translate(-moveDistance * transformModel.SCALE_X, 0)
88
- this.stepScrollX = remainderX
89
- }
90
- if (Math.abs(this.stepScrollY) >= gridSize) {
91
- const remainderY = this.stepScrollY % gridSize
92
- const moveDistanceY = this.stepScrollY - remainderY
93
- transformModel.translate(0, -moveDistanceY * transformModel.SCALE_Y)
94
- this.stepScrollY = remainderY
95
- }
96
- return
97
- }
98
- // 如果没有禁止缩放画布,那么进行缩放. 在禁止缩放画布后,按住 ctrl、cmd 键也不能缩放了。
99
- if (!stopZoomGraph) {
100
- ev.preventDefault()
101
- const position = graphModel.getPointByClient({
102
- x: ev.clientX,
103
- y: ev.clientY,
104
- })
105
- const { x, y } = position.canvasOverlayPosition
106
- transformModel.zoom(ev.deltaY < 0, [x, y])
107
- }
108
- }
109
- clickHandler = (ev: MouseEvent) => {
110
- // 点击空白处取消节点选中状态, 不包括冒泡过来的事件。
111
- const target = ev.target as HTMLElement
112
- if (target.getAttribute('name') === 'canvas-overlay') {
113
- const { graphModel } = this.props
114
- const { selectElements } = graphModel
115
- if (selectElements.size > 0) {
116
- graphModel.clearSelectElements()
117
- }
118
- // 如果是拖拽状态,不触发点击事件
119
- if (this.state.isDragging) return
120
- graphModel.eventCenter.emit(EventType.BLANK_CLICK, { e: ev })
121
- }
122
- }
123
- handleContextMenu = (ev: MouseEvent) => {
124
- const target = ev.target as HTMLElement
125
- if (target.getAttribute('name') === 'canvas-overlay') {
126
- ev.preventDefault()
127
- const { graphModel } = this.props
128
- const position = graphModel.getPointByClient({
129
- x: ev.clientX,
130
- y: ev.clientY,
131
- })
132
- // graphModel.setElementState(ElementState.SHOW_MENU, position.domOverlayPosition);
133
- graphModel.eventCenter.emit(EventType.BLANK_CONTEXTMENU, {
134
- e: ev,
135
- position,
136
- })
137
- }
138
- }
139
- // 鼠标、触摸板 按下
140
- pointerDownHandler = (ev: PointerEvent) => {
141
- const {
142
- graphModel: {
143
- eventCenter,
144
- editConfigModel,
145
- transformModel: { SCALE_X },
146
- gridSize,
147
- },
148
- } = this.props
149
- this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY })
150
- if (this.longPressTimer) {
151
- clearTimeout(this.longPressTimer)
152
- }
153
- if (ev.pointerType === 'touch') {
154
- this.longPressTimer = window.setTimeout(() => {
155
- this.handleContextMenu(ev)
156
- }, 500)
157
- }
158
- // 检测双指触摸,初始化捏合缩放
159
- if (this.pointers.size === 2) {
160
- const {
161
- graphModel: { transformModel, editConfigModel },
162
- } = this.props
163
- // 记录两指当前位置用于计算初始距离
164
- const pts = Array.from(this.pointers.values())
165
- const dx = pts[0].x - pts[1].x
166
- const dy = pts[0].y - pts[1].y
167
- const cx = (pts[0].x + pts[1].x) / 2
168
- const cy = (pts[0].y + pts[1].y) / 2
169
- // 记录捏合起始距离与当前缩放,后续按比例计算缩放
170
- this.pinchStartDistance = Math.hypot(dx, dy)
171
- this.pinchStartScale = transformModel.SCALE_X
172
- // 双指操作下取消画布拖拽,避免与捏合缩放冲突
173
- this.stepDrag.cancelDrag()
174
- this.pinchLastCenterX = cx
175
- this.pinchLastCenterY = cy
176
- editConfigModel.updateEditConfig({ isPinching: true })
177
- return
178
- }
179
- const { adjustEdge, adjustNodePosition, stopMoveGraph } = editConfigModel
180
- const target = ev.target as HTMLElement
181
- const isFrozenElement = !adjustEdge && !adjustNodePosition
182
- if (target.getAttribute('name') === 'canvas-overlay' || isFrozenElement) {
183
- if (stopMoveGraph !== true) {
184
- this.stepDrag.setStep(gridSize * SCALE_X)
185
- this.stepDrag.handleMouseDown(ev)
186
- } else {
187
- eventCenter.emit(EventType.BLANK_MOUSEDOWN, { e: ev })
188
- }
189
- }
190
- }
191
- pointerMoveHandler = (ev: PointerEvent) => {
192
- // 记录当前指针位置(按 pointerId)
193
- this.pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY })
194
- // 当已记录初始捏合距离且存在两指时,执行捏合缩放
195
- if (this.pinchStartDistance && this.pointers.size >= 2) {
196
- const {
197
- graphModel,
198
- graphModel: { editConfigModel, transformModel },
199
- } = this.props
200
- if (editConfigModel.stopZoomGraph) return
201
- // 取消触摸长按计时,避免捏合过程中误触发上下文菜单
202
- if (this.longPressTimer) {
203
- clearTimeout(this.longPressTimer)
204
- }
205
- // 计算两指间当前距离
206
- const pts = Array.from(this.pointers.values())
207
- const dx = pts[0].x - pts[1].x
208
- const dy = pts[0].y - pts[1].y
209
- const dist = Math.hypot(dx, dy)
210
- // 以初始缩放为基准,根据距离比例得到新的缩放比例
211
- const scale =
212
- (this.pinchStartScale ?? transformModel.SCALE_X) *
213
- (dist / this.pinchStartDistance)
214
- // 取两指中心作为缩放原点,并转换为画布坐标系
215
- const cx = (pts[0].x + pts[1].x) / 2
216
- const cy = (pts[0].y + pts[1].y) / 2
217
- const pos = graphModel.getPointByClient({ x: cx, y: cy })
218
- const { x, y } = pos.canvasOverlayPosition
219
- transformModel.zoom(scale, [x, y])
220
- // 双指中心位移驱动画布平移,配合缩放实现捏合移动;
221
- if (!editConfigModel.stopMoveGraph || editConfigModel.isPinching) {
222
- const deltaX =
223
- this.pinchLastCenterX === undefined ? 0 : cx - this.pinchLastCenterX
224
- const deltaY =
225
- this.pinchLastCenterY === undefined ? 0 : cy - this.pinchLastCenterY
226
- transformModel.translate(deltaX, deltaY)
227
- this.pinchLastCenterX = cx
228
- this.pinchLastCenterY = cy
229
- }
230
- ev.preventDefault()
231
- }
232
- }
233
- pointerUpHandler = (ev: PointerEvent) => {
234
- this.pointers.delete(ev.pointerId)
235
- if (this.longPressTimer) {
236
- clearTimeout(this.longPressTimer)
237
- this.longPressTimer = undefined
238
- }
239
- // 双指松开或仅剩一指:结束捏合手势并清理临时状态
240
- if (this.pointers.size < 2) {
241
- // 清空捏合距离与缩放起始值
242
- this.pinchStartDistance = undefined
243
- this.pinchStartScale = undefined
244
- // 清空上一帧的双指中心
245
- this.pinchLastCenterX = undefined
246
- this.pinchLastCenterY = undefined
247
- const {
248
- graphModel: { editConfigModel },
249
- } = this.props
250
- // 标记退出捏合,框选等交互可恢复
251
- editConfigModel.updateEditConfig({ isPinching: false })
252
- // 为了处理画布移动的时候,编辑和菜单仍然存在的问题。
253
- this.clickHandler(ev)
254
- }
255
- }
256
-
257
- render() {
258
- const {
259
- graphModel: { transformModel },
260
- } = this.props
261
- const { transform } = transformModel.getTransformStyle()
262
- const { children } = this.props
263
- const { isDragging } = this.state
264
-
265
- return (
266
- <svg
267
- xmlns="http://www.w3.org/2000/svg"
268
- width="100%"
269
- height="100%"
270
- name="canvas-overlay"
271
- onWheel={this.zoomHandler}
272
- onPointerDown={this.pointerDownHandler}
273
- onPointerMove={this.pointerMoveHandler}
274
- onPointerUp={this.pointerUpHandler}
275
- onPointerCancel={this.pointerUpHandler}
276
- onContextMenu={this.handleContextMenu}
277
- style={{ touchAction: 'none', WebkitUserSelect: 'none' }}
278
- className={
279
- isDragging
280
- ? 'lf-canvas-overlay lf-dragging'
281
- : 'lf-canvas-overlay lf-drag-able'
282
- }
283
- >
284
- <g transform={transform}>{children}</g>
285
- </svg>
286
- )
287
- }
288
- }
289
-
290
- export default CanvasOverlay