update(script-setup): Refactor remaining files to script setup style
This commit is contained in:
@@ -1,49 +1,72 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import Edge from '~/components/Edges/Edge'
|
||||
import { ConnectionLineComponent, ConnectionLineType, ConnectionMode, Dimensions, Edge as TEdge, Transform } from '~/types'
|
||||
import { getSourceTargetNodes } from '~/container/EdgeRenderer/utils'
|
||||
import Edge from '~/components/Edges/Edge.vue'
|
||||
import ConnectionLine from '~/components/ConnectionLine/ConnectionLine.vue'
|
||||
import {
|
||||
ConnectionLineType,
|
||||
ConnectionMode,
|
||||
CustomConnectionLine,
|
||||
Dimensions,
|
||||
EdgeType,
|
||||
RevueFlowStore,
|
||||
Transform,
|
||||
} from '~/types'
|
||||
import MarkerDefinitions from '~/container/MarkerDefinitions.vue'
|
||||
|
||||
interface EdgeRendererProps {
|
||||
edges: TEdge[]
|
||||
edgeTypes: any
|
||||
transform: Transform
|
||||
connectionLineType: ConnectionLineType
|
||||
connectionLineStyle?: CSSProperties
|
||||
connectionLineComponent?: ConnectionLineComponent
|
||||
connectionMode?: ConnectionMode
|
||||
arrowHeadColor: string
|
||||
markerEndId?: string
|
||||
onlyRenderVisibleElements: boolean
|
||||
edgeUpdaterRadius?: number
|
||||
edgeTypes: Record<string, EdgeType>
|
||||
dimensions: Dimensions
|
||||
transform: Transform
|
||||
connectionLineType?: ConnectionLineType
|
||||
connectionLineStyle?: CSSProperties
|
||||
customConnectionLine?: CustomConnectionLine
|
||||
connectionMode?: ConnectionMode
|
||||
arrowHeadColor?: string
|
||||
markerEndId?: string
|
||||
onlyRenderVisibleElements?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<EdgeRendererProps>(), {
|
||||
transform: () => [0, 0, 1],
|
||||
edges: () => [],
|
||||
arrowHeadColor: '#fff',
|
||||
arrowHeadColor: '#b1b1b7',
|
||||
dimensions: () => ({ width: 0, height: 0 }),
|
||||
onlyRenderVisibleElements: false,
|
||||
connectionMode: ConnectionMode.Strict,
|
||||
connectionLineType: ConnectionLineType.Bezier,
|
||||
})
|
||||
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
|
||||
const sourceNode = computed(() => store.nodes.find((n) => n.id === store.connectionNodeId))
|
||||
const connectionLineVisible = computed(
|
||||
() => store.nodesConnectable && sourceNode.value && store.connectionNodeId && store.connectionHandleType,
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<svg :width="props.dimensions.width" :height="props.dimensions.height" class="revue-flow__edges">
|
||||
<MarkerDefinitions :color="props.arrowHeadColor" />
|
||||
<g
|
||||
:transform="
|
||||
props.transform &&
|
||||
props.transform.length &&
|
||||
`translate(${props.transform[0]},${props.transform[1]}) scale(${props.transform[2]})`
|
||||
"
|
||||
:transform="props.transform.length && `translate(${props.transform[0]},${props.transform[1]}) scale(${props.transform[2]})`"
|
||||
>
|
||||
<template v-for="(edge, i) of props.edges" :key="`edge-${i}`">
|
||||
<template v-for="(edge, i) of store.edges" :key="`edge-${i}`">
|
||||
<Edge
|
||||
:edge="edge"
|
||||
:nodes="getSourceTargetNodes(edge, store.nodes)"
|
||||
:type="props.edgeTypes[edge.type || 'default']"
|
||||
:dimensions="props.dimensions"
|
||||
:transform="props.transform"
|
||||
:only-render-visible-elements="props.onlyRenderVisibleElements"
|
||||
:marker-end-id="props.markerEndId"
|
||||
/>
|
||||
</template>
|
||||
<ConnectionLine
|
||||
v-if="connectionLineVisible"
|
||||
:source-node="sourceNode"
|
||||
:connection-line-style="props.connectionLineStyle"
|
||||
:connection-line-type="props.connectionLineType"
|
||||
:custom-connection-line="props.customConnectionLine"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CSSProperties, defineComponent, inject, PropType } from 'vue'
|
||||
import { ConnectionLineType, ConnectionLineComponent, ConnectionMode, RevueFlowStore } from '../../types'
|
||||
import ConnectionLine from '../../components/ConnectionLine'
|
||||
import Edge from '../../components/Edges/EdgeDepr'
|
||||
import MarkerDefinitions from './MarkerDefinitions'
|
||||
import Edge from '../../components/Edges/Edge'
|
||||
|
||||
interface EdgeRendererProps {
|
||||
edgeTypes: any
|
||||
@@ -21,59 +21,59 @@ export default defineComponent({
|
||||
components: {
|
||||
Edge,
|
||||
ConnectionLine,
|
||||
MarkerDefinitions
|
||||
MarkerDefinitions,
|
||||
},
|
||||
props: {
|
||||
edgeTypes: {
|
||||
type: Object,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
connectionLineType: {
|
||||
type: String as PropType<EdgeRendererProps['connectionLineType']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
connectionLineStyle: {
|
||||
type: Object as PropType<EdgeRendererProps['connectionLineStyle']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
connectionLineComponent: {
|
||||
type: Object as PropType<EdgeRendererProps['connectionLineComponent']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
connectionMode: {
|
||||
type: String as PropType<EdgeRendererProps['connectionMode']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
arrowHeadColor: {
|
||||
type: String as PropType<EdgeRendererProps['arrowHeadColor']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
markerEndId: {
|
||||
type: String as PropType<EdgeRendererProps['markerEndId']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
onlyRenderVisibleElements: {
|
||||
type: Boolean as PropType<EdgeRendererProps['onlyRenderVisibleElements']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
edgeUpdaterRadius: {
|
||||
type: Number as PropType<EdgeRendererProps['edgeUpdaterRadius']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
}
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
|
||||
return () => (
|
||||
<svg width={store.width} height={store.height} class="revue-flow__edges">
|
||||
<svg width={store.width} height={store.height} className="revue-flow__edges">
|
||||
<MarkerDefinitions color={props.arrowHeadColor} />
|
||||
<g transform={`translate(${store.transform[0]},${store.transform[1]}) scale(${store.transform[2]})`}>
|
||||
{store.edges.map((edge, i) => (
|
||||
@@ -95,5 +95,5 @@ export default defineComponent({
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Ref } from 'vue'
|
||||
import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '~/components/Edges'
|
||||
import { rectToBox } from '~/utils/graph'
|
||||
import { Position, Node, XYPosition, ElementId, HandleElement, Transform, Edge, EdgeType } from '~/types'
|
||||
@@ -137,12 +138,12 @@ export function isEdgeVisible({ sourcePos, targetPos, width, height, transform }
|
||||
}
|
||||
|
||||
type SourceTargetNode = {
|
||||
sourceNode: Node | null
|
||||
targetNode: Node | null
|
||||
sourceNode: Node
|
||||
targetNode: Node
|
||||
}
|
||||
|
||||
export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): SourceTargetNode => {
|
||||
return nodes.reduce(
|
||||
export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): Ref<SourceTargetNode> => {
|
||||
const sourceTargetNode: SourceTargetNode = nodes.reduce(
|
||||
(res, node) => {
|
||||
if (node.id === edge.source) {
|
||||
res.sourceNode = node
|
||||
@@ -152,6 +153,8 @@ export const getSourceTargetNodes = (edge: Edge, nodes: Node[]): SourceTargetNod
|
||||
}
|
||||
return res
|
||||
},
|
||||
{ sourceNode: null, targetNode: null } as SourceTargetNode,
|
||||
{ sourceNode: null, targetNode: null } as any,
|
||||
)
|
||||
|
||||
return ref(sourceTargetNode)
|
||||
}
|
||||
|
||||
+50
-96
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import '~/style.css'
|
||||
import '~/theme-default.css'
|
||||
import { CSSProperties } from 'vue'
|
||||
import { CSSProperties, onBeforeUnmount } from 'vue'
|
||||
import ZoomPane from './ZoomPane.vue'
|
||||
import SelectionPane from './SelectionPane.vue'
|
||||
import NodeRenderer from '~/container/NodeRenderer.vue'
|
||||
@@ -12,11 +12,9 @@ import {
|
||||
Elements,
|
||||
PanOnScrollMode,
|
||||
RevueFlowStore,
|
||||
Node,
|
||||
Edge,
|
||||
NodeType,
|
||||
EdgeType,
|
||||
ConnectionLineComponent,
|
||||
CustomConnectionLine,
|
||||
KeyCode,
|
||||
TranslateExtent,
|
||||
NodeExtent,
|
||||
@@ -25,21 +23,18 @@ import { RevueFlowHooks, useRevueFlow } from '~/hooks/RevueFlowHooks'
|
||||
import configureStore from '~/store/configure-store'
|
||||
import { initialState } from '~/store'
|
||||
import { createNodeTypes } from '~/container/NodeRenderer/utils'
|
||||
import InputNode from '~/components/Nodes/InputNode'
|
||||
import DefaultNode from '~/components/Nodes/DefaultNode'
|
||||
import OutputNode from '~/components/Nodes/OutputNode'
|
||||
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
|
||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
|
||||
import { createEdgeTypes } from '~/container/EdgeRenderer/utils'
|
||||
import { isEdge, isNode, parseEdge, parseNode } from '~/utils/graph'
|
||||
|
||||
interface RevueFlowProps {
|
||||
modelValue: Elements
|
||||
elements: Elements
|
||||
nodeTypes?: Record<string, NodeType>
|
||||
edgeTypes?: Record<string, EdgeType>
|
||||
connectionMode?: ConnectionMode
|
||||
connectionLineType?: ConnectionLineType
|
||||
connectionLineStyle?: CSSProperties
|
||||
connectionLineComponent?: ConnectionLineComponent
|
||||
connectionLineComponent?: CustomConnectionLine
|
||||
deleteKeyCode?: KeyCode
|
||||
selectionKeyCode?: KeyCode
|
||||
multiSelectionKeyCode?: KeyCode
|
||||
@@ -69,11 +64,6 @@ interface RevueFlowProps {
|
||||
edgeUpdaterRadius?: number
|
||||
}
|
||||
|
||||
type NextElements = {
|
||||
nextNodes: Node[]
|
||||
nextEdges: Edge[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<RevueFlowProps>(), {
|
||||
modelValue: () => [] as Elements,
|
||||
connectionMode: ConnectionMode.Strict,
|
||||
@@ -86,6 +76,7 @@ const props = withDefaults(defineProps<RevueFlowProps>(), {
|
||||
snapGrid: () => [15, 15],
|
||||
onlyRenderVisibleElements: false,
|
||||
nodesConnectable: true,
|
||||
nodesDraggable: true,
|
||||
elementsSelectable: true,
|
||||
selectNodesOnDrag: true,
|
||||
minZoom: 0.5,
|
||||
@@ -112,102 +103,65 @@ const props = withDefaults(defineProps<RevueFlowProps>(), {
|
||||
})
|
||||
const emit = defineEmits(Object.keys(useRevueFlow()))
|
||||
|
||||
const store = configureStore(initialState)()
|
||||
provide<RevueFlowStore>('store', store)
|
||||
const defaultNodeTypes: Record<string, NodeType> = {
|
||||
input: InputNode as NodeType,
|
||||
default: DefaultNode as NodeType,
|
||||
output: OutputNode as NodeType,
|
||||
}
|
||||
|
||||
const defaultEdgeTypes: Record<string, EdgeType> = {
|
||||
default: BezierEdge as EdgeType,
|
||||
straight: StraightEdge as EdgeType,
|
||||
step: StepEdge as EdgeType,
|
||||
smoothstep: SmoothStepEdge as EdgeType,
|
||||
}
|
||||
|
||||
let store = inject<RevueFlowStore>('store')
|
||||
if (!store) {
|
||||
store = configureStore({
|
||||
...initialState,
|
||||
...props,
|
||||
})()
|
||||
provide<RevueFlowStore>('store', store)
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => store?.$dispose())
|
||||
|
||||
store.setElements(props.elements)
|
||||
store.setMinZoom(props.minZoom)
|
||||
store.setMaxZoom(props.maxZoom)
|
||||
store.setTranslateExtent(props.translateExtent)
|
||||
store.setNodeExtent(props.nodeExtent)
|
||||
|
||||
const hooks = useRevueFlow().bind(emit)
|
||||
provide<RevueFlowHooks>('hooks', hooks)
|
||||
|
||||
const elements = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const defaultNodeTypes = {
|
||||
input: InputNode,
|
||||
default: DefaultNode,
|
||||
output: OutputNode,
|
||||
}
|
||||
|
||||
const defaultEdgeTypes = {
|
||||
default: BezierEdge,
|
||||
straight: StraightEdge,
|
||||
step: StepEdge,
|
||||
smoothstep: SmoothStepEdge,
|
||||
}
|
||||
|
||||
const nodeTypes = createNodeTypes({ ...defaultNodeTypes, ...props.nodeTypes })
|
||||
const edgeTypes = createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })
|
||||
const nodes = ref<Node[]>([])
|
||||
const edges = ref<Edge[]>([])
|
||||
|
||||
const setElements = (elements: Elements) => {
|
||||
const propElements = elements
|
||||
const nextElements: NextElements = {
|
||||
nextNodes: [],
|
||||
nextEdges: [],
|
||||
}
|
||||
const { nextNodes, nextEdges } = propElements.reduce((res, propElement): NextElements => {
|
||||
if (isNode(propElement)) {
|
||||
const storeNode = nodes.value.find((node) => node.id === propElement.id)
|
||||
|
||||
if (storeNode) {
|
||||
const updatedNode: Node = {
|
||||
...storeNode,
|
||||
...propElement,
|
||||
}
|
||||
|
||||
if (storeNode.position.x !== propElement.position.x || storeNode.position.y !== propElement.position.y) {
|
||||
updatedNode.__rf.position = propElement.position
|
||||
}
|
||||
|
||||
if (typeof propElement.type !== 'undefined' && propElement.type !== storeNode.type) {
|
||||
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
||||
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
||||
updatedNode.__rf.width = null
|
||||
}
|
||||
|
||||
res.nextNodes.push(updatedNode)
|
||||
} else {
|
||||
res.nextNodes.push(parseNode(propElement, props.nodeExtent))
|
||||
}
|
||||
} else if (isEdge(propElement)) {
|
||||
const storeEdge = edges.value.find((se) => se.id === propElement.id)
|
||||
|
||||
if (storeEdge) {
|
||||
res.nextEdges.push({
|
||||
...storeEdge,
|
||||
...propElement,
|
||||
})
|
||||
} else {
|
||||
res.nextEdges.push(parseEdge(propElement))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}, nextElements)
|
||||
|
||||
nodes.value = nextNodes
|
||||
edges.value = nextEdges
|
||||
}
|
||||
|
||||
setElements(elements.value)
|
||||
</script>
|
||||
<template>
|
||||
<div class="revue-flow">
|
||||
<ZoomPane>
|
||||
<ZoomPane
|
||||
:selection-key-code="props.selectionKeyCode"
|
||||
:zoom-activation-key-code="props.zoomActivationKeyCode"
|
||||
:default-zoom="props.defaultZoom"
|
||||
:default-position="props.defaultPosition"
|
||||
:zoom-on-scroll="props.zoomOnScroll"
|
||||
:zoom-on-pinch="props.zoomOnPinch"
|
||||
:zoom-on-double-click="props.zoomOnDoubleClick"
|
||||
:pan-on-scroll="props.panOnScroll"
|
||||
:pan-on-scroll-speed="props.panOnScrollSpeed"
|
||||
:pan-on-scroll-mode="props.panOnScrollMode"
|
||||
:pane-moveable="props.paneMoveable"
|
||||
>
|
||||
<template #default="{ transform, dimensions }">
|
||||
<SelectionPane
|
||||
:delete-key-code="props.deleteKeyCode"
|
||||
:multi-selection-key-code="props.multiSelectionKeyCode"
|
||||
:selection-key-code="props.selectionKeyCode"
|
||||
>
|
||||
<NodeRenderer v-bind="props" :node-types="nodeTypes" :nodes="nodes" :transform="transform" :dimensions="dimensions" />
|
||||
<EdgeRenderer
|
||||
v-if="false"
|
||||
v-bind="props"
|
||||
:edge-types="edgeTypes"
|
||||
:edges="edges"
|
||||
:transform="transform"
|
||||
:dimensions="dimensions"
|
||||
/>
|
||||
<NodeRenderer :node-types="nodeTypes" :transform="transform" :dimensions="dimensions" />
|
||||
<EdgeRenderer :edge-types="edgeTypes" :transform="transform" :dimensions="dimensions" />
|
||||
</SelectionPane>
|
||||
</template>
|
||||
</ZoomPane>
|
||||
|
||||
@@ -1,37 +1,26 @@
|
||||
<script lang="ts" setup>
|
||||
import Node from '~/components/Node.vue'
|
||||
import { NodeType, Node as TNode, Transform, Dimensions, NodeDimensionUpdate } from '~/types'
|
||||
import Node from '~/components/Nodes/Node.vue'
|
||||
import { NodeType, Node as TNode, Transform, Dimensions, RevueFlowStore } from '~/types'
|
||||
import { getNodesInside } from '~/utils/graph'
|
||||
import { getDimensions } from '~/utils'
|
||||
import { getHandleBounds } from '~/components/Nodes/utils'
|
||||
|
||||
interface NodeRendererProps {
|
||||
nodes: TNode[]
|
||||
transform: Transform
|
||||
nodeTypes: Record<string, NodeType>
|
||||
selectNodesOnDrag: boolean
|
||||
snapToGrid: boolean
|
||||
snapGrid: [number, number]
|
||||
onlyRenderVisibleElements: boolean
|
||||
dimensions: Dimensions
|
||||
transform: Transform
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<NodeRendererProps>(), {
|
||||
selectNodesOnDrag: true,
|
||||
snapGrid: () => [15, 15],
|
||||
snapToGrid: false,
|
||||
onlyRenderVisibleElements: false,
|
||||
transform: () => [0, 0, 1],
|
||||
nodes: () => [],
|
||||
dimensions: () => ({ width: 0, height: 0 }),
|
||||
})
|
||||
|
||||
const nodes = ref(props.nodes)
|
||||
const getNodes = () =>
|
||||
props.onlyRenderVisibleElements
|
||||
? nodes.value &&
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
|
||||
const getNodes = computed(() =>
|
||||
store.onlyRenderVisibleElements
|
||||
? store.nodes &&
|
||||
getNodesInside(
|
||||
nodes.value,
|
||||
store.nodes,
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
@@ -41,9 +30,8 @@ const getNodes = () =>
|
||||
props.transform,
|
||||
true,
|
||||
)
|
||||
: nodes.value
|
||||
|
||||
const cNodes = computed(() => getNodes())
|
||||
: store.nodes,
|
||||
)
|
||||
|
||||
const type = (node: TNode) => {
|
||||
const nodeType = node.type || 'default'
|
||||
@@ -54,65 +42,23 @@ const type = (node: TNode) => {
|
||||
return type
|
||||
}
|
||||
|
||||
const updateNodeDimensions = (updates: NodeDimensionUpdate[]) => {
|
||||
nodes.value = nodes.value.map((node) => {
|
||||
const update = updates.find((u) => u.id === node.id)
|
||||
if (update) {
|
||||
const dimensions = getDimensions(update.nodeElement)
|
||||
const doUpdate =
|
||||
dimensions.width &&
|
||||
dimensions.height &&
|
||||
(node.__rf.width !== dimensions.width || node.__rf.height !== dimensions.height || update.forceUpdate)
|
||||
|
||||
if (doUpdate) {
|
||||
const handleBounds = getHandleBounds(update.nodeElement, props.transform[2])
|
||||
|
||||
return {
|
||||
...node,
|
||||
__rf: {
|
||||
...node.__rf,
|
||||
...dimensions,
|
||||
handleBounds,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
})
|
||||
}
|
||||
const selected = (nodeId: string) => store.selectedElements?.some(({ id }) => id === nodeId)
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="revue-flow__nodes"
|
||||
:style="{ transform: `translate(${props.transform[0]}px,${props.transform[1]}px) scale(${props.transform[2]})` }"
|
||||
>
|
||||
<template v-for="(node, i) of cNodes" :key="`node-${i}`">
|
||||
<template v-for="(node, i) of getNodes" :key="`node-${i}`">
|
||||
<Node
|
||||
:node="node"
|
||||
:snap-grid="props.snapGrid"
|
||||
:snap-to-grid="props.snapToGrid"
|
||||
:select-nodes-on-drag="props.selectNodesOnDrag"
|
||||
:type="type(node)"
|
||||
:scale="props.transform[2]"
|
||||
@updateNodeDimensions="updateNodeDimensions"
|
||||
>
|
||||
<template #default="{ selected, isConnectable }">
|
||||
<component
|
||||
:is="type(node)"
|
||||
v-bind="{
|
||||
data: node.data,
|
||||
type: node.type,
|
||||
xPos: node.__rf.position.x,
|
||||
yPos: node.__rf.position.y,
|
||||
selected: selected,
|
||||
isConnectable: isConnectable,
|
||||
sourcePosition: node.sourcePosition,
|
||||
targetPosition: node.targetPosition,
|
||||
isDragging: node.__rf.isDragging,
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
</Node>
|
||||
:selected="selected(node.id)"
|
||||
:selectable="node.selectable || store.elementsSelectable"
|
||||
:connectable="node.connectable || store.nodesConnectable"
|
||||
:draggable="node.draggable || store.nodesDraggable"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineComponent, inject, PropType } from 'vue'
|
||||
import Node from '../../components/Nodes/Node'
|
||||
import Node from '../../components/Nodes/NodeDepr'
|
||||
import { getNodesInside } from '../../utils/graph'
|
||||
import { NodeType, RevueFlowStore } from '../../types'
|
||||
|
||||
@@ -18,28 +18,28 @@ export default defineComponent({
|
||||
nodeTypes: {
|
||||
type: Object as PropType<NodeRendererProps['nodeTypes']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
selectNodesOnDrag: {
|
||||
type: Boolean as PropType<NodeRendererProps['selectNodesOnDrag']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
snapToGrid: {
|
||||
type: Boolean as PropType<NodeRendererProps['snapToGrid']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
snapGrid: {
|
||||
type: Array as unknown as PropType<NodeRendererProps['snapGrid']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
onlyRenderVisibleElements: {
|
||||
type: Boolean as PropType<NodeRendererProps['onlyRenderVisibleElements']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
}
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
@@ -53,19 +53,19 @@ export default defineComponent({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: store?.width,
|
||||
height: store?.height
|
||||
height: store?.height,
|
||||
},
|
||||
store.transform,
|
||||
true
|
||||
true,
|
||||
)
|
||||
: store.nodes
|
||||
}
|
||||
|
||||
return () => (
|
||||
<div
|
||||
class="revue-flow__nodes"
|
||||
className="revue-flow__nodes"
|
||||
style={{
|
||||
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`
|
||||
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`,
|
||||
}}
|
||||
>
|
||||
{getNodes().map((node, i) => {
|
||||
@@ -90,5 +90,5 @@ export default defineComponent({
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import DefaultNode from '~/components/Nodes/DefaultNode'
|
||||
import InputNode from '~/components/Nodes/InputNode'
|
||||
import OutputNode from '~/components/Nodes/OutputNode'
|
||||
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
|
||||
import { NodeType } from '~/types'
|
||||
|
||||
export function createNodeTypes(nodeTypes: Record<string, NodeType>): Record<string, NodeType> {
|
||||
|
||||
@@ -2,9 +2,9 @@ import { PropType } from 'vue'
|
||||
import '../../style.css'
|
||||
import '../../theme-default.css'
|
||||
import GraphView from '../GraphView'
|
||||
import DefaultNode from '../../components/Nodes/DefaultNode'
|
||||
import InputNode from '../../components/Nodes/InputNode'
|
||||
import OutputNode from '../../components/Nodes/OutputNode'
|
||||
import DefaultNode from '../../components/Nodes/DefaultNodeDepr'
|
||||
import InputNode from '../../components/Nodes/InputNodeDepr'
|
||||
import OutputNode from '../../components/Nodes/OutputNodeDepr'
|
||||
import { createNodeTypes } from '../NodeRenderer/utils'
|
||||
import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges'
|
||||
import { createEdgeTypes } from '../EdgeRenderer/utils'
|
||||
@@ -16,14 +16,14 @@ import { RevueFlowHooks, useRevueFlow } from '../../hooks/RevueFlowHooks'
|
||||
const defaultNodeTypes = {
|
||||
input: InputNode,
|
||||
default: DefaultNode,
|
||||
output: OutputNode
|
||||
output: OutputNode,
|
||||
}
|
||||
|
||||
const defaultEdgeTypes = {
|
||||
default: BezierEdge,
|
||||
straight: StraightEdge,
|
||||
step: StepEdge,
|
||||
smoothstep: SmoothStepEdge
|
||||
smoothstep: SmoothStepEdge,
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@@ -33,189 +33,189 @@ export default defineComponent({
|
||||
modelValue: {
|
||||
type: Array as PropType<RevueFlowProps['modelValue']>,
|
||||
required: false,
|
||||
default: () => []
|
||||
default: () => [],
|
||||
},
|
||||
nodeTypesId: {
|
||||
type: String as PropType<RevueFlowProps['nodeTypesId']>,
|
||||
required: false,
|
||||
default: '1'
|
||||
default: '1',
|
||||
},
|
||||
edgeTypesId: {
|
||||
type: String as PropType<RevueFlowProps['edgeTypesId']>,
|
||||
required: false,
|
||||
default: '1'
|
||||
default: '1',
|
||||
},
|
||||
nodeTypes: {
|
||||
type: Object as PropType<RevueFlowProps['nodeTypes']>,
|
||||
required: false,
|
||||
default: () => defaultNodeTypes
|
||||
default: () => defaultNodeTypes,
|
||||
},
|
||||
edgeTypes: {
|
||||
type: Object as PropType<RevueFlowProps['edgeTypes']>,
|
||||
required: false,
|
||||
default: () => defaultEdgeTypes
|
||||
default: () => defaultEdgeTypes,
|
||||
},
|
||||
connectionMode: {
|
||||
type: String as PropType<RevueFlowProps['connectionMode']>,
|
||||
required: false,
|
||||
default: ConnectionMode.Strict
|
||||
default: ConnectionMode.Strict,
|
||||
},
|
||||
connectionLineType: {
|
||||
type: String as PropType<RevueFlowProps['connectionLineType']>,
|
||||
required: false,
|
||||
default: ConnectionLineType.Bezier
|
||||
default: ConnectionLineType.Bezier,
|
||||
},
|
||||
connectionLineStyle: {
|
||||
type: Object as PropType<RevueFlowProps['connectionLineStyle']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
connectionLineComponent: {
|
||||
type: Object as PropType<RevueFlowProps['connectionLineComponent']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
selectionKeyCode: {
|
||||
type: [Number, String] as PropType<RevueFlowProps['selectionKeyCode']>,
|
||||
required: false,
|
||||
default: 'Shift'
|
||||
default: 'Shift',
|
||||
},
|
||||
multiSelectionKeyCode: {
|
||||
type: [Number, String] as PropType<RevueFlowProps['multiSelectionKeyCode']>,
|
||||
required: false,
|
||||
default: 'Meta'
|
||||
default: 'Meta',
|
||||
},
|
||||
zoomActivationKeyCode: {
|
||||
type: [Number, String] as PropType<RevueFlowProps['zoomActivationKeyCode']>,
|
||||
required: false,
|
||||
default: 'Meta'
|
||||
default: 'Meta',
|
||||
},
|
||||
deleteKeyCode: {
|
||||
type: [Number, String] as PropType<RevueFlowProps['deleteKeyCode']>,
|
||||
required: false,
|
||||
default: 'Backspace'
|
||||
default: 'Backspace',
|
||||
},
|
||||
snapToGrid: {
|
||||
type: Boolean as PropType<RevueFlowProps['snapToGrid']>,
|
||||
required: false,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
snapGrid: {
|
||||
type: Array as unknown as PropType<RevueFlowProps['snapGrid']>,
|
||||
required: false,
|
||||
default: () => [15, 15]
|
||||
default: () => [15, 15],
|
||||
},
|
||||
onlyRenderVisibleElements: {
|
||||
type: Boolean as PropType<RevueFlowProps['onlyRenderVisibleElements']>,
|
||||
required: false,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
nodesDraggable: {
|
||||
type: Boolean as PropType<RevueFlowProps['nodesDraggable']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
nodesConnectable: {
|
||||
type: Boolean as PropType<RevueFlowProps['nodesConnectable']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
elementsSelectable: {
|
||||
type: Boolean as PropType<RevueFlowProps['elementsSelectable']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
selectNodesOnDrag: {
|
||||
type: Boolean as PropType<RevueFlowProps['selectNodesOnDrag']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
minZoom: {
|
||||
type: Number as PropType<RevueFlowProps['minZoom']>,
|
||||
required: false,
|
||||
default: 0.5
|
||||
default: 0.5,
|
||||
},
|
||||
maxZoom: {
|
||||
type: Number as PropType<RevueFlowProps['maxZoom']>,
|
||||
required: false,
|
||||
default: 2
|
||||
default: 2,
|
||||
},
|
||||
defaultZoom: {
|
||||
type: Number as PropType<RevueFlowProps['defaultZoom']>,
|
||||
required: false,
|
||||
default: 1
|
||||
default: 1,
|
||||
},
|
||||
defaultPosition: {
|
||||
type: Array as unknown as PropType<RevueFlowProps['defaultPosition']>,
|
||||
required: false,
|
||||
default: () => [0, 0]
|
||||
default: () => [0, 0],
|
||||
},
|
||||
translateExtent: {
|
||||
type: Array as unknown as PropType<RevueFlowProps['translateExtent']>,
|
||||
required: false,
|
||||
default: () => [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY]
|
||||
]
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
},
|
||||
nodeExtent: {
|
||||
type: Array as unknown as PropType<RevueFlowProps['nodeExtent']>,
|
||||
required: false,
|
||||
default: () => [
|
||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY]
|
||||
]
|
||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||
],
|
||||
},
|
||||
arrowHeadColor: {
|
||||
type: String as PropType<RevueFlowProps['arrowHeadColor']>,
|
||||
required: false,
|
||||
default: '#b1b1b7'
|
||||
default: '#b1b1b7',
|
||||
},
|
||||
markerEndId: {
|
||||
type: String as PropType<RevueFlowProps['markerEndId']>,
|
||||
required: false,
|
||||
default: undefined
|
||||
default: undefined,
|
||||
},
|
||||
zoomOnScroll: {
|
||||
type: Boolean as PropType<RevueFlowProps['zoomOnScroll']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
zoomOnPinch: {
|
||||
type: Boolean as PropType<RevueFlowProps['zoomOnPinch']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
panOnScroll: {
|
||||
type: Boolean as PropType<RevueFlowProps['panOnScroll']>,
|
||||
required: false,
|
||||
default: false
|
||||
default: false,
|
||||
},
|
||||
panOnScrollSpeed: {
|
||||
type: Number as PropType<RevueFlowProps['panOnScrollSpeed']>,
|
||||
required: false,
|
||||
default: 0.5
|
||||
default: 0.5,
|
||||
},
|
||||
panOnScrollMode: {
|
||||
type: String as PropType<RevueFlowProps['panOnScrollMode']>,
|
||||
required: false,
|
||||
default: PanOnScrollMode.Free
|
||||
default: PanOnScrollMode.Free,
|
||||
},
|
||||
zoomOnDoubleClick: {
|
||||
type: Boolean as PropType<RevueFlowProps['zoomOnDoubleClick']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
paneMoveable: {
|
||||
type: Boolean as PropType<RevueFlowProps['paneMoveable']>,
|
||||
required: false,
|
||||
default: true
|
||||
default: true,
|
||||
},
|
||||
edgeUpdaterRadius: {
|
||||
type: Number as PropType<RevueFlowProps['edgeUpdaterRadius']>,
|
||||
required: false,
|
||||
default: 10
|
||||
}
|
||||
default: 10,
|
||||
},
|
||||
},
|
||||
emits: Object.keys(useRevueFlow()),
|
||||
setup(props, { emit, slots }) {
|
||||
@@ -240,7 +240,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
return () => (
|
||||
<div class="revue-flow">
|
||||
<div className="revue-flow">
|
||||
<GraphView
|
||||
nodeTypes={createNodeTypes({ ...defaultNodeTypes, ...props.nodeTypes })}
|
||||
edgeTypes={createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })}
|
||||
@@ -279,5 +279,5 @@ export default defineComponent({
|
||||
{slots.default ? slots.default() : ''}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import { inject } from 'vue'
|
||||
import { RevueFlowHooks } from '~/hooks/RevueFlowHooks'
|
||||
import useKeyPress from '~/hooks/useKeyPress'
|
||||
import { KeyCode } from '~/types'
|
||||
import { KeyCode, RevueFlowStore } from '~/types'
|
||||
import useGlobalKeyHandler from '~/hooks/useGlobalKeyHandler'
|
||||
import NodesSelection from '~/components/NodesSelection/NodesSelection.vue'
|
||||
import UserSelection from '~/components/UserSelection/UserSelection.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
selectionKeyCode: KeyCode
|
||||
deleteKeyCode: KeyCode
|
||||
multiSelectionKeyCode: KeyCode
|
||||
}>(),
|
||||
{
|
||||
selectionKeyCode: 'Shift',
|
||||
deleteKeyCode: 'Backspace',
|
||||
multiSelectionKeyCode: 'Meta',
|
||||
},
|
||||
)
|
||||
interface SelectionPaneProps {
|
||||
selectionKeyCode?: KeyCode
|
||||
deleteKeyCode?: KeyCode
|
||||
multiSelectionKeyCode?: KeyCode
|
||||
}
|
||||
const props = withDefaults(defineProps<SelectionPaneProps>(), {
|
||||
selectionKeyCode: 'Shift',
|
||||
deleteKeyCode: 'Backspace',
|
||||
multiSelectionKeyCode: 'Meta',
|
||||
})
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const hooks = inject<RevueFlowHooks>('hooks')!
|
||||
const keyPressed = useKeyPress(props.selectionKeyCode)
|
||||
const nodeSelectionActive = ref(false)
|
||||
const selectedElements = ref([])
|
||||
|
||||
const onClick = (event: MouseEvent) => {
|
||||
hooks.paneClick.trigger(event)
|
||||
nodeSelectionActive.value = false
|
||||
selectedElements.value = []
|
||||
store.unsetNodesSelection()
|
||||
store.resetSelectedElements()
|
||||
}
|
||||
|
||||
const onContextMenu = (event: MouseEvent) => hooks.paneContextMenu.trigger(event)
|
||||
@@ -37,10 +35,13 @@ useGlobalKeyHandler({
|
||||
deleteKeyCode: props.deleteKeyCode,
|
||||
multiSelectionKeyCode: props.multiSelectionKeyCode,
|
||||
})
|
||||
|
||||
const userSelectionVisible = computed(() => keyPressed.value && (store.selectionActive || store.elementsSelectable))
|
||||
const nodesSelectionVisible = computed(() => store.nodesSelectionActive)
|
||||
</script>
|
||||
<template>
|
||||
<slot></slot>
|
||||
<div v-if="keyPressed" id="user-selection">User Selection</div>
|
||||
<div v-if="nodeSelectionActive" id="nodes-selection">Nodes Selection</div>
|
||||
<UserSelection v-if="userSelectionVisible" id="user-selection" />
|
||||
<NodesSelection v-if="nodesSelectionVisible" id="nodes-selection" />
|
||||
<div class="revue-flow__pane" @click="onClick" @contextmenu="onContextMenu" @wheel="onWheel" />
|
||||
</template>
|
||||
|
||||
+35
-30
@@ -1,39 +1,28 @@
|
||||
<script lang="ts" setup>
|
||||
import { RevueFlowOptions, ConnectionLineType, ConnectionMode, Elements, PanOnScrollMode } from '~/types'
|
||||
import { KeyCode, PanOnScrollMode, RevueFlowStore } from '~/types'
|
||||
import useZoom from '~/composables/useZoom'
|
||||
import useResizeHandler from '~/hooks/useResizeHandler'
|
||||
import useZoomPanHelper from '~/hooks/useZoomPanHelper'
|
||||
|
||||
interface RevueFlowProps extends RevueFlowOptions {
|
||||
modelValue: Elements
|
||||
interface ZoomPaneProps {
|
||||
selectionKeyCode?: KeyCode
|
||||
zoomActivationKeyCode?: KeyCode
|
||||
paneMoveable?: boolean
|
||||
defaultZoom?: number
|
||||
defaultPosition?: [number, number]
|
||||
zoomOnScroll?: boolean
|
||||
zoomOnPinch?: boolean
|
||||
panOnScroll?: boolean
|
||||
panOnScrollSpeed?: number
|
||||
panOnScrollMode?: PanOnScrollMode
|
||||
zoomOnDoubleClick?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<RevueFlowProps>(), {
|
||||
modelValue: () => [] as Elements,
|
||||
connectionMode: ConnectionMode.Strict,
|
||||
connectionLineType: ConnectionLineType.Bezier,
|
||||
const props = withDefaults(defineProps<ZoomPaneProps>(), {
|
||||
selectionKeyCode: 'Shift',
|
||||
multiSelectionKeyCode: 'Meta',
|
||||
zoomActivationKeyCode: 'Meta',
|
||||
deleteKeyCode: 'Backspace',
|
||||
snapToGrid: false,
|
||||
snapGrid: () => [15, 15],
|
||||
onlyRenderVisibleElements: false,
|
||||
nodesConnectable: true,
|
||||
elementsSelectable: true,
|
||||
selectNodesOnDrag: true,
|
||||
minZoom: 0.5,
|
||||
maxZoom: 2,
|
||||
defaultZoom: 1,
|
||||
defaultPosition: () => [0, 0],
|
||||
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],
|
||||
],
|
||||
arrowHeadColor: '#b1b1b7',
|
||||
zoomOnScroll: true,
|
||||
zoomOnPinch: true,
|
||||
zoomOnDoubleClick: true,
|
||||
@@ -41,11 +30,27 @@ const props = withDefaults(defineProps<RevueFlowProps>(), {
|
||||
panOnScrollSpeed: 0.5,
|
||||
panOnScrollMode: PanOnScrollMode.Free,
|
||||
paneMoveable: true,
|
||||
edgeUpdaterRadius: 10,
|
||||
})
|
||||
const zoomPane = templateRef<HTMLDivElement>('zoom-pane', null)
|
||||
const transform = useZoom(zoomPane, props)
|
||||
const dimensions = useResizeHandler(zoomPane)
|
||||
const store = inject<RevueFlowStore>('store')!
|
||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
||||
const { transform, d3Selection, d3Zoom } = useZoom(zoomPaneEl, props, (initD3ZoomPayload) => store.initD3Zoom(initD3ZoomPayload))
|
||||
|
||||
watch(transform, (val) => (store.transform = val), { flush: 'post' })
|
||||
const dimensions = useResizeHandler(zoomPaneEl)
|
||||
watch(dimensions, (val) => (store.dimensions = val), { flush: 'post' })
|
||||
|
||||
const getZoomPanHelper = reactify(useZoomPanHelper)
|
||||
const zoomPanHelper = getZoomPanHelper(
|
||||
d3Zoom,
|
||||
d3Selection,
|
||||
store.nodes,
|
||||
transform,
|
||||
dimensions,
|
||||
store.minZoom,
|
||||
store.maxZoom,
|
||||
store.snapToGrid,
|
||||
store.snapGrid,
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
|
||||
|
||||
Reference in New Issue
Block a user