|
@@ -0,0 +1,157 @@
|
|
|
+// 根据传入的elements、node节点、edge节点对elements元素进行再计算
|
|
|
+
|
|
|
+import { ArrowHeadType, isEdge, isNode, Position } from 'react-flow-renderer'
|
|
|
+import { buildUUID } from '@/utils/uuid'
|
|
|
+
|
|
|
+import type { Edge, Elements, Node, XYPosition } from 'react-flow-renderer'
|
|
|
+
|
|
|
+export function generateElements(elements: Elements, newNode?: Node | null, oldEdge?: Edge | null) {
|
|
|
+ if (!newNode || !oldEdge) return elements
|
|
|
+ // 取出当前操作edge的数据
|
|
|
+ const { id: edgeId, source: edgeSid, target: edgeTid } = oldEdge
|
|
|
+ // 原来node节点中的sort
|
|
|
+ const sort = elements.find(item => item.id === edgeTid)?.data?.sort
|
|
|
+ // console.log(sort)
|
|
|
+
|
|
|
+ let oldIdx
|
|
|
+ const newElements: Elements = [...elements].map((item, idx) => {
|
|
|
+ if (isNode(item)) {
|
|
|
+ if (item.data?.sort >= sort) {
|
|
|
+ return { ...item, data: { ...item.data, sort: item.data.sort + 1 } }
|
|
|
+ }
|
|
|
+ if (item.id === edgeTid) {
|
|
|
+ oldIdx = idx
|
|
|
+ }
|
|
|
+ return item
|
|
|
+ } else if (isEdge(item) && item.id === edgeId) {
|
|
|
+ // 修改原来edge的source
|
|
|
+ const edge = { ...item, source: newNode.id }
|
|
|
+ return edge
|
|
|
+ }
|
|
|
+
|
|
|
+ return item
|
|
|
+ })
|
|
|
+ // 添加新的node和edge
|
|
|
+ // TODO: 在当前oldEdge target指向的节点前插入node
|
|
|
+ newElements.splice(oldIdx + 1, 0, {
|
|
|
+ ...newNode,
|
|
|
+ position: { x: 500, y: sort * 200 },
|
|
|
+ type: 'common',
|
|
|
+ data: { sort }
|
|
|
+ })
|
|
|
+
|
|
|
+ newElements.push({
|
|
|
+ id: buildUUID(),
|
|
|
+ source: edgeSid,
|
|
|
+ target: newNode.id,
|
|
|
+ type: 'common',
|
|
|
+ arrowHeadType: ArrowHeadType.Arrow
|
|
|
+ })
|
|
|
+ return newElements.map(item => {
|
|
|
+ if (isNode(item)) {
|
|
|
+ if (item.id === '83282d24-22d9-4bd8-a6bf-71d6df94f29e') {
|
|
|
+ console.log(item.data?.sort * 200)
|
|
|
+ }
|
|
|
+ return { ...item, position: { ...item.position, y: item.data?.sort * 200 } }
|
|
|
+ }
|
|
|
+ return item
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// this helper function returns the intersection point
|
|
|
+// of the line between the center of the intersectionNode and the target node
|
|
|
+function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition {
|
|
|
+ // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a
|
|
|
+ const {
|
|
|
+ width: intersectionNodeWidth,
|
|
|
+ height: intersectionNodeHeight,
|
|
|
+ position: intersectionNodePosition
|
|
|
+ } = intersectionNode.__rf
|
|
|
+ const targetPosition = targetNode.__rf.position
|
|
|
+
|
|
|
+ const w = intersectionNodeWidth / 2
|
|
|
+ const h = intersectionNodeHeight / 2
|
|
|
+
|
|
|
+ const x2 = intersectionNodePosition.x + w
|
|
|
+ const y2 = intersectionNodePosition.y + h
|
|
|
+ const x1 = targetPosition.x + w
|
|
|
+ const y1 = targetPosition.y + h
|
|
|
+
|
|
|
+ const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h)
|
|
|
+ const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h)
|
|
|
+ const a = 1 / (Math.abs(xx1) + Math.abs(yy1))
|
|
|
+ const xx3 = a * xx1
|
|
|
+ const yy3 = a * yy1
|
|
|
+ const x = w * (xx3 + yy3) + x2
|
|
|
+ const y = h * (-xx3 + yy3) + y2
|
|
|
+
|
|
|
+ return { x, y }
|
|
|
+}
|
|
|
+
|
|
|
+// returns the position (top,right,bottom or right) passed node compared to the intersection point
|
|
|
+function getEdgePosition(node: Node, intersectionPoint: XYPosition) {
|
|
|
+ const n = { ...node.__rf.position, ...node.__rf }
|
|
|
+ const nx = Math.round(n.x)
|
|
|
+ const ny = Math.round(n.y)
|
|
|
+ const px = Math.round(intersectionPoint.x)
|
|
|
+ const py = Math.round(intersectionPoint.y)
|
|
|
+
|
|
|
+ if (px <= nx + 1) {
|
|
|
+ return Position.Left
|
|
|
+ }
|
|
|
+ if (px >= nx + n.width - 1) {
|
|
|
+ return Position.Right
|
|
|
+ }
|
|
|
+ if (py <= ny + 1) {
|
|
|
+ return Position.Top
|
|
|
+ }
|
|
|
+ if (py >= n.y + n.height - 1) {
|
|
|
+ return Position.Bottom
|
|
|
+ }
|
|
|
+
|
|
|
+ return Position.Top
|
|
|
+}
|
|
|
+
|
|
|
+// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge
|
|
|
+export function getEdgeParams(source: Node, target: Node) {
|
|
|
+ const sourceIntersectionPoint = getNodeIntersection(source, target)
|
|
|
+ const targetIntersectionPoint = getNodeIntersection(target, source)
|
|
|
+
|
|
|
+ const sourcePos = getEdgePosition(source, sourceIntersectionPoint)
|
|
|
+ const targetPos = getEdgePosition(target, targetIntersectionPoint)
|
|
|
+
|
|
|
+ return {
|
|
|
+ sx: sourceIntersectionPoint.x,
|
|
|
+ sy: sourceIntersectionPoint.y,
|
|
|
+ tx: targetIntersectionPoint.x,
|
|
|
+ ty: targetIntersectionPoint.y,
|
|
|
+ sourcePos,
|
|
|
+ targetPos
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export function createElements() {
|
|
|
+ const elements = []
|
|
|
+ const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 }
|
|
|
+
|
|
|
+ elements.push({ id: 'target', data: { label: 'Target' }, position: center })
|
|
|
+
|
|
|
+ for (let i = 0; i < 8; i++) {
|
|
|
+ const degrees = i * (360 / 8)
|
|
|
+ const radians = degrees * (Math.PI / 180)
|
|
|
+ const x = 250 * Math.cos(radians) + center.x
|
|
|
+ const y = 250 * Math.sin(radians) + center.y
|
|
|
+
|
|
|
+ elements.push({ id: `${i}`, data: { label: 'Source' }, position: { x, y } })
|
|
|
+
|
|
|
+ elements.push({
|
|
|
+ id: `edge-${i}`,
|
|
|
+ target: 'target',
|
|
|
+ source: `${i}`,
|
|
|
+ type: 'floating',
|
|
|
+ arrowHeadType: ArrowHeadType.Arrow
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return elements
|
|
|
+}
|