refactor(utils): move store utils to state

* set z index on edge
* extend edgeVisibleParams by dimensions of target and node edge

Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Braks
2021-12-20 19:29:52 +01:00
parent 43531043e9
commit 6903dcb139
4 changed files with 85 additions and 130 deletions
+53 -6
View File
@@ -1,7 +1,7 @@
import { rectToBox } from './graph'
import { EdgePositions, GraphNode, HandleElement, Position, Rect, Transform, XYPosition } from '~/types'
import { EdgePositions, GraphEdge, GraphNode, HandleElement, Position, Rect, Transform, XYPosition } from '~/types'
export function getHandlePosition(position: Position, rect: Rect, handle?: HandleElement): XYPosition {
export const getHandlePosition = (position: Position, rect: Rect, handle?: HandleElement): XYPosition => {
const x = (handle?.x ?? 0) + rect.x
const y = (handle?.y ?? 0) + rect.y
const width = handle?.width ?? rect.width
@@ -31,7 +31,7 @@ export function getHandlePosition(position: Position, rect: Rect, handle?: Handl
}
}
export function getHandle(bounds?: HandleElement[], handleId?: string): HandleElement | undefined {
export const getHandle = (bounds?: HandleElement[], handleId?: string): HandleElement | undefined => {
if (!bounds) return undefined
// there is no handleId when there are no multiple handles/ handles with ids
@@ -79,17 +79,31 @@ export const getEdgePositions = (
interface IsEdgeVisibleParams {
sourcePos: XYPosition
targetPos: XYPosition
sourceWidth: number
sourceHeight: number
targetWidth: number
targetHeight: number
width: number
height: number
transform: Transform
}
export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }: IsEdgeVisibleParams): boolean {
export function isEdgeVisible({
sourcePos,
targetPos,
sourceWidth,
sourceHeight,
targetWidth,
targetHeight,
width,
height,
transform,
}: IsEdgeVisibleParams): boolean {
const edgeBox = {
x: Math.min(sourcePos.x, targetPos.x),
y: Math.min(sourcePos.y, targetPos.y),
x2: Math.max(sourcePos.x, targetPos.x),
y2: Math.max(sourcePos.y, targetPos.y),
x2: Math.max(sourcePos.x + sourceWidth, targetPos.x + targetWidth),
y2: Math.max(sourcePos.y + sourceHeight, targetPos.y + targetHeight),
}
if (edgeBox.x === edgeBox.x2) {
@@ -113,3 +127,36 @@ export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }
return overlappingArea > 0
}
export const groupEdgesByZLevel = (edges: GraphEdge[], nodes: GraphNode[]) => {
let maxLevel = -1
const nodeIds = nodes.map((n) => n.id)
const levelLookup = edges.reduce<Record<string, GraphEdge[]>>((tree, edge) => {
const z = edge.z
? edge.z
: Math.max(
nodes[nodeIds.indexOf(edge.source)].computedPosition.z || 0,
nodes[nodeIds.indexOf(edge.target)].computedPosition.z || 0,
)
if (tree[z]) {
tree[z].push(edge)
} else {
tree[z] = [edge]
}
maxLevel = z > maxLevel ? z : maxLevel
return tree
}, {})
return Object.entries(levelLookup).map(([key, edges]) => {
const level = +key
return {
edges,
level,
isMaxLevel: level === maxLevel,
}
})
}
+32 -17
View File
@@ -4,6 +4,7 @@ import {
CoordinateExtent,
Dimensions,
Edge,
EdgeMarkerType,
Elements,
FlowElements,
FlowExportObject,
@@ -184,6 +185,7 @@ export const parseNode = (node: Node, nodeExtent: CoordinateExtent, defaults?: P
...defaults,
}
: defaults
return {
...node,
...(defaults as GraphNode),
@@ -202,9 +204,11 @@ export const parseEdge = (
type: edge.type ?? 'default',
source: edge.source.toString(),
target: edge.target.toString(),
z: typeof edge.style?.zIndex === 'string' ? parseInt(edge.style?.zIndex) : edge.style?.zIndex ?? 0,
...defaults,
}
: defaults
return {
...edge,
...defaults,
@@ -266,24 +270,21 @@ export const getNodesInside = (nodes: GraphNode[], rect: Rect, [tx, ty, tScale]:
return nodes.filter((node) => {
if (!node || node.selectable === false) return false
const { position = { x: 0, y: 0 }, dimensions = { width: 0, height: 0 }, dragging = false } = node
const nBox = rectToBox({ ...position, ...dimensions })
const { computedPosition = { x: 0, y: 0 }, dimensions = { width: 0, height: 0 }, dragging = false } = node
const nBox = rectToBox({ ...computedPosition, ...dimensions })
const xOverlap = Math.max(0, Math.min(rBox.x2, nBox.x2) - Math.max(rBox.x, nBox.x))
const yOverlap = Math.max(0, Math.min(rBox.y2, nBox.y2) - Math.max(rBox.y, nBox.y))
const overlappingArea = Math.ceil(xOverlap * yOverlap)
const notInitialized =
typeof dimensions.width === 'undefined' ||
typeof dimensions.height === 'undefined' ||
dimensions.width === 0 ||
dimensions.height === 0 ||
dragging
if (dimensions.width === null || dimensions.height === null || dragging) {
// nodes are initialized with width and height = null
return true
}
if (partially) {
return overlappingArea > 0
}
const partiallyVisible = partially && overlappingArea > 0
const area = dimensions.width * dimensions.height
return overlappingArea >= area
return notInitialized || partiallyVisible || overlappingArea >= area
})
}
@@ -331,9 +332,9 @@ export const getTransformForBounds = (
return [x, y, clampedZoom]
}
export function calculateXYZPosition(node: GraphNode, result: XYZPosition): XYZPosition {
export const getXYZPos = (node: GraphNode, result: XYZPosition): XYZPosition => {
if (!node.parentNode) return result
return calculateXYZPosition(node.parentNode, {
return getXYZPos(node.parentNode, {
x: result.x + node.parentNode.position.x,
y: result.y + node.parentNode.position.y,
z:
@@ -341,9 +342,23 @@ export function calculateXYZPosition(node: GraphNode, result: XYZPosition): XYZP
})
}
export function isParentSelected(node: GraphNode): boolean {
if (!node.parentNode) return false
export const isParentSelected = (node: GraphNode): boolean => {
if (!node.parentNode) return false
if (node.parentNode.selected) return true
return isParentSelected(node.parentNode)
}
export const getMarkerId = (marker: EdgeMarkerType | undefined): string => {
if (typeof marker === 'undefined') {
return ''
}
if (typeof marker === 'string') {
return marker
}
return Object.keys(marker)
.sort()
.map((key: string) => `${key}=${(marker as any)[key]}`)
.join('&')
}
-1
View File
@@ -1,4 +1,3 @@
export * from './edge'
export * from './graph'
export * from './node'
export * from './store'
-106
View File
@@ -1,106 +0,0 @@
import { ConnectionMode, FlowState, PanOnScrollMode, DefaultNodeTypes, DefaultEdgeTypes, ConnectionLineType } from '~/types'
import { DefaultNode, InputNode, OutputNode, BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components'
import { createHooks } from '~/composables'
export const defaultNodeTypes: DefaultNodeTypes = {
input: InputNode,
default: DefaultNode,
output: OutputNode,
}
export const defaultEdgeTypes: DefaultEdgeTypes = {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge,
smoothstep: SmoothStepEdge,
}
export const initialState = (): FlowState => ({
elements: [],
nodes: [],
edges: [],
nodeTypes: [],
edgeTypes: [],
isReady: false,
instance: undefined,
dimensions: {
width: 0,
height: 0,
},
transform: [0, 0, 1],
selectedElements: undefined,
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
d3Zoom: undefined,
d3Selection: undefined,
d3ZoomHandler: undefined,
minZoom: 0.5,
maxZoom: 2,
translateExtent: [
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
],
nodeExtent: [
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
],
preventScrolling: true,
zoomOnScroll: true,
zoomOnPinch: true,
zoomOnDoubleClick: true,
panOnScroll: false,
panOnScrollSpeed: 0.5,
panOnScrollMode: PanOnScrollMode.Free,
paneMoveable: true,
edgeUpdaterRadius: 10,
onlyRenderVisibleElements: false,
defaultZoom: 1,
defaultPosition: [0, 0],
nodesSelectionActive: false,
selectionActive: false,
userSelectionRect: {
startX: 0,
startY: 0,
x: 0,
y: 0,
width: 0,
height: 0,
draw: false,
},
arrowHeadColor: '#b1b1b7',
connectionLineStyle: {},
connectionLineType: ConnectionLineType.Bezier,
connectionNodeId: undefined,
connectionHandleId: undefined,
connectionHandleType: 'source',
connectionPosition: { x: NaN, y: NaN },
connectionMode: ConnectionMode.Loose,
snapGrid: [15, 15],
snapToGrid: false,
edgesUpdatable: false,
nodesConnectable: true,
nodesDraggable: true,
elementsSelectable: true,
selectNodesOnDrag: true,
multiSelectionActive: false,
selectionKeyCode: 'Shift',
multiSelectionKeyCode: 'Meta',
zoomActivationKeyCode: 'Meta',
deleteKeyCode: 'Backspace',
hooks: createHooks(),
loading: undefined,
markerEndId: undefined,
storageKey: undefined,
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
})