@logicflow/core
Version:
LogicFlow, help you quickly create flowcharts
198 lines (190 loc) • 5.13 kB
text/typescript
import { get, assign, cloneDeep } from 'lodash-es'
import { action, observable } from 'mobx'
import BaseEdgeModel from './BaseEdgeModel'
import { BaseNodeModel } from '../node'
import LogicFlow from '../../LogicFlow'
import GraphModel from '../GraphModel'
import { ModelType } from '../../constant'
import { getBezierControlPoints, IBezierControls } from '../../util'
import Point = LogicFlow.Point
import EdgeConfig = LogicFlow.EdgeConfig
export class BezierEdgeModel extends BaseEdgeModel {
modelType = ModelType.BEZIER_EDGE
offset!: number
path = ''
constructor(data: EdgeConfig, graphModel: GraphModel) {
super(data, graphModel)
this.initEdgeData(data)
this.setAttributes()
}
initEdgeData(data: EdgeConfig): void {
this.offset = get(data, 'properties.offset', 100)
super.initEdgeData(data)
}
getEdgeStyle() {
const { bezier } = this.graphModel.theme
const style = super.getEdgeStyle()
const { style: customStyle = {} } = this.properties
return {
...style,
...cloneDeep(bezier),
...cloneDeep(customStyle),
}
}
getTextPosition(): Point {
if (this.pointsList && this.pointsList.length > 0) {
let pointsXSum = 0
let pointsYSum = 0
this.pointsList.forEach(({ x, y }) => {
pointsXSum += x
pointsYSum += y
})
return {
x: pointsXSum / this.pointsList.length,
y: pointsYSum / this.pointsList.length,
}
}
return {
x: (this.startPoint.x + this.endPoint.x) / 2,
y: (this.startPoint.y + this.endPoint.y) / 2,
}
}
getData() {
const data = super.getData()
const pointsList = this.pointsList.map(({ x, y }) => ({ x, y }))
return {
...data,
pointsList,
}
}
/* 获取贝塞尔曲线的控制点 */
private getControls(): IBezierControls {
const start = this.startPoint
const end = this.endPoint
const points = getBezierControlPoints({
start,
end,
sourceNode: this.sourceNode,
targetNode: this.targetNode,
offset: this.offset,
})
return points
}
/* 获取贝塞尔曲线的path */
private getPath(points: Point[]): string {
const [start, sNext, ePre, end] = points
return `M ${start.x} ${start.y}
C ${sNext.x} ${sNext.y},
${ePre.x} ${ePre.y},
${end.x} ${end.y}`
}
initPoints() {
if (this.pointsList.length > 0) {
this.path = this.getPath(this.pointsList)
} else {
this.updatePoints()
}
}
updatePoints() {
const { sNext, ePre } = this.getControls()
this.updatePath(sNext, ePre)
}
updatePath(sNext: Point, ePre: Point) {
sNext = cloneDeep(sNext)
ePre = cloneDeep(ePre)
const start = {
x: this.startPoint.x,
y: this.startPoint.y,
}
const end = {
x: this.endPoint.x,
y: this.endPoint.y,
}
if (!sNext || !ePre) {
const control = this.getControls()
sNext = control.sNext
ePre = control.ePre
}
this.pointsList = [start, sNext, ePre, end]
this.path = this.getPath(this.pointsList)
}
updateStartPoint(anchor: Point) {
this.startPoint = Object.assign({}, anchor)
this.updatePoints()
}
updateEndPoint(anchor: Point) {
this.endPoint = Object.assign({}, anchor)
this.updatePoints()
}
moveStartPoint(deltaX: number, deltaY: number): void {
this.startPoint.x += deltaX
this.startPoint.y += deltaY
const [, sNext, ePre] = this.pointsList
// 保持调整点一起移动
sNext.x += deltaX
sNext.y += deltaY
this.updatePath(sNext, ePre)
}
moveEndPoint(deltaX: number, deltaY: number): void {
this.endPoint.x += deltaX
this.endPoint.y += deltaY
const [, sNext, ePre] = this.pointsList
// 保持调整点一起移动
ePre.x += deltaX
ePre.y += deltaY
this.updatePath(sNext, ePre)
}
updateAdjustAnchor(anchor: Point, type: string) {
if (type === 'sNext') {
this.pointsList[1] = anchor
} else if (type === 'ePre') {
this.pointsList[2] = anchor
}
this.path = this.getPath(this.pointsList)
if (this.text?.value) {
this.setText(assign({}, this.text, this.textPosition))
}
}
// 获取边调整的起点
getAdjustStart() {
return this.pointsList[0] || this.startPoint
}
// 获取边调整的终点
getAdjustEnd() {
const { pointsList } = this
return pointsList[pointsList.length - 1] || this.endPoint
}
// 起终点拖拽调整过程中,进行曲线路径更新
updateAfterAdjustStartAndEnd({
startPoint,
endPoint,
sourceNode,
targetNode,
}: {
startPoint: Point
endPoint: Point
sourceNode: BaseNodeModel
targetNode: BaseNodeModel
}) {
const { sNext, ePre } = getBezierControlPoints({
start: startPoint,
end: endPoint,
sourceNode,
targetNode,
offset: this.offset,
})
this.pointsList = [startPoint, sNext, ePre, endPoint]
this.initPoints()
}
}
export default BezierEdgeModel