Skip to content
3 changes: 3 additions & 0 deletions packages/core/src/model/EditConfigModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export interface IEditConfigType {
edgeTextMode: TextMode
// 开启网格对齐
snapGrid: boolean
isPinching: boolean
}

export type IConfigKeys = keyof IEditConfigType
Expand Down Expand Up @@ -186,6 +187,7 @@ const allKeys = [
'edgeTextMultiple', // 是否支持多个边文本
'nodeTextVertical', // 节点文本是否纵向显示
'edgeTextVertical', // 边文本是否纵向显示
'isPinching', //是否是双指捏合态
] as const

/**
Expand All @@ -202,6 +204,7 @@ export class EditConfigModel {
@observable stopMoveGraph = false
@observable stopScrollGraph = false
@observable snapGrid = false
@observable isPinching = false
/*********************************************************
* 文本相关配置(全局)
********************************************************/
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/model/GraphModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@ export class GraphModel {
clearSelectElements() {
this.selectElements.forEach((element) => {
element?.setSelected(false)
element?.setHovered(false)
})
this.selectElements.clear()
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/tool/MultipleSelectTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class MultipleSelect extends Component<IToolProps> {
})
}

handleMouseDown = (ev: MouseEvent) => {
handleMouseDown = (ev: PointerEvent) => {
this.stepDrag.handleMouseDown(ev)
}
// 使多选区域的滚轮事件可以触发画布的滚轮事件
Expand Down Expand Up @@ -123,7 +123,7 @@ export default class MultipleSelect extends Component<IToolProps> {
<div
className="lf-multiple-select"
style={style}
onMouseDown={this.handleMouseDown}
onPointerDown={this.handleMouseDown}
onContextMenu={this.handleContextMenu}
onWheel={this.handleWheelEvent}
/>
Expand Down
28 changes: 16 additions & 12 deletions packages/core/src/util/drag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const LEFT_MOUSE_BUTTON_CODE = 0
export type IDragParams = {
deltaX: number
deltaY: number
event?: MouseEvent
event?: PointerEvent
[key: string]: unknown
}

Expand Down Expand Up @@ -99,16 +99,16 @@ export class StepDrag {
this.model = model
}

handleMouseDown = (e: MouseEvent) => {
handleMouseDown = (e: PointerEvent) => {
const DOC: any = window?.document
if (e.button !== LEFT_MOUSE_BUTTON_CODE) return
if (this.isStopPropagation) e.stopPropagation()
e.preventDefault()
this.isStartDragging = true
this.startX = e.clientX
this.startY = e.clientY

DOC.addEventListener('mousemove', this.handleMouseMove, false)
DOC.addEventListener('mouseup', this.handleMouseUp, false)
DOC.addEventListener('pointermove', this.handleMouseMove, false)
DOC.addEventListener('pointerup', this.handleMouseUp, false)
const elementData = this.model?.getData()
this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEDOWN`], {
e,
Expand All @@ -117,8 +117,9 @@ export class StepDrag {
this.startTime = new Date().getTime()
}

handleMouseMove = (e: MouseEvent) => {
handleMouseMove = (e: PointerEvent) => {
if (this.isStopPropagation) e.stopPropagation()
e.preventDefault()
if (!this.isStartDragging) return
this.sumDeltaX += e.clientX - this.startX
this.sumDeltaY += e.clientY - this.startY
Expand Down Expand Up @@ -170,15 +171,19 @@ export class StepDrag {
}
}

handleMouseUp = (e: MouseEvent) => {
handleMouseUp = (e: PointerEvent) => {
const DOC = window.document

this.isStartDragging = false
if (this.isStopPropagation) e.stopPropagation()
const target = e.target as any
if (target && typeof target.releasePointerCapture === 'function') {
target.releasePointerCapture(e.pointerId)
}
// fix #568: 如果onDragging在下一个事件循环中触发,而drop在当前事件循环,会出现问题。
Promise.resolve().then(() => {
DOC.removeEventListener('mousemove', this.handleMouseMove, false)
DOC.removeEventListener('mouseup', this.handleMouseUp, false)
DOC.removeEventListener('pointermove', this.handleMouseMove, false)
DOC.removeEventListener('pointerup', this.handleMouseUp, false)
const elementData = this.model?.getData()
this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEUP`], {
e,
Expand All @@ -195,9 +200,8 @@ export class StepDrag {
}
cancelDrag = () => {
const DOC: any = window?.document

DOC.removeEventListener('mousemove', this.handleMouseMove, false)
DOC.removeEventListener('mouseup', this.handleMouseUp, false)
DOC.removeEventListener('pointermove', this.handleMouseMove, false)
DOC.removeEventListener('pointerup', this.handleMouseUp, false)
this.onDragEnd({ event: undefined })
this.isDragging = false
}
Expand Down
38 changes: 32 additions & 6 deletions packages/core/src/view/Anchor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ interface IProps {
anchorIndex: number
graphModel: GraphModel
nodeModel: BaseNodeModel
setHoverOff: (e: MouseEvent) => void
setHoverOff: (e: PointerEvent) => void
}

interface IState {
Expand Down Expand Up @@ -154,7 +154,7 @@ class Anchor extends Component<IProps, IState> {
endY: y1,
dragging: true,
})
this.moveAnchorEnd(x1, y1)
this.moveAnchorEnd(x1, y1, event)
if (nearBoundary.length > 0 && !stopMoveGraph && autoExpand) {
this.t = createRaf(() => {
const [translateX, translateY] = nearBoundary
Expand All @@ -164,7 +164,7 @@ class Anchor extends Component<IProps, IState> {
endX: endX - translateX,
endY: endY - translateY,
})
this.moveAnchorEnd(endX - translateX, endY - translateY)
this.moveAnchorEnd(endX - translateX, endY - translateY, event)
})
}
eventCenter.emit(EventType.ANCHOR_DRAG, {
Expand All @@ -189,6 +189,11 @@ class Anchor extends Component<IProps, IState> {
this.sourceRuleResults.clear()
this.targetRuleResults.clear()
const { graphModel, nodeModel, anchorData } = this.props
// 拖拽结束清理:取消悬浮态
if (this.preTargetNode) {
this.preTargetNode.setHovered(false)
this.preTargetNode = undefined
}

graphModel.eventCenter.emit(EventType.ANCHOR_DRAGEND, {
data: anchorData,
Expand Down Expand Up @@ -216,7 +221,7 @@ class Anchor extends Component<IProps, IState> {
}
}

checkEnd = (event: MouseEvent | null | undefined) => {
checkEnd = (event: PointerEvent | null | undefined) => {
const {
graphModel,
nodeModel,
Expand Down Expand Up @@ -289,7 +294,7 @@ class Anchor extends Component<IProps, IState> {
}
}

moveAnchorEnd(endX: number, endY: number) {
moveAnchorEnd(endX: number, endY: number, event?: PointerEvent) {
const { graphModel, nodeModel, anchorData } = this.props
const info = targetNodeInfo(
{
Expand Down Expand Up @@ -344,12 +349,33 @@ class Anchor extends Component<IProps, IState> {
} else {
targetNode.setElementState(ElementState.NOT_ALLOW_CONNECT)
}
// 人工触发进入目标节点事件,同步设置 hovered 以驱动锚点显隐和样式
if (!targetNode.isHovered) {
const nodeData = targetNode.getData()
if (event) {
graphModel.eventCenter.emit(EventType.NODE_MOUSEENTER, {
data: nodeData,
e: event,
})
}
targetNode.setHovered(true)
}
} else if (
this.preTargetNode &&
this.preTargetNode.state !== ElementState.DEFAULT
) {
// 为了保证鼠标离开的时候,将上一个节点状态重置为正常状态。
this.preTargetNode.setElementState(ElementState.DEFAULT)
// 未命中任何节点:人工派发离开事件并取消悬浮,避免状态残留
const prevData = this.preTargetNode.getData()
if (event) {
graphModel.eventCenter.emit(EventType.NODE_MOUSELEAVE, {
data: prevData,
e: event,
})
}
this.preTargetNode.setHovered(false)
this.preTargetNode = undefined
}
}

Expand All @@ -375,7 +401,7 @@ class Anchor extends Component<IProps, IState> {
nodeModel,
})
}}
onMouseDown={(ev) => {
onPointerDown={(ev) => {
graphModel.eventCenter.emit(EventType.ANCHOR_MOUSEDOWN, {
data: anchorData,
e: ev!,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/view/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ export class ResizeControl extends Component<
height={25}
fill="transparent"
stroke="transparent"
onMouseDown={this.dragHandler.handleMouseDown}
onPointerDown={this.dragHandler.handleMouseDown}
/>
</g>
)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/view/Rotate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class RotateControlPoint extends Component<IRotateControlProps> {
return (
<g className="lf-rotate-control">
<g
onMouseDown={(ev) => {
onPointerDown={(ev) => {
this.stepperDrag.handleMouseDown(ev)
}}
>
Expand Down
71 changes: 55 additions & 16 deletions packages/core/src/view/behavior/dnd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class Dnd {
nodeConfig: OnDragNodeConfig | null = null
lf: LogicFlow
fakeNode: BaseNodeModel | null = null
docPointerMove?: (e: PointerEvent) => void
docPointerUp?: (e: PointerEvent) => void

constructor(params: { lf: LogicFlow }) {
const { lf } = params
Expand All @@ -36,19 +38,67 @@ export class Dnd {
}
}

isInsideCanvas(e: PointerEvent): boolean {
const overlay = this.lf.graphModel.rootEl.querySelector(
'[name="canvas-overlay"]',
) as HTMLElement | null
const topEl = window.document.elementFromPoint(
e.clientX,
e.clientY,
) as HTMLElement | null
return (
topEl === overlay ||
(topEl !== null && !!overlay && overlay.contains(topEl))
)
}
startDrag(nodeConfig: OnDragNodeConfig) {
const { editConfigModel } = this.lf.graphModel
if (!editConfigModel?.isSilentMode) {
this.nodeConfig = nodeConfig
window.document.addEventListener('mouseup', this.stopDrag)
if (editConfigModel?.isSilentMode) return
this.nodeConfig = nodeConfig
// 指针移动:根据命中结果判断是否在画布覆盖层上,驱动假节点创建/移动或清理
this.docPointerMove = (e: PointerEvent) => {
if (!this.nodeConfig) return
// 离开画布:清理吸附线与假节点
if (!this.isInsideCanvas(e)) {
this.onDragLeave()
return
}
// 首次进入画布:创建假节点并初始化位置
if (!this.fakeNode) {
this.dragEnter(e)
return
}
// 在画布内移动:更新假节点位置与吸附线
this.onDragOver(e)
}
// 指针抬起:在画布内落点生成节点,否则清理假节点
this.docPointerUp = (e: PointerEvent) => {
if (!this.nodeConfig) return
if (this.isInsideCanvas(e)) {
this.onDrop(e)
} else {
this.onDragLeave()
}
// 阻止默认行为与冒泡,避免滚动/点击穿透
e.preventDefault()
e.stopPropagation()
// 结束拖拽并移除监听
this.stopDrag()
}
window.document.addEventListener('pointermove', this.docPointerMove)
window.document.addEventListener('pointerup', this.docPointerUp)
}

stopDrag = () => {
this.nodeConfig = null
window.document.removeEventListener('mouseup', this.stopDrag)
if (this.docPointerMove) {
window.document.removeEventListener('pointermove', this.docPointerMove)
}
if (this.docPointerUp) {
window.document.removeEventListener('pointerup', this.docPointerUp)
}
}
dragEnter = (e: MouseEvent) => {
dragEnter = (e: PointerEvent) => {
if (!this.nodeConfig || this.fakeNode) return
this.fakeNode = this.lf.createFakeNode({
...this.nodeConfig,
Expand Down Expand Up @@ -107,17 +157,6 @@ export class Dnd {
this.lf.graphModel.removeFakeNode()
this.fakeNode = null
}

eventMap() {
return {
onMouseEnter: this.dragEnter,
onMouseOver: this.dragEnter, // IE11
onMouseMove: this.onDragOver,
onMouseLeave: this.onDragLeave,
// onMouseOut: this.onDragLeave, // IE11
onMouseUp: this.onDrop,
}
}
}

export default Dnd
4 changes: 2 additions & 2 deletions packages/core/src/view/edge/AdjustPoint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class AdjustPoint extends Component<IProps, IState> {
})
}

handleMouseDown = (ev: MouseEvent) => {
handleMouseDown = (ev: PointerEvent) => {
if (this.stepDrag) {
this.stepDrag.handleMouseDown(ev)
}
Expand Down Expand Up @@ -414,7 +414,7 @@ export class AdjustPoint extends Component<IProps, IState> {
return (
<g
pointerEvents={dragging ? 'none' : ''}
onMouseDown={this.handleMouseDown}
onPointerDown={this.handleMouseDown}
>
{!dragging ? getAdjustPointShape(x, y, edgeModel) : ''}
</g>
Expand Down
Loading