@logicflow/core
Version:
LogicFlow, help you quickly create flowcharts
239 lines (226 loc) • 6.84 kB
text/typescript
import { action, observable } from 'mobx'
import { GraphModel, BaseNodeModel } from '.'
import LogicFlow from '../LogicFlow'
import { getNodeBBox } from '../util'
import Position = LogicFlow.Position
import NodeData = LogicFlow.NodeData
export type ISnaplineInfo = {
isShowHorizontal: boolean
isShowVertical: boolean
position: Position
}
export class SnaplineModel {
graphModel: GraphModel
// 是否展示水平对齐线
isShowHorizontal: boolean
// 是否展示垂直对齐线
isShowVertical: boolean
// 对齐线的中心位置,目前仅展示中心对齐的情况,后面可以考虑多种对齐策略
position: Position
constructor(graphModel: GraphModel) {
this.isShowHorizontal = false
this.isShowVertical = false
this.position = {
x: 0,
y: 0,
}
this.graphModel = graphModel
}
getStyle() {
return {
...this.graphModel.theme.snapline,
}
}
// 计算节点中心线与其他节点的对齐信息
private getCenterSnapLine(
draggingNode: NodeData,
nodes: BaseNodeModel[],
): ISnaplineInfo {
const { x, y } = draggingNode
let isShowVertical = false
let isShowHorizontal = false
for (let i = 0; i < nodes.length; i++) {
const item = nodes[i]
// 排除当前节点
if (item.id !== draggingNode.id) {
if (x === item.x) {
isShowVertical = true
}
if (y === item.y) {
isShowHorizontal = true
}
// 如果水平垂直都显示,则停止循环。减少不必要的遍历
if (isShowVertical && isShowHorizontal) {
break
}
}
}
return {
isShowVertical,
isShowHorizontal,
position: {
x,
y,
},
}
}
// 计算节点上下边框与其他节点的上下边框的对齐信息
private getHorizontalSnapline(
draggingNode: NodeData,
nodes: BaseNodeModel[],
): ISnaplineInfo {
let isShowHorizontal = false
let horizontalY: number = 0
const { id } = draggingNode
let draggingData
if (id) {
const { fakeNode } = this.graphModel
if (fakeNode && fakeNode.id === id) {
draggingData = getNodeBBox(fakeNode)
} else {
const nodeModel = this.graphModel.getNodeModelById(id)
if (nodeModel) {
draggingData = getNodeBBox(nodeModel)
}
}
}
for (let i = 0; i < nodes.length; i++) {
const item = nodes[i]
// 排除当前节点
if (item.id !== draggingNode.id) {
const itemData = getNodeBBox(item)
// 如果节点的最大最小Y轴坐标与节点的最大最小Y轴坐标相等,展示水平线
if (
itemData.minY === draggingData?.minY ||
itemData.maxY === draggingData?.minY
) {
// 找到则停止循环。减少不必要的遍历
isShowHorizontal = true
horizontalY = draggingData.minY
break
}
if (
itemData.minY === draggingData?.maxY ||
itemData.maxY === draggingData?.maxY
) {
isShowHorizontal = true
horizontalY = draggingData.maxY
break
}
}
}
return {
isShowHorizontal,
isShowVertical: this.isShowVertical,
position: {
...this.position,
y: horizontalY,
},
}
}
// 计算节点左右边框与其他节点的左右边框的对齐信息
private getVerticalSnapline(
draggingNode: NodeData,
nodes: BaseNodeModel[],
): ISnaplineInfo {
let isShowVertical: boolean = false
let verticalX: number = 0
const { id } = draggingNode
let draggingData
if (id) {
const { fakeNode } = this.graphModel
if (fakeNode && fakeNode.id === id) {
draggingData = getNodeBBox(fakeNode)
} else {
const nodeModel = this.graphModel.getNodeModelById(id)
if (nodeModel) {
draggingData = getNodeBBox(nodeModel)
}
}
}
for (let i = 0; i < nodes.length; i++) {
const item = nodes[i]
// 排除当前节点
if (item.id !== draggingNode.id) {
const itemData = getNodeBBox(item)
// 如果节点的最大最小X轴坐标与节点的最大最小X轴坐标相等,展示垂直线
if (
itemData.minX === draggingData?.minX ||
itemData.maxX === draggingData?.minX
) {
// 找到则停止循环。减少不必要的遍历
isShowVertical = true
verticalX = draggingData.minX
break
}
if (
itemData.minX === draggingData?.maxX ||
itemData.maxX === draggingData?.maxX
) {
isShowVertical = true
verticalX = draggingData.maxX
break
}
}
}
return {
isShowHorizontal: this.isShowHorizontal,
isShowVertical,
position: {
...this.position,
x: verticalX,
},
}
}
// 计算节点与其他节点的对齐信息
getSnapLinePosition(
draggingNode: NodeData,
nodes: BaseNodeModel[],
): ISnaplineInfo {
const snaplineInfo = this.getCenterSnapLine(draggingNode, nodes)
const { isShowHorizontal, isShowVertical } = snaplineInfo
// 中心对齐优先级最高
// 如果没有中心坐标的水平对齐,计算上下边框的对齐
if (!isShowHorizontal) {
const horizontalSnapline = this.getHorizontalSnapline(draggingNode, nodes)
if (horizontalSnapline.isShowHorizontal) {
snaplineInfo.isShowHorizontal = horizontalSnapline.isShowHorizontal
snaplineInfo.position.y = horizontalSnapline.position.y
}
}
// 如果没有中心坐标的垂直对齐,计算左右边框的对齐
if (!isShowVertical) {
const verticalSnapline = this.getVerticalSnapline(draggingNode, nodes)
if (verticalSnapline.isShowVertical) {
snaplineInfo.isShowVertical = verticalSnapline.isShowVertical
snaplineInfo.position.x = verticalSnapline.position.x
}
}
return snaplineInfo
}
// 设置对齐信息
private setSnaplineInfo(snaplineInfo: ISnaplineInfo): void {
const { isShowHorizontal, isShowVertical, position } = snaplineInfo
this.position = position
this.isShowHorizontal = isShowHorizontal
this.isShowVertical = isShowVertical
}
// 清空对齐信息,对齐线消失
clearSnapline(): void {
this.position = {
x: 0,
y: 0,
}
this.isShowHorizontal = false
this.isShowVertical = false
}
// 设置节点对齐线
setNodeSnapLine(nodeData: NodeData): void {
const { nodes } = this.graphModel
const info = this.getSnapLinePosition(nodeData, nodes)
this.setSnaplineInfo(info)
}
}
export default SnaplineModel