chore(lint): Update eslint rules
* Remove semi
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import { ref, defineComponent, CSSProperties, PropType, computed, inject, h } from 'vue';
|
||||
import { ref, defineComponent, CSSProperties, PropType, computed, inject, h } from 'vue'
|
||||
|
||||
import { getBezierPath } from '../Edges/BezierEdge';
|
||||
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
|
||||
import { Node, HandleElement, Position, ConnectionLineType, ConnectionLineComponent, RevueFlowStore } from '../../types';
|
||||
import { getBezierPath } from '../Edges/BezierEdge'
|
||||
import { getSmoothStepPath } from '../Edges/SmoothStepEdge'
|
||||
import { Node, HandleElement, Position, ConnectionLineType, ConnectionLineComponent, RevueFlowStore } from '../../types'
|
||||
|
||||
interface ConnectionLineProps {
|
||||
connectionLineType: ConnectionLineType;
|
||||
connectionLineStyle?: CSSProperties;
|
||||
customConnectionLine?: ConnectionLineComponent;
|
||||
connectionLineType: ConnectionLineType
|
||||
connectionLineStyle?: CSSProperties
|
||||
customConnectionLine?: ConnectionLineComponent
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -29,35 +29,35 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const sourceNode = ref<Node | null>(store.nodes.find((n) => n.id === store.connectionNodeId) || null);
|
||||
const nodesConnectable = computed(() => store.nodesConnectable);
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const sourceNode = ref<Node | null>(store.nodes.find((n) => n.id === store.connectionNodeId) || null)
|
||||
const nodesConnectable = computed(() => store.nodesConnectable)
|
||||
|
||||
const sourceHandle = computed(() =>
|
||||
store.connectionHandleId && store.connectionHandleType
|
||||
? sourceNode.value?.__rf.handleBounds[store.connectionHandleType].find(
|
||||
(d: HandleElement) => d.id === store.connectionHandleId
|
||||
)
|
||||
(d: HandleElement) => d.id === store.connectionHandleId
|
||||
)
|
||||
: store.connectionHandleType && sourceNode.value?.__rf.handleBounds[store.connectionHandleType][0]
|
||||
);
|
||||
)
|
||||
const sourceHandleX = computed(() =>
|
||||
sourceHandle.value ? sourceHandle.value.x + sourceHandle.value.width / 2 : (sourceNode.value?.__rf.width as number) / 2
|
||||
);
|
||||
)
|
||||
const sourceHandleY = computed(() =>
|
||||
sourceHandle.value ? sourceHandle.value.y + sourceHandle.value.height / 2 : sourceNode.value?.__rf.height
|
||||
);
|
||||
const sourceX = computed(() => sourceNode.value?.__rf.position.x + sourceHandleX.value);
|
||||
const sourceY = computed(() => sourceNode.value?.__rf.position.y + sourceHandleY.value);
|
||||
)
|
||||
const sourceX = computed(() => sourceNode.value?.__rf.position.x + sourceHandleX.value)
|
||||
const sourceY = computed(() => sourceNode.value?.__rf.position.y + sourceHandleY.value)
|
||||
|
||||
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2]);
|
||||
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2]);
|
||||
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2])
|
||||
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2])
|
||||
|
||||
const isRightOrLeft = computed(
|
||||
() => sourceHandle.value?.position === Position.Left || sourceHandle.value?.position === Position.Right
|
||||
);
|
||||
const targetPosition = computed(() => (isRightOrLeft.value ? Position.Left : Position.Top));
|
||||
)
|
||||
const targetPosition = computed(() => (isRightOrLeft.value ? Position.Left : Position.Top))
|
||||
|
||||
let dAttr = computed(() => `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`);
|
||||
let dAttr = computed(() => `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`)
|
||||
|
||||
if (props.connectionLineType === ConnectionLineType.Bezier) {
|
||||
dAttr = computed(() =>
|
||||
@@ -69,7 +69,7 @@ export default defineComponent({
|
||||
targetY: targetY.value,
|
||||
targetPosition: targetPosition.value
|
||||
})
|
||||
);
|
||||
)
|
||||
} else if (props.connectionLineType === ConnectionLineType.Step) {
|
||||
dAttr = computed(() =>
|
||||
getSmoothStepPath({
|
||||
@@ -81,7 +81,7 @@ export default defineComponent({
|
||||
targetPosition: targetPosition.value,
|
||||
borderRadius: 0
|
||||
})
|
||||
);
|
||||
)
|
||||
} else if (props.connectionLineType === ConnectionLineType.SmoothStep) {
|
||||
dAttr = computed(() =>
|
||||
getSmoothStepPath({
|
||||
@@ -92,7 +92,7 @@ export default defineComponent({
|
||||
targetY: targetY.value,
|
||||
targetPosition: targetPosition.value
|
||||
})
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
if (props.customConnectionLine) {
|
||||
@@ -110,7 +110,7 @@ export default defineComponent({
|
||||
connectionLineStyle: props.connectionLineStyle
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
return () =>
|
||||
@@ -120,6 +120,6 @@ export default defineComponent({
|
||||
</g>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import EdgeText from './EdgeText';
|
||||
import { getMarkerEnd, getCenter, GetCenterParams, DefaultEdgeProps } from './utils';
|
||||
import { ArrowHeadType, EdgeType, Position } from '../../types';
|
||||
import { reactify } from '@vueuse/core';
|
||||
import { defineComponent } from 'vue'
|
||||
import EdgeText from './EdgeText'
|
||||
import { getMarkerEnd, getCenter, GetCenterParams, DefaultEdgeProps } from './utils'
|
||||
import { ArrowHeadType, EdgeType, Position } from '../../types'
|
||||
import { reactify } from '@vueuse/core'
|
||||
|
||||
interface GetBezierPathParams {
|
||||
sourceX: number;
|
||||
sourceY: number;
|
||||
sourcePosition?: Position;
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
targetPosition?: Position;
|
||||
centerX?: number;
|
||||
centerY?: number;
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
export function getBezierPath({
|
||||
@@ -25,23 +25,23 @@ export function getBezierPath({
|
||||
centerX,
|
||||
centerY
|
||||
}: GetBezierPathParams): string {
|
||||
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||
const leftAndRight = [Position.Left, Position.Right];
|
||||
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY })
|
||||
const leftAndRight = [Position.Left, Position.Right]
|
||||
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY
|
||||
|
||||
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`;
|
||||
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`
|
||||
|
||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`;
|
||||
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`
|
||||
} else if (leftAndRight.includes(targetPosition)) {
|
||||
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
|
||||
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`
|
||||
} else if (leftAndRight.includes(sourcePosition)) {
|
||||
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`;
|
||||
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`
|
||||
}
|
||||
|
||||
return path;
|
||||
return path
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -58,8 +58,8 @@ export default defineComponent({
|
||||
targetY: targetY,
|
||||
sourcePosition: sourcePosition,
|
||||
targetPosition: targetPosition
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
const path = reactify(({ sourceX, sourceY, targetX, targetY, targetPosition, sourcePosition }: GetBezierPathParams) => {
|
||||
return getBezierPath({
|
||||
sourceX: sourceX,
|
||||
@@ -68,10 +68,10 @@ export default defineComponent({
|
||||
targetY: targetY,
|
||||
targetPosition: targetPosition,
|
||||
sourcePosition: sourcePosition
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
|
||||
|
||||
return () => (
|
||||
<>
|
||||
@@ -94,6 +94,6 @@ export default defineComponent({
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as EdgeType;
|
||||
}) as EdgeType
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { computed, defineComponent, h, inject, PropType, ref, watchPostEffect } from 'vue';
|
||||
import EdgeAnchor from './EdgeAnchor';
|
||||
import { ConnectionMode, Edge, Elements, Node, Position, RevueFlowStore, Transform } from '../../types';
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
|
||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../container/EdgeRenderer/utils';
|
||||
import { isEdge } from '../../utils/graph';
|
||||
import { onMouseDown } from '../Handle/handler';
|
||||
import { controlledRef } from '@vueuse/core';
|
||||
import { computed, defineComponent, h, inject, PropType, ref, watchPostEffect } from 'vue'
|
||||
import EdgeAnchor from './EdgeAnchor'
|
||||
import { ConnectionMode, Edge, Elements, Node, Position, RevueFlowStore, Transform } from '../../types'
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
|
||||
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../container/EdgeRenderer/utils'
|
||||
import { isEdge } from '../../utils/graph'
|
||||
import { onMouseDown } from '../Handle/handler'
|
||||
import { controlledRef } from '@vueuse/core'
|
||||
|
||||
interface EdgeProps {
|
||||
edge: Edge;
|
||||
nodes: Node[];
|
||||
selectedElements: Elements | null;
|
||||
elementsSelectable: boolean;
|
||||
transform: Transform;
|
||||
width: number;
|
||||
height: number;
|
||||
onlyRenderVisibleElements: boolean;
|
||||
connectionMode?: ConnectionMode;
|
||||
markerEndId?: string;
|
||||
edgeUpdaterRadius?: number;
|
||||
edge: Edge
|
||||
nodes: Node[]
|
||||
selectedElements: Elements | null
|
||||
elementsSelectable: boolean
|
||||
transform: Transform
|
||||
width: number
|
||||
height: number
|
||||
onlyRenderVisibleElements: boolean
|
||||
connectionMode?: ConnectionMode
|
||||
markerEndId?: string
|
||||
edgeUpdaterRadius?: number
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -54,41 +54,41 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!;
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!
|
||||
const nodes = controlledRef(getSourceTargetNodes(props.edge, store.nodes), {
|
||||
onBeforeChange: (value, oldValue) => {
|
||||
if (JSON.stringify(value) === JSON.stringify(oldValue)) return false;
|
||||
if (JSON.stringify(value) === JSON.stringify(oldValue)) return false
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
watchPostEffect(() => {
|
||||
nodes.value = getSourceTargetNodes(props.edge, store.nodes);
|
||||
});
|
||||
nodes.value = getSourceTargetNodes(props.edge, store.nodes)
|
||||
})
|
||||
|
||||
hooks.connect.on((connection) => {
|
||||
hooks.edgeUpdate.trigger({ edge: props.edge, connection });
|
||||
});
|
||||
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
|
||||
})
|
||||
|
||||
if (!nodes.value.sourceNode) {
|
||||
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`);
|
||||
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`)
|
||||
}
|
||||
|
||||
if (!nodes.value.targetNode) {
|
||||
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`);
|
||||
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
|
||||
}
|
||||
|
||||
// when connection type is loose we can define all handles as sources
|
||||
const targetNodeHandles =
|
||||
props.connectionMode === ConnectionMode.Strict
|
||||
? nodes.value.targetNode?.__rf.handleBounds.target
|
||||
: nodes.value.targetNode?.__rf.handleBounds.target || nodes.value.targetNode?.__rf.handleBounds.source;
|
||||
: nodes.value.targetNode?.__rf.handleBounds.target || nodes.value.targetNode?.__rf.handleBounds.source
|
||||
|
||||
const sourceHandle =
|
||||
nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null);
|
||||
const targetHandle = getHandle(targetNodeHandles, props.edge.targetHandle || null);
|
||||
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom;
|
||||
const targetPosition = targetHandle ? targetHandle.position : Position.Top;
|
||||
nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null)
|
||||
const targetHandle = getHandle(targetNodeHandles, props.edge.targetHandle || null)
|
||||
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom
|
||||
const targetPosition = targetHandle ? targetHandle.position : Position.Top
|
||||
|
||||
const isVisible = ({ sourceX, sourceY, targetX, targetY }: Record<string, number>) => {
|
||||
return props.onlyRenderVisibleElements
|
||||
@@ -99,10 +99,10 @@ export default defineComponent({
|
||||
height: store.height || 0,
|
||||
transform: store.transform
|
||||
})
|
||||
: true;
|
||||
};
|
||||
: true
|
||||
}
|
||||
|
||||
const isSelected = computed(() => store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false);
|
||||
const isSelected = computed(() => store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false)
|
||||
|
||||
const edgeElement = () => {
|
||||
const el: Edge = {
|
||||
@@ -110,51 +110,51 @@ export default defineComponent({
|
||||
source: props.edge.source,
|
||||
target: props.edge.target,
|
||||
type: props.edge.type
|
||||
};
|
||||
}
|
||||
|
||||
if (props.edge.sourceHandle) {
|
||||
el.sourceHandle = props.edge.sourceHandle;
|
||||
el.sourceHandle = props.edge.sourceHandle
|
||||
}
|
||||
|
||||
if (props.edge.targetHandle) {
|
||||
el.targetHandle = props.edge.targetHandle;
|
||||
el.targetHandle = props.edge.targetHandle
|
||||
}
|
||||
|
||||
if (typeof props.edge.data !== 'undefined') {
|
||||
el.data = props.edge.data;
|
||||
el.data = props.edge.data
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
return el
|
||||
}
|
||||
|
||||
const onEdgeClick = (event: MouseEvent) => {
|
||||
if (store.elementsSelectable) {
|
||||
store.unsetNodesSelection();
|
||||
store.addSelectedElements(edgeElement() as any);
|
||||
store.unsetNodesSelection()
|
||||
store.addSelectedElements(edgeElement() as any)
|
||||
}
|
||||
|
||||
hooks.edgeClick.trigger({ event, edge: edgeElement() });
|
||||
};
|
||||
hooks.edgeClick.trigger({ event, edge: edgeElement() })
|
||||
}
|
||||
|
||||
const onEdgeContextMenu = (event: MouseEvent) =>
|
||||
hooks.edgeContextMenu.trigger({
|
||||
event,
|
||||
edge: edgeElement()
|
||||
});
|
||||
})
|
||||
|
||||
const onEdgeMouseEnter = (event: MouseEvent) => hooks.edgeMouseEnter.trigger({ event, edge: edgeElement() });
|
||||
const onEdgeMouseEnter = (event: MouseEvent) => hooks.edgeMouseEnter.trigger({ event, edge: edgeElement() })
|
||||
|
||||
const onEdgeMouseMove = (event: MouseEvent) => hooks.edgeMouseMove.trigger({ event, edge: edgeElement() });
|
||||
const onEdgeMouseMove = (event: MouseEvent) => hooks.edgeMouseMove.trigger({ event, edge: edgeElement() })
|
||||
|
||||
const onEdgeMouseLeave = (event: MouseEvent) => hooks.edgeMouseLeave.trigger({ event, edge: edgeElement() });
|
||||
const onEdgeMouseLeave = (event: MouseEvent) => hooks.edgeMouseLeave.trigger({ event, edge: edgeElement() })
|
||||
|
||||
const handleEdgeUpdater = (event: MouseEvent, isSourceHandle: boolean) => {
|
||||
const nodeId = isSourceHandle ? props.edge.target : props.edge.source;
|
||||
const handleId = isSourceHandle ? props.edge.targetHandle : props.edge.sourceHandle;
|
||||
const isValidConnection = () => true;
|
||||
const isTarget = isSourceHandle;
|
||||
const nodeId = isSourceHandle ? props.edge.target : props.edge.source
|
||||
const handleId = isSourceHandle ? props.edge.targetHandle : props.edge.sourceHandle
|
||||
const isValidConnection = () => true
|
||||
const isTarget = isSourceHandle
|
||||
|
||||
hooks.edgeUpdateStart.trigger({ event, edge: edgeElement() });
|
||||
hooks.edgeUpdateStart.trigger({ event, edge: edgeElement() })
|
||||
onMouseDown(
|
||||
event,
|
||||
store,
|
||||
@@ -164,20 +164,20 @@ export default defineComponent({
|
||||
isTarget,
|
||||
isValidConnection,
|
||||
isSourceHandle ? 'target' : 'source'
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent) => {
|
||||
handleEdgeUpdater(event, true);
|
||||
};
|
||||
handleEdgeUpdater(event, true)
|
||||
}
|
||||
|
||||
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent) => {
|
||||
handleEdgeUpdater(event, false);
|
||||
};
|
||||
handleEdgeUpdater(event, false)
|
||||
}
|
||||
|
||||
const updating = ref<boolean>(false);
|
||||
const onEdgeUpdaterMouseEnter = () => (updating.value = true);
|
||||
const onEdgeUpdaterMouseOut = () => (updating.value = false);
|
||||
const updating = ref<boolean>(false)
|
||||
const onEdgeUpdaterMouseEnter = () => (updating.value = true)
|
||||
const onEdgeUpdaterMouseOut = () => (updating.value = false)
|
||||
|
||||
return () => {
|
||||
const { targetX, targetY, sourceX, sourceY } = getEdgePositions(
|
||||
@@ -187,7 +187,7 @@ export default defineComponent({
|
||||
nodes.value.targetNode as Node,
|
||||
targetHandle,
|
||||
targetPosition
|
||||
);
|
||||
)
|
||||
return !props.edge.isHidden && isVisible({ targetX, targetY, sourceX, sourceY }) ? (
|
||||
<g
|
||||
class={[
|
||||
@@ -242,7 +242,7 @@ export default defineComponent({
|
||||
</g>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { Position } from '../../types';
|
||||
import { defineComponent, HTMLAttributes, PropType } from 'vue';
|
||||
import { Position } from '../../types'
|
||||
import { defineComponent, HTMLAttributes, PropType } from 'vue'
|
||||
|
||||
const shiftX = (x: number, shift: number, position: Position): number => {
|
||||
if (position === Position.Left) return x - shift;
|
||||
if (position === Position.Right) return x + shift;
|
||||
return x;
|
||||
};
|
||||
if (position === Position.Left) return x - shift
|
||||
if (position === Position.Right) return x + shift
|
||||
return x
|
||||
}
|
||||
|
||||
const shiftY = (y: number, shift: number, position: Position): number => {
|
||||
if (position === Position.Top) return y - shift;
|
||||
if (position === Position.Bottom) return y + shift;
|
||||
return y;
|
||||
};
|
||||
if (position === Position.Top) return y - shift
|
||||
if (position === Position.Bottom) return y + shift
|
||||
return y
|
||||
}
|
||||
|
||||
export interface EdgeAnchorProps extends HTMLAttributes {
|
||||
position: Position;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
radius?: number;
|
||||
position: Position
|
||||
centerX: number
|
||||
centerY: number
|
||||
radius?: number
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -50,6 +50,6 @@ export default defineComponent({
|
||||
stroke="transparent"
|
||||
fill="transparent"
|
||||
/>
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EdgeTextProps, Rect } from '../../types';
|
||||
import { defineComponent, PropType, ref, watchEffect } from 'vue';
|
||||
import { EdgeTextProps, Rect } from '../../types'
|
||||
import { defineComponent, PropType, ref, watchEffect } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -37,11 +37,11 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const edgeRef = ref<SVGTextElement | null>(null);
|
||||
const edgeTextBox = ref<Rect>({ x: 0, y: 0, width: 0, height: 0 });
|
||||
const edgeRef = ref<SVGTextElement | null>(null)
|
||||
const edgeTextBox = ref<Rect>({ x: 0, y: 0, width: 0, height: 0 })
|
||||
|
||||
watchEffect(() => {
|
||||
const textBbox = edgeRef.value?.getBBox();
|
||||
const textBbox = edgeRef.value?.getBBox()
|
||||
|
||||
if (textBbox) {
|
||||
edgeTextBox.value = {
|
||||
@@ -49,9 +49,9 @@ export default defineComponent({
|
||||
y: textBbox.y,
|
||||
width: textBbox.width,
|
||||
height: textBbox.height
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return () => (
|
||||
<g
|
||||
@@ -75,6 +75,6 @@ export default defineComponent({
|
||||
</text>
|
||||
{slots.default ? slots.default() : ''}
|
||||
</g>
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import EdgeText from './EdgeText';
|
||||
import { getMarkerEnd, getCenter, EdgeSmoothProps, GetCenterParams } from './utils';
|
||||
import { ArrowHeadType, EdgeType, Position } from '../../types';
|
||||
import { reactify } from '@vueuse/core';
|
||||
import { getBezierPath } from './BezierEdge';
|
||||
import { defineComponent } from 'vue'
|
||||
import EdgeText from './EdgeText'
|
||||
import { getMarkerEnd, getCenter, EdgeSmoothProps, GetCenterParams } from './utils'
|
||||
import { ArrowHeadType, EdgeType, Position } from '../../types'
|
||||
import { reactify } from '@vueuse/core'
|
||||
import { getBezierPath } from './BezierEdge'
|
||||
|
||||
// These are some helper methods for drawing the round corners
|
||||
// The name indicates the direction of the path. "bottomLeftCorner" goes
|
||||
// from bottom to the left and "leftBottomCorner" goes from left to the bottom.
|
||||
// We have to consider the direction of the paths because of the animated lines.
|
||||
const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}`;
|
||||
const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}`;
|
||||
const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}`;
|
||||
const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}`;
|
||||
const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}`;
|
||||
const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}`;
|
||||
const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`;
|
||||
const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`;
|
||||
const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}`
|
||||
const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}`
|
||||
const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}`
|
||||
const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}`
|
||||
const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}`
|
||||
const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}`
|
||||
const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`
|
||||
const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`
|
||||
|
||||
interface GetSmoothStepPathParams {
|
||||
sourceX: number;
|
||||
sourceY: number;
|
||||
sourcePosition?: Position;
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
targetPosition?: Position;
|
||||
borderRadius?: number;
|
||||
centerX?: number;
|
||||
centerY?: number;
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
sourcePosition?: Position
|
||||
targetX: number
|
||||
targetY: number
|
||||
targetPosition?: Position
|
||||
borderRadius?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
|
||||
export function getSmoothStepPath({
|
||||
@@ -41,56 +41,55 @@ export function getSmoothStepPath({
|
||||
centerX,
|
||||
centerY
|
||||
}: GetSmoothStepPathParams): string {
|
||||
const [_centerX, _centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY });
|
||||
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX));
|
||||
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY));
|
||||
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY);
|
||||
const leftAndRight = [Position.Left, Position.Right];
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
|
||||
const [_centerX, _centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY })
|
||||
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX))
|
||||
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY))
|
||||
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY)
|
||||
const leftAndRight = [Position.Left, Position.Right]
|
||||
const cX = typeof centerX !== 'undefined' ? centerX : _centerX
|
||||
const cY = typeof centerY !== 'undefined' ? centerY : _centerY
|
||||
|
||||
let firstCornerPath;
|
||||
let secondCornerPath;
|
||||
let firstCornerPath
|
||||
let secondCornerPath
|
||||
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath = sourceY <= targetY ? bottomLeftCorner(sourceX, cY, cornerSize) : topLeftCorner(sourceX, cY, cornerSize);
|
||||
secondCornerPath = sourceY <= targetY ? rightTopCorner(targetX, cY, cornerSize) : rightBottomCorner(targetX, cY, cornerSize);
|
||||
firstCornerPath = sourceY <= targetY ? bottomLeftCorner(sourceX, cY, cornerSize) : topLeftCorner(sourceX, cY, cornerSize)
|
||||
secondCornerPath = sourceY <= targetY ? rightTopCorner(targetX, cY, cornerSize) : rightBottomCorner(targetX, cY, cornerSize)
|
||||
} else {
|
||||
firstCornerPath = sourceY < targetY ? bottomRightCorner(sourceX, cY, cornerSize) : topRightCorner(sourceX, cY, cornerSize);
|
||||
secondCornerPath = sourceY < targetY ? leftTopCorner(targetX, cY, cornerSize) : leftBottomCorner(targetX, cY, cornerSize);
|
||||
firstCornerPath = sourceY < targetY ? bottomRightCorner(sourceX, cY, cornerSize) : topRightCorner(sourceX, cY, cornerSize)
|
||||
secondCornerPath = sourceY < targetY ? leftTopCorner(targetX, cY, cornerSize) : leftBottomCorner(targetX, cY, cornerSize)
|
||||
}
|
||||
|
||||
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize);
|
||||
secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize);
|
||||
firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize)
|
||||
secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize)
|
||||
} else if (sourcePosition === Position.Right && targetPosition === Position.Left) {
|
||||
// and sourceX > targetX
|
||||
firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize);
|
||||
secondCornerPath =
|
||||
sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize);
|
||||
firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize)
|
||||
secondCornerPath = sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize)
|
||||
}
|
||||
} else if (leftAndRight.includes(sourcePosition) && !leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? rightTopCorner(targetX, sourceY, cornerSize) : rightBottomCorner(targetX, sourceY, cornerSize);
|
||||
sourceY <= targetY ? rightTopCorner(targetX, sourceY, cornerSize) : rightBottomCorner(targetX, sourceY, cornerSize)
|
||||
} else {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? leftTopCorner(targetX, sourceY, cornerSize) : leftBottomCorner(targetX, sourceY, cornerSize);
|
||||
sourceY <= targetY ? leftTopCorner(targetX, sourceY, cornerSize) : leftBottomCorner(targetX, sourceY, cornerSize)
|
||||
}
|
||||
secondCornerPath = '';
|
||||
secondCornerPath = ''
|
||||
} else if (!leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
|
||||
if (sourceX <= targetX) {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? bottomLeftCorner(sourceX, targetY, cornerSize) : topLeftCorner(sourceX, targetY, cornerSize);
|
||||
sourceY <= targetY ? bottomLeftCorner(sourceX, targetY, cornerSize) : topLeftCorner(sourceX, targetY, cornerSize)
|
||||
} else {
|
||||
firstCornerPath =
|
||||
sourceY <= targetY ? bottomRightCorner(sourceX, targetY, cornerSize) : topRightCorner(sourceX, targetY, cornerSize);
|
||||
sourceY <= targetY ? bottomRightCorner(sourceX, targetY, cornerSize) : topRightCorner(sourceX, targetY, cornerSize)
|
||||
}
|
||||
secondCornerPath = '';
|
||||
secondCornerPath = ''
|
||||
}
|
||||
|
||||
return `M ${sourceX},${sourceY}${firstCornerPath}${secondCornerPath}L ${targetX},${targetY}`;
|
||||
return `M ${sourceX},${sourceY}${firstCornerPath}${secondCornerPath}L ${targetX},${targetY}`
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -107,8 +106,8 @@ export default defineComponent({
|
||||
targetY: targetY,
|
||||
sourcePosition: sourcePosition,
|
||||
targetPosition: targetPosition
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
const path = reactify(({ sourceX, sourceY, targetX, targetY, targetPosition, sourcePosition }: GetSmoothStepPathParams) => {
|
||||
return getBezierPath({
|
||||
sourceX: sourceX,
|
||||
@@ -117,10 +116,10 @@ export default defineComponent({
|
||||
targetY: targetY,
|
||||
targetPosition: targetPosition,
|
||||
sourcePosition: sourcePosition
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
|
||||
|
||||
return () => (
|
||||
<>
|
||||
@@ -143,6 +142,6 @@ export default defineComponent({
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as unknown as EdgeType;
|
||||
}) as unknown as EdgeType
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import SmoothStepEdge from './SmoothStepEdge';
|
||||
import { EdgeSmoothProps } from './utils';
|
||||
import { EdgeType } from '../../types';
|
||||
import { defineComponent } from 'vue'
|
||||
import SmoothStepEdge from './SmoothStepEdge'
|
||||
import { EdgeSmoothProps } from './utils'
|
||||
import { EdgeType } from '../../types'
|
||||
|
||||
export default defineComponent({
|
||||
components: { SmoothStepEdge },
|
||||
@@ -10,6 +10,6 @@ export default defineComponent({
|
||||
...EdgeSmoothProps
|
||||
},
|
||||
setup(props) {
|
||||
return () => <SmoothStepEdge {...props} borderRadius={0} />;
|
||||
return () => <SmoothStepEdge {...props} borderRadius={0} />
|
||||
}
|
||||
}) as EdgeType;
|
||||
}) as EdgeType
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import EdgeText from './EdgeText';
|
||||
import { getMarkerEnd, DefaultEdgeProps } from './utils';
|
||||
import { reactify } from '@vueuse/core';
|
||||
import { ArrowHeadType, EdgeType } from '../../types';
|
||||
import { defineComponent } from 'vue'
|
||||
import EdgeText from './EdgeText'
|
||||
import { getMarkerEnd, DefaultEdgeProps } from './utils'
|
||||
import { reactify } from '@vueuse/core'
|
||||
import { ArrowHeadType, EdgeType } from '../../types'
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
@@ -11,15 +11,15 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const centerY = reactify((targetY: number, sourceY: number) => {
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||
return targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||
});
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2
|
||||
return targetY < sourceY ? targetY + yOffset : targetY - yOffset
|
||||
})
|
||||
const centerX = reactify((targetX: number, sourceX: number) => {
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
||||
return targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||
});
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2
|
||||
return targetX < sourceX ? targetX + xOffset : targetX - xOffset
|
||||
})
|
||||
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
|
||||
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
|
||||
|
||||
return () => (
|
||||
<>
|
||||
@@ -42,6 +42,6 @@ export default defineComponent({
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as unknown as EdgeType;
|
||||
}) as unknown as EdgeType
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { default as BezierEdge } from './BezierEdge';
|
||||
export { default as StepEdge } from './StepEdge';
|
||||
export { default as SmoothStepEdge } from './SmoothStepEdge';
|
||||
export { default as StraightEdge } from './StraightEdge';
|
||||
export { default as BezierEdge } from './BezierEdge'
|
||||
export { default as StepEdge } from './StepEdge'
|
||||
export { default as SmoothStepEdge } from './SmoothStepEdge'
|
||||
export { default as StraightEdge } from './StraightEdge'
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { ArrowHeadType, Position, EdgeProps, EdgeSmoothStepProps } from '../../types';
|
||||
import { PropType } from 'vue';
|
||||
import { ArrowHeadType, Position, EdgeProps, EdgeSmoothStepProps } from '../../types'
|
||||
import { PropType } from 'vue'
|
||||
|
||||
export const getMarkerEnd = (arrowHeadType?: ArrowHeadType, markerEndId?: string): string => {
|
||||
if (typeof markerEndId !== 'undefined' && markerEndId) {
|
||||
return `url(#${markerEndId})`;
|
||||
return `url(#${markerEndId})`
|
||||
}
|
||||
|
||||
return typeof arrowHeadType !== 'undefined' ? `url(#revue-flow__${arrowHeadType})` : 'none';
|
||||
};
|
||||
|
||||
export interface GetCenterParams {
|
||||
sourceX: number;
|
||||
sourceY: number;
|
||||
targetX: number;
|
||||
targetY: number;
|
||||
sourcePosition?: Position;
|
||||
targetPosition?: Position;
|
||||
return typeof arrowHeadType !== 'undefined' ? `url(#revue-flow__${arrowHeadType})` : 'none'
|
||||
}
|
||||
|
||||
const LeftOrRight = [Position.Left, Position.Right];
|
||||
export interface GetCenterParams {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition?: Position
|
||||
targetPosition?: Position
|
||||
}
|
||||
|
||||
const LeftOrRight = [Position.Left, Position.Right]
|
||||
|
||||
export const getCenter = ({
|
||||
sourceX,
|
||||
@@ -28,31 +28,31 @@ export const getCenter = ({
|
||||
sourcePosition = Position.Bottom,
|
||||
targetPosition = Position.Top
|
||||
}: GetCenterParams): [number, number, number, number] => {
|
||||
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition);
|
||||
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition);
|
||||
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition)
|
||||
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition)
|
||||
|
||||
// we expect flows to be horizontal or vertical (all handles left or right respectively top or bottom)
|
||||
// a mixed edge is when one the source is on the left and the target is on the top for example.
|
||||
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight);
|
||||
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight)
|
||||
|
||||
if (mixedEdge) {
|
||||
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0;
|
||||
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset;
|
||||
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0
|
||||
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset
|
||||
|
||||
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY);
|
||||
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset;
|
||||
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY)
|
||||
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset];
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2;
|
||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
|
||||
const xOffset = Math.abs(targetX - sourceX) / 2
|
||||
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset
|
||||
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2;
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
|
||||
const yOffset = Math.abs(targetY - sourceY) / 2
|
||||
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset
|
||||
|
||||
return [centerX, centerY, xOffset, yOffset];
|
||||
};
|
||||
return [centerX, centerY, xOffset, yOffset]
|
||||
}
|
||||
|
||||
export const DefaultEdgeProps = {
|
||||
id: {
|
||||
@@ -165,7 +165,7 @@ export const DefaultEdgeProps = {
|
||||
required: false,
|
||||
default: undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const EdgeSmoothProps = {
|
||||
...DefaultEdgeProps,
|
||||
@@ -174,4 +174,4 @@ export const EdgeSmoothProps = {
|
||||
required: false,
|
||||
default: 5
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { getHostForElement } from '../../utils';
|
||||
import { ElementId, ConnectionMode, Connection, HandleType, RevueFlowStore } from '../../types';
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
|
||||
import { getHostForElement } from '../../utils'
|
||||
import { ElementId, ConnectionMode, Connection, HandleType, RevueFlowStore } from '../../types'
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
|
||||
|
||||
export type ValidConnectionFunc = (connection: Connection) => boolean;
|
||||
export type ValidConnectionFunc = (connection: Connection) => boolean
|
||||
|
||||
type Result = {
|
||||
elementBelow: Element | null;
|
||||
isValid: boolean;
|
||||
connection: Connection;
|
||||
isHoveringHandle: boolean;
|
||||
};
|
||||
elementBelow: Element | null
|
||||
isValid: boolean
|
||||
connection: Connection
|
||||
isHoveringHandle: boolean
|
||||
}
|
||||
|
||||
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
|
||||
function checkElementBelowIsValid(
|
||||
@@ -21,27 +21,27 @@ function checkElementBelowIsValid(
|
||||
isValidConnection: ValidConnectionFunc,
|
||||
doc: Document | ShadowRoot
|
||||
) {
|
||||
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY);
|
||||
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false;
|
||||
const elementBelowIsSource = elementBelow?.classList.contains('source') || false;
|
||||
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
|
||||
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false
|
||||
const elementBelowIsSource = elementBelow?.classList.contains('source') || false
|
||||
|
||||
const result: Result = {
|
||||
elementBelow,
|
||||
isValid: false,
|
||||
connection: { source: null, target: null, sourceHandle: null, targetHandle: null },
|
||||
isHoveringHandle: false
|
||||
};
|
||||
}
|
||||
|
||||
if (elementBelow && (elementBelowIsTarget || elementBelowIsSource)) {
|
||||
result.isHoveringHandle = true;
|
||||
result.isHoveringHandle = true
|
||||
|
||||
// in strict mode we don't allow target to target or source to source connections
|
||||
const isValid =
|
||||
connectionMode === ConnectionMode.Strict ? (isTarget && elementBelowIsSource) || (!isTarget && elementBelowIsTarget) : true;
|
||||
connectionMode === ConnectionMode.Strict ? (isTarget && elementBelowIsSource) || (!isTarget && elementBelowIsTarget) : true
|
||||
|
||||
if (isValid) {
|
||||
const elementBelowNodeId = elementBelow.getAttribute('data-nodeid');
|
||||
const elementBelowHandleId = elementBelow.getAttribute('data-handleid');
|
||||
const elementBelowNodeId = elementBelow.getAttribute('data-nodeid')
|
||||
const elementBelowHandleId = elementBelow.getAttribute('data-handleid')
|
||||
const connection: Connection = isTarget
|
||||
? {
|
||||
source: elementBelowNodeId,
|
||||
@@ -54,30 +54,30 @@ function checkElementBelowIsValid(
|
||||
sourceHandle: handleId,
|
||||
target: elementBelowNodeId,
|
||||
targetHandle: elementBelowHandleId
|
||||
};
|
||||
}
|
||||
|
||||
result.connection = connection;
|
||||
result.isValid = isValidConnection(connection);
|
||||
result.connection = connection
|
||||
result.isValid = isValidConnection(connection)
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function resetRecentHandle(hoveredHandle: Element): void {
|
||||
hoveredHandle?.classList.remove('revue-flow__handle-valid');
|
||||
hoveredHandle?.classList.remove('revue-flow__handle-connecting');
|
||||
hoveredHandle?.classList.remove('revue-flow__handle-valid')
|
||||
hoveredHandle?.classList.remove('revue-flow__handle-connecting')
|
||||
}
|
||||
|
||||
export function onMouseDown(
|
||||
event: MouseEvent,
|
||||
store: RevueFlowStore,
|
||||
hooks: {
|
||||
connectStart: RevueFlowHooks['connectStart'];
|
||||
connectStop: RevueFlowHooks['connectStop'];
|
||||
connectEnd: RevueFlowHooks['connectEnd'];
|
||||
connect: RevueFlowHooks['connect'];
|
||||
edgeUpdateEnd: RevueFlowHooks['edgeUpdateEnd'];
|
||||
connectStart: RevueFlowHooks['connectStart']
|
||||
connectStop: RevueFlowHooks['connectStop']
|
||||
connectEnd: RevueFlowHooks['connectEnd']
|
||||
connect: RevueFlowHooks['connect']
|
||||
edgeUpdateEnd: RevueFlowHooks['edgeUpdateEnd']
|
||||
},
|
||||
handleId: ElementId | null,
|
||||
nodeId: ElementId,
|
||||
@@ -85,39 +85,39 @@ export function onMouseDown(
|
||||
isValidConnection: ValidConnectionFunc,
|
||||
elementEdgeUpdaterType?: HandleType
|
||||
): void {
|
||||
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
||||
const revueFlowNode = (event.target as Element).closest('.revue-flow')
|
||||
// when revue-flow is used inside a shadow root we can't use document
|
||||
const doc = getHostForElement(event.target as HTMLElement);
|
||||
const doc = getHostForElement(event.target as HTMLElement)
|
||||
|
||||
if (!doc) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY);
|
||||
const elementBelowIsTarget = elementBelow?.classList.contains('target');
|
||||
const elementBelowIsSource = elementBelow?.classList.contains('source');
|
||||
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
|
||||
const elementBelowIsTarget = elementBelow?.classList.contains('target')
|
||||
const elementBelowIsSource = elementBelow?.classList.contains('source')
|
||||
|
||||
if (!revueFlowNode || (!elementBelowIsTarget && !elementBelowIsSource && !elementEdgeUpdaterType)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source';
|
||||
const containerBounds = revueFlowNode.getBoundingClientRect();
|
||||
let recentHoveredHandle: Element;
|
||||
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source'
|
||||
const containerBounds = revueFlowNode.getBoundingClientRect()
|
||||
let recentHoveredHandle: Element
|
||||
|
||||
store.connectionPosition.x = event.clientX - containerBounds.left;
|
||||
store.connectionPosition.y = event.clientY - containerBounds.top;
|
||||
store.connectionPosition.x = event.clientX - containerBounds.left
|
||||
store.connectionPosition.y = event.clientY - containerBounds.top
|
||||
|
||||
store.setConnectionNodeId({
|
||||
connectionNodeId: nodeId,
|
||||
connectionHandleId: handleId,
|
||||
connectionHandleType: handleType
|
||||
});
|
||||
hooks.connectStart.trigger({ event, params: { nodeId, handleId, handleType } });
|
||||
})
|
||||
hooks.connectStart.trigger({ event, params: { nodeId, handleId, handleType } })
|
||||
|
||||
function onMouseMove(event: MouseEvent) {
|
||||
store.connectionPosition.x = event.clientX - containerBounds.left;
|
||||
store.connectionPosition.y = event.clientY - containerBounds.top;
|
||||
store.connectionPosition.x = event.clientX - containerBounds.left
|
||||
store.connectionPosition.y = event.clientY - containerBounds.top
|
||||
|
||||
const { connection, elementBelow, isValid, isHoveringHandle } = checkElementBelowIsValid(
|
||||
event,
|
||||
@@ -127,18 +127,18 @@ export function onMouseDown(
|
||||
handleId,
|
||||
isValidConnection,
|
||||
doc
|
||||
);
|
||||
)
|
||||
|
||||
if (!isHoveringHandle) {
|
||||
return resetRecentHandle(recentHoveredHandle);
|
||||
return resetRecentHandle(recentHoveredHandle)
|
||||
}
|
||||
|
||||
const isOwnHandle = connection.source === connection.target;
|
||||
const isOwnHandle = connection.source === connection.target
|
||||
|
||||
if (!isOwnHandle && elementBelow) {
|
||||
recentHoveredHandle = elementBelow;
|
||||
elementBelow.classList.add('revue-flow__handle-connecting');
|
||||
elementBelow.classList.toggle('revue-flow__handle-valid', isValid);
|
||||
recentHoveredHandle = elementBelow
|
||||
elementBelow.classList.add('revue-flow__handle-connecting')
|
||||
elementBelow.classList.toggle('revue-flow__handle-valid', isValid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,27 +151,27 @@ export function onMouseDown(
|
||||
handleId,
|
||||
isValidConnection,
|
||||
doc
|
||||
);
|
||||
)
|
||||
|
||||
hooks.connectStop.trigger(event);
|
||||
hooks.connectStop.trigger(event)
|
||||
|
||||
if (isValid) {
|
||||
hooks.connect.trigger(connection);
|
||||
hooks.connect.trigger(connection)
|
||||
}
|
||||
|
||||
hooks.connectEnd.trigger(event);
|
||||
hooks.connectEnd.trigger(event)
|
||||
|
||||
if (elementEdgeUpdaterType) {
|
||||
hooks.edgeUpdateEnd.trigger({ event } as any);
|
||||
hooks.edgeUpdateEnd.trigger({ event } as any)
|
||||
}
|
||||
|
||||
resetRecentHandle(recentHoveredHandle);
|
||||
store.setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null });
|
||||
resetRecentHandle(recentHoveredHandle)
|
||||
store.setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null })
|
||||
|
||||
doc.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject);
|
||||
doc.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject);
|
||||
doc.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject)
|
||||
doc.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject)
|
||||
}
|
||||
|
||||
doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject);
|
||||
doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject);
|
||||
doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject)
|
||||
doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ElementId, Position, RevueFlowStore } from '../../types';
|
||||
import { onMouseDown, ValidConnectionFunc } from './handler';
|
||||
import { defineComponent, inject, PropType } from 'vue';
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
|
||||
import { ElementId, Position, RevueFlowStore } from '../../types'
|
||||
import { onMouseDown, ValidConnectionFunc } from './handler'
|
||||
import { defineComponent, inject, PropType } from 'vue'
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
|
||||
|
||||
const alwaysValid = () => true;
|
||||
const alwaysValid = () => true
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -34,12 +34,12 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!;
|
||||
const nodeId = inject<ElementId>('NodeIdContext')!;
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!
|
||||
const nodeId = inject<ElementId>('NodeIdContext')!
|
||||
|
||||
const onMouseDownHandler = (event: MouseEvent) =>
|
||||
onMouseDown(event, store, hooks, props.id as string, nodeId, props.type === 'target', props.isValidConnection);
|
||||
onMouseDown(event, store, hooks, props.id as string, nodeId, props.type === 'target', props.isValidConnection)
|
||||
|
||||
return () => (
|
||||
<div
|
||||
@@ -60,6 +60,6 @@ export default defineComponent({
|
||||
>
|
||||
{slots.default ? slots.default() : ''}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, NodeType, Position } from '../../types';
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import Handle from '../../components/Handle'
|
||||
import { NodeProps, NodeType, Position } from '../../types'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DefaultNode',
|
||||
@@ -35,6 +35,6 @@ export default defineComponent({
|
||||
{props.data?.label}
|
||||
<Handle type="source" position={props.sourcePosition} isConnectable={props.isConnectable} />
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as NodeType;
|
||||
}) as NodeType
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, NodeType, Position } from '../../types';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import Handle from '../../components/Handle'
|
||||
import { NodeProps, NodeType, Position } from '../../types'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'InputNode',
|
||||
@@ -29,6 +29,6 @@ export default defineComponent({
|
||||
{props.data?.label}
|
||||
<Handle type="source" position={props.sourcePosition} isConnectable={props.isConnectable} />
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as NodeType;
|
||||
}) as NodeType
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { computed, defineComponent, h, inject, onMounted, PropType, provide } from 'vue';
|
||||
import { templateRef, useResizeObserver } from '@vueuse/core';
|
||||
import { DraggableCore, DraggableEventListener } from '@braks/revue-draggable';
|
||||
import { Node, NodeDimensionUpdate, NodeType, RevueFlowStore } from '../../types';
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
|
||||
import { computed, defineComponent, h, inject, onMounted, PropType, provide } from 'vue'
|
||||
import { templateRef, useResizeObserver } from '@vueuse/core'
|
||||
import { DraggableCore, DraggableEventListener } from '@braks/revue-draggable'
|
||||
import { Node, NodeDimensionUpdate, NodeType, RevueFlowStore } from '../../types'
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
|
||||
|
||||
interface NodeProps {
|
||||
nodeTypes: Record<string, NodeType>;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [number, number];
|
||||
selectNodesOnDrag: boolean;
|
||||
nodeTypes: Record<string, NodeType>
|
||||
snapToGrid: boolean
|
||||
snapGrid: [number, number]
|
||||
selectNodesOnDrag: boolean
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -39,22 +39,22 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!;
|
||||
provide('NodeIdContext', props.node.id);
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!
|
||||
provide('NodeIdContext', props.node.id)
|
||||
|
||||
const nodeElement = templateRef<HTMLDivElement>('nodeElement', null);
|
||||
const nodeElement = templateRef<HTMLDivElement>('nodeElement', null)
|
||||
|
||||
const selected = computed(() => store.selectedElements?.some(({ id }) => id === props.node.id) || false);
|
||||
const selected = computed(() => store.selectedElements?.some(({ id }) => id === props.node.id) || false)
|
||||
const isDraggable = computed(
|
||||
() => props.node.draggable || (store.nodesDraggable && typeof props.node.draggable === 'undefined')
|
||||
);
|
||||
)
|
||||
const isSelectable = computed(
|
||||
() => props.node.selectable || (store.elementsSelectable && typeof props.node.selectable === 'undefined')
|
||||
);
|
||||
)
|
||||
const isConnectable = computed(
|
||||
() => props.node.connectable || (store.nodesConnectable && typeof props.node.connectable === 'undefined')
|
||||
);
|
||||
)
|
||||
|
||||
const node = () =>
|
||||
({
|
||||
@@ -62,72 +62,72 @@ export default defineComponent({
|
||||
type: props.node.type,
|
||||
position: { x: props.node.__rf.position.x, y: props.node.__rf.position.y },
|
||||
data: props.node.data
|
||||
} as Node);
|
||||
} as Node)
|
||||
|
||||
const onMouseEnterHandler = () => {
|
||||
if (props.node.__rf.isDragging) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
return (event: MouseEvent) => hooks.nodeMouseEnter.trigger({ event, node: node() });
|
||||
};
|
||||
return (event: MouseEvent) => hooks.nodeMouseEnter.trigger({ event, node: node() })
|
||||
}
|
||||
|
||||
const onMouseMoveHandler = () => {
|
||||
if (props.node.__rf.isDragging) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
return (event: MouseEvent) => hooks.nodeMouseMove.trigger({ event, node: node() });
|
||||
};
|
||||
return (event: MouseEvent) => hooks.nodeMouseMove.trigger({ event, node: node() })
|
||||
}
|
||||
|
||||
const onMouseLeaveHandler = () => {
|
||||
if (props.node.__rf.isDragging) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
return (event: MouseEvent) => hooks.nodeMouseLeave.trigger({ event, node: node() });
|
||||
};
|
||||
return (event: MouseEvent) => hooks.nodeMouseLeave.trigger({ event, node: node() })
|
||||
}
|
||||
|
||||
const onContextMenuHandler = () => {
|
||||
return (event: MouseEvent) => hooks.nodeContextMenu.trigger({ event, node: node() });
|
||||
};
|
||||
return (event: MouseEvent) => hooks.nodeContextMenu.trigger({ event, node: node() })
|
||||
}
|
||||
|
||||
const onSelectNodeHandler = (event: MouseEvent) => {
|
||||
if (!isDraggable.value) {
|
||||
const n = node();
|
||||
const n = node()
|
||||
if (isSelectable.value) {
|
||||
store.unsetNodesSelection();
|
||||
store.unsetNodesSelection()
|
||||
|
||||
if (!selected.value) {
|
||||
store.addSelectedElements([n]);
|
||||
store.addSelectedElements([n])
|
||||
}
|
||||
}
|
||||
|
||||
hooks.nodeClick.trigger({ event, node: n });
|
||||
hooks.nodeClick.trigger({ event, node: n })
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const onDragStart: DraggableEventListener = ({ event }) => {
|
||||
const n = node();
|
||||
hooks.nodeDragStart.trigger({ event, node: n });
|
||||
const n = node()
|
||||
hooks.nodeDragStart.trigger({ event, node: n })
|
||||
|
||||
if (props.selectNodesOnDrag && isSelectable.value) {
|
||||
store.unsetNodesSelection();
|
||||
store.unsetNodesSelection()
|
||||
|
||||
if (!selected.value) {
|
||||
store.addSelectedElements([n]);
|
||||
store.addSelectedElements([n])
|
||||
}
|
||||
} else if (!props.selectNodesOnDrag && !selected.value && isSelectable.value) {
|
||||
store.unsetNodesSelection();
|
||||
store.addSelectedElements([]);
|
||||
store.unsetNodesSelection()
|
||||
store.addSelectedElements([])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const onDrag: DraggableEventListener = ({ event, data }) => {
|
||||
const n = node();
|
||||
n.position.x += data.deltaX;
|
||||
n.position.y += data.deltaY;
|
||||
hooks.nodeDrag.trigger({ event, node: n });
|
||||
const n = node()
|
||||
n.position.x += data.deltaX
|
||||
n.position.y += data.deltaY
|
||||
hooks.nodeDrag.trigger({ event, node: n })
|
||||
|
||||
store?.updateNodePosDiff({
|
||||
id: props.node.id as string,
|
||||
@@ -136,39 +136,39 @@ export default defineComponent({
|
||||
y: data.deltaY
|
||||
},
|
||||
isDragging: true
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
const onDragStop: DraggableEventListener = ({ event }) => {
|
||||
const n = node();
|
||||
const n = node()
|
||||
// onDragStop also gets called when user just clicks on a node.
|
||||
// Because of that we set dragging to true inside the onDrag handler and handle the click here
|
||||
if (!props.node.__rf.isDragging) {
|
||||
if (isSelectable.value && !props.selectNodesOnDrag && !selected.value) {
|
||||
store.addSelectedElements([n]);
|
||||
store.addSelectedElements([n])
|
||||
}
|
||||
|
||||
hooks.nodeClick.trigger({ event, node: n });
|
||||
hooks.nodeClick.trigger({ event, node: n })
|
||||
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
store.updateNodePosDiff({
|
||||
id: n.id || '',
|
||||
isDragging: false
|
||||
});
|
||||
})
|
||||
|
||||
hooks.nodeDragStop.trigger({ event, node: n });
|
||||
};
|
||||
hooks.nodeDragStop.trigger({ event, node: n })
|
||||
}
|
||||
|
||||
useResizeObserver(nodeElement, (entries) => {
|
||||
const updates: NodeDimensionUpdate[] = entries.map((entry) => ({
|
||||
id: entry.target.getAttribute('data-id') || '',
|
||||
nodeElement: entry.target as HTMLDivElement
|
||||
}));
|
||||
}))
|
||||
|
||||
store.updateNodeDimensions(updates);
|
||||
});
|
||||
store.updateNodeDimensions(updates)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
store.updateNodeDimensions([
|
||||
@@ -177,8 +177,8 @@ export default defineComponent({
|
||||
nodeElement: nodeElement.value,
|
||||
forceUpdate: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
])
|
||||
})
|
||||
|
||||
return () =>
|
||||
props.node.isHidden ? (
|
||||
@@ -231,6 +231,6 @@ export default defineComponent({
|
||||
})}
|
||||
</div>
|
||||
</DraggableCore>
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Handle from '../../components/Handle';
|
||||
import { NodeProps, NodeType, Position } from '../../types';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import Handle from '../../components/Handle'
|
||||
import { NodeProps, NodeType, Position } from '../../types'
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'OutputNode',
|
||||
@@ -29,6 +29,6 @@ export default defineComponent({
|
||||
{props.data?.label}
|
||||
<Handle type="source" position={props.targetPosition} isConnectable={props.isConnectable} />
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
}) as NodeType;
|
||||
}) as NodeType
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { HandleElement, Position } from '../../types';
|
||||
import { getDimensions } from '../../utils';
|
||||
import { HandleElement, Position } from '../../types'
|
||||
import { getDimensions } from '../../utils'
|
||||
|
||||
export const getHandleBounds = (nodeElement: HTMLDivElement, scale: number) => {
|
||||
const bounds = nodeElement.getBoundingClientRect();
|
||||
const bounds = nodeElement.getBoundingClientRect()
|
||||
|
||||
return {
|
||||
source: getHandleBoundsByHandleType('.source', nodeElement, bounds, scale),
|
||||
target: getHandleBoundsByHandleType('.target', nodeElement, bounds, scale)
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const getHandleBoundsByHandleType = (
|
||||
selector: string,
|
||||
@@ -16,19 +16,19 @@ export const getHandleBoundsByHandleType = (
|
||||
parentBounds: ClientRect | DOMRect,
|
||||
k: number
|
||||
): HandleElement[] | null => {
|
||||
const handles = nodeElement.querySelectorAll(selector);
|
||||
const handles = nodeElement.querySelectorAll(selector)
|
||||
|
||||
if (!handles || !handles.length) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const handlesArray = Array.from(handles) as HTMLDivElement[];
|
||||
const handlesArray = Array.from(handles) as HTMLDivElement[]
|
||||
|
||||
return handlesArray.map((handle): HandleElement => {
|
||||
const bounds = handle.getBoundingClientRect();
|
||||
const dimensions = getDimensions(handle);
|
||||
const handleId = handle.getAttribute('data-handleid');
|
||||
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position;
|
||||
const bounds = handle.getBoundingClientRect()
|
||||
const dimensions = getDimensions(handle)
|
||||
const handleId = handle.getAttribute('data-handleid')
|
||||
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position
|
||||
|
||||
return {
|
||||
id: handleId,
|
||||
@@ -36,6 +36,6 @@ export const getHandleBoundsByHandleType = (
|
||||
x: (bounds.left - parentBounds.left) / k,
|
||||
y: (bounds.top - parentBounds.top) / k,
|
||||
...dimensions
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,56 +3,56 @@
|
||||
* The nodes selection rectangle gets displayed when a user
|
||||
* made a selectio with on or several nodes
|
||||
*/
|
||||
import { computed, defineComponent, inject } from 'vue';
|
||||
import { Draggable, DraggableEventListener } from '@braks/revue-draggable';
|
||||
import { isNode } from '../../utils/graph';
|
||||
import { Node, RevueFlowStore } from '../../types';
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
|
||||
import { computed, defineComponent, inject } from 'vue'
|
||||
import { Draggable, DraggableEventListener } from '@braks/revue-draggable'
|
||||
import { isNode } from '../../utils/graph'
|
||||
import { Node, RevueFlowStore } from '../../types'
|
||||
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
|
||||
|
||||
export interface NodesSelectionProps {
|
||||
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
|
||||
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void;
|
||||
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void;
|
||||
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void;
|
||||
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void
|
||||
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void
|
||||
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void
|
||||
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void
|
||||
}
|
||||
|
||||
const NodesSelection = defineComponent({
|
||||
setup() {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!;
|
||||
const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number]);
|
||||
const transform = computed(() => store.transform);
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!
|
||||
const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number])
|
||||
const transform = computed(() => store.transform)
|
||||
|
||||
const selectedNodes = computed(() =>
|
||||
store.selectedElements
|
||||
? store.selectedElements.filter(isNode).map((selectedNode) => {
|
||||
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id);
|
||||
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id)
|
||||
|
||||
return {
|
||||
...matchingNode,
|
||||
position: matchingNode?.__rf.position
|
||||
} as Node;
|
||||
} as Node
|
||||
})
|
||||
: []
|
||||
);
|
||||
)
|
||||
|
||||
const style = computed(() => ({
|
||||
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`
|
||||
}));
|
||||
}))
|
||||
|
||||
const innerStyle = computed(() => ({
|
||||
width: `${store.selectedNodesBbox.width}px`,
|
||||
height: `${store.selectedNodesBbox.height}px`,
|
||||
top: `${store.selectedNodesBbox.y}px`,
|
||||
left: `${store.selectedNodesBbox.x}px`
|
||||
}));
|
||||
}))
|
||||
|
||||
const onStart: DraggableEventListener = ({ event }) => {
|
||||
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value });
|
||||
};
|
||||
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value })
|
||||
}
|
||||
|
||||
const onDrag: DraggableEventListener = ({ event, data }) => {
|
||||
hooks.selectionDrag.trigger({ event, nodes: selectedNodes.value });
|
||||
hooks.selectionDrag.trigger({ event, nodes: selectedNodes.value })
|
||||
|
||||
store.updateNodePosDiff({
|
||||
diff: {
|
||||
@@ -60,24 +60,24 @@ const NodesSelection = defineComponent({
|
||||
y: data.deltaY
|
||||
},
|
||||
isDragging: true
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
const onStop: DraggableEventListener = ({ event }) => {
|
||||
store.updateNodePosDiff({
|
||||
isDragging: false
|
||||
});
|
||||
})
|
||||
|
||||
hooks.selectionDragStop.trigger({ event, nodes: selectedNodes.value });
|
||||
};
|
||||
hooks.selectionDragStop.trigger({ event, nodes: selectedNodes.value })
|
||||
}
|
||||
|
||||
const onContextMenu = (event: MouseEvent) => {
|
||||
const selectedNodes: Node[] = store.selectedElements
|
||||
? store.selectedElements.filter(isNode).map((selectedNode) => store.nodes.find((node) => node.id === selectedNode.id))
|
||||
: [];
|
||||
: []
|
||||
|
||||
hooks.selectionContextMenu.trigger({ event, nodes: selectedNodes });
|
||||
};
|
||||
hooks.selectionContextMenu.trigger({ event, nodes: selectedNodes })
|
||||
}
|
||||
|
||||
return () => {
|
||||
return !store.selectedElements || store.selectionActive ? (
|
||||
@@ -95,9 +95,9 @@ const NodesSelection = defineComponent({
|
||||
<div class="revue-flow__nodesselection-rect" onContextmenu={onContextMenu} style={innerStyle.value} />
|
||||
</Draggable>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
export default NodesSelection;
|
||||
export default NodesSelection
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/**
|
||||
* The user selection rectangle gets displayed when a user drags the mouse while pressing shift
|
||||
*/
|
||||
import { RevueFlowStore, XYPosition } from '../../types';
|
||||
import { computed, defineComponent, inject } from 'vue';
|
||||
import { templateRef, useEventListener } from '@vueuse/core';
|
||||
import { RevueFlowStore, XYPosition } from '../../types'
|
||||
import { computed, defineComponent, inject } from 'vue'
|
||||
import { templateRef, useEventListener } from '@vueuse/core'
|
||||
|
||||
function getMousePosition(event: MouseEvent): XYPosition | void {
|
||||
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
||||
const revueFlowNode = (event.target as Element).closest('.revue-flow')
|
||||
if (!revueFlowNode) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const containerBounds = revueFlowNode.getBoundingClientRect();
|
||||
const containerBounds = revueFlowNode.getBoundingClientRect()
|
||||
|
||||
return {
|
||||
x: event.clientX - containerBounds.left,
|
||||
y: event.clientY - containerBounds.top
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const SelectionRect = (props: { width: number; height: number; x: number; y: number }) => {
|
||||
@@ -29,51 +29,51 @@ const SelectionRect = (props: { width: number; height: number; x: number; y: num
|
||||
transform: `translate(${props.x}px, ${props.y}px)`
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: { SelectionRect },
|
||||
setup() {
|
||||
const store = inject<RevueFlowStore>('store')!;
|
||||
const el = templateRef('user-selection', null);
|
||||
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable);
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const el = templateRef('user-selection', null)
|
||||
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable)
|
||||
|
||||
const onMouseDown = (event: MouseEvent) => {
|
||||
const mousePos = getMousePosition(event);
|
||||
const mousePos = getMousePosition(event)
|
||||
if (!mousePos) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
store.setUserSelection(mousePos);
|
||||
};
|
||||
store.setUserSelection(mousePos)
|
||||
}
|
||||
|
||||
const onMouseMove = (event: MouseEvent) => {
|
||||
if (!store.selectionActive) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const mousePos = getMousePosition(event);
|
||||
const mousePos = getMousePosition(event)
|
||||
if (!mousePos) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
store.updateUserSelection(mousePos);
|
||||
};
|
||||
store.updateUserSelection(mousePos)
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
store.unsetUserSelection();
|
||||
};
|
||||
store.unsetUserSelection()
|
||||
}
|
||||
|
||||
const onMouseLeave = () => {
|
||||
store.unsetUserSelection();
|
||||
store.unsetNodesSelection();
|
||||
};
|
||||
store.unsetUserSelection()
|
||||
store.unsetNodesSelection()
|
||||
}
|
||||
|
||||
useEventListener(el, 'mousedown', onMouseDown);
|
||||
useEventListener(el, 'mousemove', onMouseMove);
|
||||
useEventListener(el, 'click', onMouseUp);
|
||||
useEventListener(el, 'mouseup', onMouseUp);
|
||||
useEventListener(el, 'mouseleave', onMouseLeave);
|
||||
useEventListener(el, 'mousedown', onMouseDown)
|
||||
useEventListener(el, 'mousemove', onMouseMove)
|
||||
useEventListener(el, 'click', onMouseUp)
|
||||
useEventListener(el, 'mouseup', onMouseUp)
|
||||
useEventListener(el, 'mouseleave', onMouseLeave)
|
||||
|
||||
return () =>
|
||||
shouldRender.value ? (
|
||||
@@ -91,6 +91,6 @@ export default defineComponent({
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user