docs: update nodes / edges pages

This commit is contained in:
braks
2024-06-13 22:27:07 +02:00
parent d51203c465
commit 76fe779f34
2 changed files with 363 additions and 274 deletions

View File

@@ -73,6 +73,10 @@ const straightEdge = ref([
target: '2', target: '2',
}, },
]); ]);
function logEvent(name, data) {
console.log(name, data)
}
</script> </script>
# Introduction to Edges # Introduction to Edges
@@ -86,8 +90,7 @@ For the full list of options available for an edge, check out the [Edge Type](/t
## Adding Edges to the Graph ## Adding Edges to the Graph
Edges are generally created by adding them to the `mode-value` (using `v-model`) or to the `edges` prop of the Vue Flow component. Edges are rendered by passing them to the `edges` prop (or the deprecated `v-model` prop) of the Vue Flow component.
This can be done dynamically at any point in your component's lifecycle.
:::code-group :::code-group
@@ -97,30 +100,30 @@ This can be done dynamically at any point in your component's lifecycle.
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
label: 'Node 2', data: { label: 'Node 2', },
} }
]); ]);
onMounted(() => { const edges = ref([
elements.value.push({ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
}) }
}) ]);
</script> </script>
<template> <template>
<VueFlow v-model="elements"/> <VueFlow :nodes="nodes" :edges="edges" />
</template> </template>
``` ```
@@ -128,42 +131,42 @@ onMounted(() => {
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import type { Elements } from '@vue-flow/core' import type { Node, Edge } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
const elements = ref<Elements>([ const nodes = ref<Node[]>([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
label: 'Node 2', data: { label: 'Node 2', },
} }
]); ]);
onMounted(() => { const edges = ref<Edge[]>([
elements.value.push({ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
}) }
}) ]);
</script> </script>
<template> <template>
<VueFlow v-model="elements"/> <VueFlow :nodes="nodes" :edges="edges" />
</template> </template>
``` ```
::: :::
If you are working with more complex graphs that necessitate extensive state access, the `useVueFlow` composable should If you are working with more complex graphs or simply require access to the internal state,
be employed. the [useVueFlow](/typedocs/functions/useVueFlow) composable will come in handy.
The [`addEdges`](/typedocs/interfaces/Actions#addEdges) action is available
through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to add edges straight to the state. The [`addEdges`](/typedocs/interfaces/Actions#addEdges) action is available through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to add edges straight to the state.
What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a
Sidebar or Toolbar. Sidebar or Toolbar.
@@ -176,31 +179,28 @@ const initialNodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
label: 'Node 2', data: { label: 'Node 2', },
} }
]) ])
const { addEdges } = useVueFlow() const { addEdges } = useVueFlow()
onMounted(() => { addEdges([
// add an edge after mount {
addEdges([ source: '1',
{ target: '2',
source: '1',
target: '2', // if a node has multiple handles of the same type,
// you should specify which handle to use by id
// if a node has multiple handles of the same type, sourceHandle: null,
// you should specify which handle to use by id targetHandle: null,
sourceHandle: null, }
targetHandle: null, ])
}
])
})
</script> </script>
<template> <template>
@@ -213,81 +213,118 @@ onMounted(() => {
Similar to adding edges, edges can be removed from the graph by removing them from the `mode-value` (using `v-model`) or from the `edges` prop of the Vue Flow component. Similar to adding edges, edges can be removed from the graph by removing them from the `mode-value` (using `v-model`) or from the `edges` prop of the Vue Flow component.
```vue ```vue
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow, Panel } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
label: 'Node 2', data: { label: 'Node 2', },
}, },
]);
const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
} }
]); ]);
onMounted(() => { function removeEdge(id) {
elements.value.splice(2, 1) edges.value = edges.value.filter((edge) => edge.id !== id)
}) }
</script> </script>
<template> <template>
<VueFlow v-model="elements"/> <VueFlow :nodes="nodes" :edges="edges">
<Panel>
<button @click="removeEdge('e1->2')">Remove Edge</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
When working with complex graphs with extensive state access, you should use the useVueFlow composable. The [`removeEdges`](/typedocs/interfaces/Actions#removeEdges) action is available through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to remove edges straight from the state.
The [`removeEdges`](/typedocs/interfaces/Actions#removeEdges) action is available through [useVueFlow](/typedocs/functions/useVueFlow),
allowing you to remove edges straight from the state.
What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a You can also use this action outside the component rendering the graph, like in a Sidebar or Toolbar.
Sidebar, Toolbar or the Edge itself.
```vue ```vue
<script setup> <script setup>
import { ref, onMounted } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core' import { VueFlow, useVueFlow } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
label: 'Node 2', data: { label: 'Node 2', },
}, },
{ {
id: 'e1-2', id: '3',
position: { x: 250, y: 50 },
data: { label: 'Node 3', },
},
{
id: '4',
position: { x: 250, y: 250 },
data: { label: 'Node 4', },
},
])
const edges = ref([
{
id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
} },
{
id: 'e1->3',
source: '1',
target: '3',
},
{
id: 'e2->3',
source: '2',
target: '3',
},
{
id: 'e2->4',
source: '2',
target: '4',
},
]) ])
const { removeEdges } = useVueFlow() const { removeEdges } = useVueFlow()
onMounted(() => { function removeOneEdge() {
// remove an edge after mount removeEdges('e1->2')
removeEdges('e1-2') }
// or remove multiple edges function removeMultipleEdges() {
removeEdges(['e1-2', 'e2-3']) removeEdges(['e1->3', 'e2->3'])
}) }
</script> </script>
<template> <template>
<VueFlow v-model="elements" /> <VueFlow :nodes="nodes" :edges="edges">
<Panel>
<button @click="removeOneEdge">Remove Edge 1</button>
<button @click="removeMultipleEdges">Remove Edges 2 and 3</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
@@ -300,13 +337,34 @@ There are multiple ways of achieving this, here are some examples:
::: code-group ::: code-group
```ts [useVueFlow]
import { useVueFlow } from '@vue-flow/core'
const instance = useVueFlow()
// use the `updateEdgeData` method to update the data of an edge
instance.updateEdgeData(edgeId, { hello: 'mona' })
// find the edge in the state by its id
const edge = instance.findEdge(edgeId)
edge.data = {
...edge.data,
hello: 'world',
}
// you can also mutate properties like `selectable` or `animated`
edge.selectable = !edge.selectable
edge.animated = !edge.animated
```
```vue [useEdge] ```vue [useEdge]
<!-- CustomEdge.vue --> <!-- CustomEdge.vue -->
<script setup> <script setup>
import { useEdge } from '@vue-flow/core' import { useEdge } from '@vue-flow/core'
// `useEdge` returns us the edge object straight from the state // `useEdge` returns us the edge object straight from the state
// since the node obj is reactive, we can mutate it to update our edges' data // since the edge obj is reactive, we can mutate it to update our edges' data
const { edge } = useEdge() const { edge } = useEdge()
function onSomeEvent() { function onSomeEvent() {
@@ -322,51 +380,36 @@ function onSomeEvent() {
</script> </script>
``` ```
```ts [useVueFlow]
import { useVueFlow } from '@vue-flow/core'
const instance = useVueFlow()
// find the node in the state by its id
const edge = instance.findEdge(edgeId)
edge.data = {
...edge.data,
hello: 'world',
}
// you can also mutate properties like `selectable` or `animated`
edge.selectable = !edge.selectable
edge.animated = !edge.animated
```
```vue [v-model] ```vue [v-model]
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { data: {
label: 'Node 1',
hello: 'world', hello: 'world',
} },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
])
const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
}, },
]) ])
function onSomeEvent(edgeId) { function onSomeEvent(edgeId) {
const edge = elements.value.find((edge) => edge.id === edgeId) const edge = edges.value.find((edge) => edge.id === edgeId)
edge.data = { edge.data = {
...elements.value[0].data, ...elements.value[0].data,
hello: 'world', hello: 'world',
@@ -447,14 +490,14 @@ import SpecialEdge from './SpecialEdge.vue'
export const edges = ref([ export const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
// this will create the edge-type `custom` // this will create the edge-type `custom`
type: 'custom', type: 'custom',
}, },
{ {
id: 'e1-3', id: 'e1->3',
source: '1', source: '1',
target: '3', target: '3',
// this will create the edge-type `special` // this will create the edge-type `special`
@@ -465,23 +508,23 @@ export const edges = ref([
const nodes = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
{ {
id: '3', id: '3',
label: 'Node 3',
position: { x: 250, y: 50 }, position: { x: 250, y: 50 },
data: { label: 'Node 3', },
}, },
{ {
id: '4', id: '4',
label: 'Node 4',
position: { x: 250, y: 250 }, position: { x: 250, y: 250 },
data: { label: 'Node 4', },
}, },
]) ])
</script> </script>
@@ -576,23 +619,23 @@ export const edges = ref<CustomEdge[]>([
const nodes = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
{ {
id: '3', id: '3',
label: 'Node 3',
position: { x: 250, y: 50 }, position: { x: 250, y: 50 },
data: { label: 'Node 3', },
}, },
{ {
id: '4', id: '4',
label: 'Node 4',
position: { x: 250, y: 250 }, position: { x: 250, y: 250 },
data: { label: 'Node 4', },
}, },
]) ])
</script> </script>
@@ -656,32 +699,37 @@ One of the easiest ways to define custom edges is, by passing them as template s
Dynamic resolution to slot-names is done for your user-defined edge-types, Dynamic resolution to slot-names is done for your user-defined edge-types,
meaning a edge with the type `custom` is expected to have a slot named `#edge-custom`. meaning a edge with the type `custom` is expected to have a slot named `#edge-custom`.
```vue{18,26} ```vue
<script setup> <script setup>
import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
import CustomEdge from './CustomEdge.vue' import CustomEdge from './CustomEdge.vue'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
])
const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
type: 'custom', type: 'custom',
source: '1', source: '1',
target: '2', target: '2',
}, },
]) ])
</script> </script>
<template> <template>
<VueFlow v-model="elements"> <VueFlow :nodes="nodes" :edges="edges">
<template #edge-custom="props"> <template #edge-custom="props">
<CustomEdge v-bind="props" /> <CustomEdge v-bind="props" />
</template> </template>
@@ -697,7 +745,7 @@ Alternatively, edge-types can also be defined by passing an object as a prop to
Take precaution to mark your components as raw (utilizing the marked function from the Vue library) to prevent their conversion into reactive objects. Otherwise, Vue will display a warning on the console. Take precaution to mark your components as raw (utilizing the marked function from the Vue library) to prevent their conversion into reactive objects. Otherwise, Vue will display a warning on the console.
::: :::
```vue{5-7,28} ```vue
<script setup> <script setup>
import { markRaw } from 'vue' import { markRaw } from 'vue'
import CustomEdge from './CustomEdge.vue' import CustomEdge from './CustomEdge.vue'
@@ -706,17 +754,22 @@ const edgeTypes = {
custom: markRaw(CustomEdge), custom: markRaw(CustomEdge),
} }
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '1', id: '2',
label: 'Node 1', position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
{ ])
id: 'e1-2',
const edges = ref([
{
id: 'e1->2',
type: 'custom', type: 'custom',
source: '1', source: '1',
target: '2', target: '2',
@@ -724,9 +777,7 @@ const elements = ref([
]) ])
</script> </script>
<template> <template>
<div style="height: 300px"> <VueFlow :nodes="nodes" :edges="edges" :edgeTypes="edgeTypes" />
<VueFlow v-model="elements" :edge-types="edgeTypes" />
</div>
</template> </template>
``` ```
@@ -784,19 +835,22 @@ const {
onEdgeUpdateEnd, onEdgeUpdateEnd,
} = useVueFlow() } = useVueFlow()
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
])
const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
}, },
@@ -819,7 +873,7 @@ onEdgeContextMenu((event, edge) => {
</script> </script>
<template> <template>
<VueFlow v-model="elements" /> <VueFlow :nodes="nodes" :edges="edges" />
</template> </template>
``` ```
@@ -828,38 +882,45 @@ onEdgeContextMenu((event, edge) => {
import { ref } from 'vue' import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}, },
{ {
id: '2', id: '2',
label: 'Node 2',
position: { x: 50, y: 250 }, position: { x: 50, y: 250 },
data: { label: 'Node 2', },
}, },
])
const edges = ref([
{ {
id: 'e1-2', id: 'e1->2',
source: '1', source: '1',
target: '2', target: '2',
}, },
]) ])
function logEvent(eventName, data) {
console.log(eventName, data)
}
</script> </script>
<template> <template>
<!-- bind listeners to the event handlers -->
<VueFlow <VueFlow
v-model="elements" :nodes="nodes"
@edge-click="console.log('edge clicked', $event)" :edges="edges"
@edge-double-click="console.log('edge double clicked', $event)" @edge-click="logEvent('edge clicked', $event)"
@edge-context-menu="console.log('edge context menu', $event)" @edge-double-click="logEvent('edge double clicked', $event)"
@edge-mouse-enter="console.log('edge mouse enter', $event)" @edge-context-menu="logEvent('edge context menu', $event)"
@edge-mouse-leave="console.log('edge mouse leave', $event)" @edge-mouse-enter="logEvent('edge mouse enter', $event)"
@edge-mouse-move="console.log('edge mouse move', $event)" @edge-mouse-leave="logEvent('edge mouse leave', $event)"
@edge-update-start="console.log('edge update start', $event)" @edge-mouse-move="logEvent('edge mouse move', $event)"
@edge-update="console.log('edge update', $event)" @edge-update-start="logEvent('edge update start', $event)"
@edge-update-end="console.log('edge update end', $event)" @edge-update="logEvent('edge update', $event)"
@edge-update-end="logEvent('edge update end', $event)"
/> />
</template> </template>
``` ```
@@ -869,19 +930,20 @@ const elements = ref([
<div class="mt-4 bg-[var(--vp-code-block-bg)] rounded-lg h-50"> <div class="mt-4 bg-[var(--vp-code-block-bg)] rounded-lg h-50">
<VueFlow <VueFlow
v-model="bezierEdge" v-model="bezierEdge"
@edge-click="console.log('edge clicked', $event)" @edge-click="logEvent('edge clicked', $event)"
@edge-double-click="console.log('edge double clicked', $event)" @edge-double-click="logEvent('edge double clicked', $event)"
@edge-context-menu="console.log('edge context menu', $event)" @edge-context-menu="logEvent('edge context menu', $event)"
@edge-mouse-enter="console.log('edge mouse enter', $event)" @edge-mouse-enter="logEvent('edge mouse enter', $event)"
@edge-mouse-leave="console.log('edge mouse leave', $event)" @edge-mouse-leave="logEvent('edge mouse leave', $event)"
@edge-mouse-move="console.log('edge mouse move', $event)" @edge-mouse-move="logEvent('edge mouse move', $event)"
@edge-update-start="console.log('edge update start', $event)" @edge-update-start="logEvent('edge update start', $event)"
@edge-update="console.log('edge update', $event)" @edge-update="logEvent('edge update', $event)"
@edge-update-end="console.log('edge update end', $event)" @edge-update-end="logEvent('edge update end', $event)"
> >
<Panel position="top-center"> <Panel position="top-center">
<p class="text-sm">Interact to see events in browser console</p> <p class="text-sm">Interact to see events in browser console</p>
</Panel> </Panel>
<Background class="rounded-lg" /> <Background class="rounded-lg" />
</VueFlow> </VueFlow>
</div> </div>

View File

@@ -44,6 +44,10 @@ const outputNode = ref([
position: { x: 50, y: 75 }, position: { x: 50, y: 75 },
} }
]); ]);
function logEvent(name, data) {
console.log(name, data)
}
</script> </script>
# Introduction to Nodes # Introduction to Nodes
@@ -67,27 +71,33 @@ This can be done dynamically at any point in your component's lifecycle.
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow, Panel } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
} }
]); ]);
onMounted(() => { function addNode() {
elements.value.push({ const id = Date.now().toString()
id: '2',
label: 'Node 2', nodes.value.push({
id,
position: { x: 150, y: 50 }, position: { x: 150, y: 50 },
data: { label: `Node ${id}`, },
}) })
}) }
</script> </script>
<template> <template>
<VueFlow v-model="elements"/> <VueFlow :nodes="nodes">
<Panel>
<button type="button" @click="addNode">Add a node</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
@@ -95,37 +105,43 @@ onMounted(() => {
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import type { Elements } from '@vue-flow/core' import type { Node } from '@vue-flow/core'
import { VueFlow } from '@vue-flow/core' import { VueFlow, Panel } from '@vue-flow/core'
const elements = ref<Elements>([ const nodes = ref<Node[]>([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1', },
} }
]); ]);
onMounted(() => { function addNode() {
elements.value.push({ const id = Date.now().toString()
id: '2',
label: 'Node 2', nodes.value.push({
position: { x: 150, y: 50 }, id,
}) position: { x: 150, y: 50 },
}) data: { label: `Node ${id}`, },
})
}
</script> </script>
<template> <template>
<VueFlow v-model="elements"/> <VueFlow :nodes="nodes">
<Panel>
<button type="button" @click="addNode">Add a node</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
::: :::
If you are working with more complex graphs that necessitate extensive state access, the `useVueFlow` composable should If you are working with more complex graphs or simply require access to the internal state,
be employed. the [useVueFlow](/typedocs/functions/useVueFlow) composable will come in handy.
The [`addNodes`](/typedocs/interfaces/Actions#addnodes) action is available
through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to add nodes straight to the state. The [`addNodes`](/typedocs/interfaces/Actions#addnodes) action is available through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to add nodes straight to the state.
What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a
Sidebar or Toolbar. Sidebar or Toolbar.
@@ -133,7 +149,6 @@ Sidebar or Toolbar.
::: code-group ::: code-group
```vue [<LogosJavascript />] ```vue [<LogosJavascript />]
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { Panel, VueFlow, useVueFlow } from '@vue-flow/core' import { Panel, VueFlow, useVueFlow } from '@vue-flow/core'
@@ -142,7 +157,7 @@ const initialNodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1' },
} }
]) ])
const { addNodes } = useVueFlow() const { addNodes } = useVueFlow()
@@ -186,8 +201,7 @@ const initialNodes = ref<Node[]>([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1' },
data: {},
} }
]) ])
const { addNodes } = useVueFlow() const { addNodes } = useVueFlow()
@@ -231,79 +245,78 @@ function onAddNodes() {
Similar to adding nodes, nodes can be removed from the graph by removing them from the `mode-value` (using `v-model`) or from the `nodes` prop of the Vue Flow component. Similar to adding nodes, nodes can be removed from the graph by removing them from the `mode-value` (using `v-model`) or from the `nodes` prop of the Vue Flow component.
```vue ```vue
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { VueFlow, Panel } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1' },
}, },
{ {
id: '2', id: '2',
position: { x: 150, y: 50 }, position: { x: 150, y: 50 },
label: 'Node 2', data: { label: 'Node 2' },
} }
]) ])
function onRemoveNode() { function removeNode(id) {
elements.value.pop() nodes.value = nodes.value.filter((node) => node.id !== id)
} }
</script> </script>
<template> <template>
<VueFlow v-model="elements" /> <VueFlow :nodes="nodes">
<Panel>
<button type="button" @click="onRemoveNode">Remove a node</button> <button type="button" @click="removeNode('1')">Remove Node 1</button>
<button type="button" @click="removeNode('2')">Remove Node 2</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
When working with complex graphs with extensive state access, you should use the useVueFlow composable. The [`removeNodes`](/typedocs/interfaces/Actions#removeNodes) action is available through [useVueFlow](/typedocs/functions/useVueFlow), allowing you to remove nodes straight from the state.
The [`removeNodes`](/typedocs/interfaces/Actions#removeNodes) action is available through [useVueFlow](/typedocs/functions/useVueFlow),
allowing you to remove nodes straight from the state.
What's more, this action isn't limited to the component rendering the graph; it can be utilized elsewhere, like in a You can also use this action outside the component rendering the graph, like in a Sidebar or Toolbar.
Sidebar, Toolbar or the Edge itself.
```vue ```vue
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core' import { VueFlow, Panel, useVueFlow } from '@vue-flow/core'
const initialNodes = ref([ const initialNodes = ref([
{ {
id: '1', id: '1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
label: 'Node 1', data: { label: 'Node 1' },
}, },
{ {
id: '2', id: '2',
position: { x: 150, y: 50 }, position: { x: 150, y: 50 },
label: 'Node 2', data: { label: 'Node 2' },
} }
]) ])
const { removeNodes } = useVueFlow() const { removeNodes } = useVueFlow()
// remove a single node from the graph function removeOneNode() {
function onRemoveNode() {
removeNodes('1') removeNodes('1')
} }
// remove multiple nodes from the graph function removeMultipleNodes() {
function onRemoveNodes() {
removeNodes(['1', '2']) removeNodes(['1', '2'])
} }
</script> </script>
<template> <template>
<VueFlow :nodes="initialNodes" /> <VueFlow :nodes="initialNodes">
<Panel>
<button type="button" @click="onRemoveNode">Remove a node</button> <button type="button" @click="removeOneNode">Remove Node 1</button>
<button type="button" @click="onRemoveNodes">Remove multiple nodes</button> <button type="button" @click="removeMultipleNodes">Remove Node 1 and 2</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
@@ -316,6 +329,30 @@ There are multiple ways of achieving this, here are some examples:
::: code-group ::: code-group
```ts [useVueFlow]
import { useVueFlow } from '@vue-flow/core'
const instance = useVueFlow()
// use the `updateNodeData` method to update the data of an edge
instance.updateNodeData(edgeId, { hello: 'mona' })
// find the node in the state by its id
const node = instance.findNode(nodeId)
node.data = {
...node.data,
hello: 'world',
}
// you can also mutate properties like `selectable` or `draggable`
node.selectable = false
node.draggable = false
// or use `updateNode` to update the node directly
instance.updateNode(nodeId, { selectable: false, draggable: false })
```
```vue [useNode] ```vue [useNode]
<!-- CustomNode.vue --> <!-- CustomNode.vue -->
<script setup> <script setup>
@@ -338,44 +375,26 @@ function onSomeEvent() {
</script> </script>
``` ```
```ts [useVueFlow]
import { useVueFlow } from '@vue-flow/core'
const instance = useVueFlow()
// find the node in the state by its id
const node = instance.findNode(nodeId)
node.data = {
...node.data,
hello: 'world',
}
// you can also mutate properties like `selectable` or `draggable`
node.selectable = false
node.draggable = false
```
```vue [v-model] ```vue [v-model]
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
data: { data: {
label: 'Node 1',
hello: 'world', hello: 'world',
} }
}, },
]) ])
function onSomeEvent(nodeId) { function onSomeEvent(nodeId) {
const node = elements.value.find((node) => node.id === nodeId) const node = nodes.value.find((node) => node.id === nodeId)
node.data = { node.data = {
...elements.value[0].data, ...nodes.value[0].data,
hello: 'world', hello: 'world',
} }
@@ -386,7 +405,11 @@ function onSomeEvent(nodeId) {
</script> </script>
<template> <template>
<VueFlow v-model="elements" /> <VueFlow :nodes="nodes">
<Panel>
<button type="button" @click="onSomeEvent('1')">Update Node 1</button>
</Panel>
</VueFlow>
</template> </template>
``` ```
@@ -410,10 +433,10 @@ import { Position } from '@vue-flow/core'
const nodes = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Default Node',
type: 'default', // You can omit this as it's the fallback type type: 'default', // You can omit this as it's the fallback type
targetPosition: Position.Top, // or Bottom, Left, Right, targetPosition: Position.Top, // or Bottom, Left, Right,
sourcePosition: Position.Bottom, // or Top, Left, Right, sourcePosition: Position.Bottom, // or Top, Left, Right,
data: { label: 'Default Node' },
} }
]) ])
``` ```
@@ -436,9 +459,9 @@ import { Position } from '@vue-flow/core'
const nodes = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Input Node',
type: 'input', type: 'input',
sourcePosition: Position.Bottom, // or Top, Left, Right, sourcePosition: Position.Bottom, // or Top, Left, Right,
data: { label: 'Input Node' },
} }
]) ])
``` ```
@@ -461,9 +484,9 @@ import { Position } from '@vue-flow/core'
const nodes = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Output Node',
type: 'output', type: 'output',
targetPosition: Position.Top, // or Bottom, Left, Right, targetPosition: Position.Top, // or Bottom, Left, Right,
data: { label: 'Output Node' },
} }
]) ])
``` ```
@@ -482,7 +505,7 @@ Node-types are determined from your nodes' definitions.
::: code-group ::: code-group
```vue{11-12,18-19} [App.vue <LogosJavascript />] ```vue [App.vue <LogosJavascript />]
<script setup> <script setup>
import { ref } from 'vue' import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
@@ -493,14 +516,14 @@ import SpecialNode from './SpecialNode.vue'
export const nodes = ref([ export const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
// this will create the node-type `custom` // this will create the node-type `custom`
type: 'custom', type: 'custom',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
}, },
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
// this will create the node-type `special` // this will create the node-type `special`
type: 'special', type: 'special',
position: { x: 150, y: 50 }, position: { x: 150, y: 50 },
@@ -523,7 +546,7 @@ export const nodes = ref([
```vue [CustomNode.vue <LogosJavascript />] ```vue [CustomNode.vue <LogosJavascript />]
<script setup> <script setup>
import { Position } from '@vue-flow/core' import { Position, Handle } from '@vue-flow/core'
// props were passed from the slot using `v-bind="customNodeProps"` // props were passed from the slot using `v-bind="customNodeProps"`
const props = defineProps(['label']) const props = defineProps(['label'])
@@ -567,14 +590,14 @@ type CustomNode = Node<CustomData, CustomEvents, CustomNodeTypes>
export const nodes = ref<CustomNode[]>([ export const nodes = ref<CustomNode[]>([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
// this will create the node-type `custom` // this will create the node-type `custom`
type: 'custom', type: 'custom',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
}, },
{ {
id: '2', id: '2',
label: 'Node 2', data: { label: 'Node 2' },
// this will create the node-type `special` // this will create the node-type `special`
type: 'special', type: 'special',
position: { x: 150, y: 50 }, position: { x: 150, y: 50 },
@@ -582,7 +605,7 @@ export const nodes = ref<CustomNode[]>([
{ {
id: '3', id: '3',
label: 'Node 3', data: { label: 'Node 3' },
// this will throw a type error, as the type is not defined in the CustomEdgeTypes // this will throw a type error, as the type is not defined in the CustomEdgeTypes
// regardless it would be rendered as a default edge type // regardless it would be rendered as a default edge type
type: 'invalid', type: 'invalid',
@@ -646,10 +669,10 @@ meaning a node with the type `custom` is expected to have a slot named `#node-cu
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
import CustomNode from './CustomNode.vue' import CustomNode from './CustomNode.vue'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
type: 'custom', type: 'custom',
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
} }
@@ -657,7 +680,7 @@ const elements = ref([
</script> </script>
<template> <template>
<VueFlow v-model="elements"> <VueFlow :nodes="nodes">
<!-- the expected slot name is `node-custom` --> <!-- the expected slot name is `node-custom` -->
<template #node-custom="props"> <template #node-custom="props">
<CustomNode v-bind="props" /> <CustomNode v-bind="props" />
@@ -685,22 +708,22 @@ const nodeTypes = {
special: markRaw(SpecialNode), special: markRaw(SpecialNode),
} }
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
type: 'custom', type: 'custom',
}, },
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
type: 'special', type: 'special',
} }
]) ])
</script> </script>
<template> <template>
<VueFlow v-model="elements" :node-types="nodeTypes" /> <VueFlow :nodes="nodes" :nodeTypes="nodeTypes" />
</template> </template>
``` ```
@@ -759,10 +782,10 @@ const {
onNodeMouseMove onNodeMouseMove
} = useVueFlow() } = useVueFlow()
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
}, },
]) ])
@@ -784,7 +807,7 @@ onNodeDragStop((event) => {
</script> </script>
<template> <template>
<VueFlow v-model="elements" /> <VueFlow :nodes="nodes" />
</template> </template>
``` ```
@@ -793,28 +816,32 @@ onNodeDragStop((event) => {
import { ref } from 'vue' import { ref } from 'vue'
import { VueFlow } from '@vue-flow/core' import { VueFlow } from '@vue-flow/core'
const elements = ref([ const nodes = ref([
{ {
id: '1', id: '1',
label: 'Node 1', data: { label: 'Node 1' },
position: { x: 50, y: 50 }, position: { x: 50, y: 50 },
}, },
]) ])
function logEvent(name, data) {
console.log(name, data)
}
</script> </script>
<template> <template>
<!-- bind listeners to the event handlers --> <!-- bind listeners to the event handlers -->
<VueFlow <VueFlow
v-model="elements" :nodes="nodes"
@node-drag-start="console.log('drag start', $event)" @node-drag-start="logEvent('drag start', $event)"
@node-drag="console.log('drag', $event)" @node-drag="logEvent('drag', $event)"
@node-drag-stop="console.log('drag stop', $event)" @node-drag-stop="logEvent('drag stop', $event)"
@node-click="console.log('click', $event)" @node-click="logEvent('click', $event)"
@node-double-click="console.log('dblclick', $event)" @node-double-click="logEvent('dblclick', $event)"
@node-contextmenu="console.log('contextmenu', $event)" @node-contextmenu="logEvent('contextmenu', $event)"
@node-mouse-enter="console.log('mouseenter', $event)" @node-mouse-enter="logEvent('mouseenter', $event)"
@node-mouse-leave="console.log('mouseleave', $event)" @node-mouse-leave="logEvent('mouseleave', $event)"
@node-mouse-move="console.log('mousemove', $event)" @node-mouse-move="logEvent('mousemove', $event)"
/> />
</template> </template>
``` ```
@@ -824,15 +851,15 @@ const elements = ref([
<div class="mt-4 bg-[var(--vp-code-block-bg)] rounded-lg h-50"> <div class="mt-4 bg-[var(--vp-code-block-bg)] rounded-lg h-50">
<VueFlow <VueFlow
v-model="defaultNode" v-model="defaultNode"
@node-drag-start="console.log('drag start', $event)" @node-drag-start="logEvent('drag start', $event)"
@node-drag="console.log('drag', $event)" @node-drag="logEvent('drag', $event)"
@node-drag-stop="console.log('drag stop', $event)" @node-drag-stop="logEvent('drag stop', $event)"
@node-click="console.log('click', $event)" @node-click="logEvent('click', $event)"
@node-double-click="console.log('dblclick', $event)" @node-double-click="logEvent('dblclick', $event)"
@node-contextmenu="console.log('contextmenu', $event)" @node-contextmenu="logEvent('contextmenu', $event)"
@node-mouse-enter="console.log('mouseenter', $event)" @node-mouse-enter="logEvent('mouseenter', $event)"
@node-mouse-leave="console.log('mouseleave', $event)" @node-mouse-leave="logEvent('mouseleave', $event)"
@node-mouse-move="console.log('mousemove', $event)" @node-mouse-move="logEvent('mousemove', $event)"
> >
<Panel position="top-center"> <Panel position="top-center">
<p class="text-sm">Interact to see events in browser console</p> <p class="text-sm">Interact to see events in browser console</p>