update(docs): Remove docs dir
* Docs are in a dedicated repo now Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
5
docs/.gitignore
vendored
5
docs/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
node_modules
|
||||
*.log
|
||||
.nuxt
|
||||
nuxt.d.ts
|
||||
.output
|
||||
@@ -1,29 +0,0 @@
|
||||
# Nuxt 3 Minimal Starter
|
||||
|
||||
We recommend to look at the [documentation](https://v3.nuxtjs.org).
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install the dependencies
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Start the development server on http://localhost:3000
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
Checkout the [deployment documentation](https://v3.nuxtjs.org/docs/deployment).
|
||||
19
docs/app.vue
19
docs/app.vue
@@ -1,19 +0,0 @@
|
||||
<template>
|
||||
<Header />
|
||||
<div id="app" class="flex">
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
@import 'assets/index.css';
|
||||
|
||||
/* these are necessary styles for vue flow */
|
||||
@import 'node_modules/@braks/vue-flow/dist/style.css';
|
||||
|
||||
/* this contains the default theme, you can skip it if you want to */
|
||||
@import 'node_modules/@braks/vue-flow/dist/theme-default.css';
|
||||
|
||||
#app {
|
||||
height: calc(100% - 92px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,102 +0,0 @@
|
||||
#__nuxt {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#__nuxt {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
color: #111;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('./polygon-scatter.svg');
|
||||
}
|
||||
|
||||
.backround-img {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('./polygon-scatter.svg');
|
||||
}
|
||||
|
||||
.overview-example__add {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vue-flow__node a {
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.vue-flow__node.dark-node {
|
||||
background: #0041d0;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.vue-flow__node.dark {
|
||||
background: #557;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.vue-flow__node-selectorNode {
|
||||
font-size: 14px;
|
||||
background: #f0f2f3;
|
||||
border: 1px solid #555;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vue-flow__node-selectorNode .vue-flow__handle {
|
||||
border-color: #f0f2f3;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.overview-example__add {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
#vue-flow-examples {
|
||||
@apply flex m-0 bg-white h-full;
|
||||
height: 100vh;
|
||||
text-transform: uppercase;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#vue-flow-docs {
|
||||
@apply flex m-0 bg-white h-full;
|
||||
|
||||
h1 {
|
||||
@apply text-4xl mb-4 font-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-lg font-qtype;
|
||||
}
|
||||
|
||||
p ~ h1 {
|
||||
@apply mt-6;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-green-500 font-semibold hover:text-green-300;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply mt-2;
|
||||
list-style-type: circle;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply bg-gray-200 hover:bg-gray-300 focus:outline-none font-bold mr-2 border-2 p-2 rounded-xl;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg id="visual" viewBox="0 0 960 540" width="960" height="540" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect width="960" height="540" fill="#31475e"></rect><g><g transform="translate(57 45)"><path d="M0 -106.9L83.6 -66.7L104.2 23.8L46.4 96.3L-46.4 96.3L-104.2 23.8L-83.6 -66.7Z" fill="#3fb984"></path></g><g transform="translate(708 88)"><path d="M0 -66L51.6 -41.2L64.3 14.7L28.6 59.5L-28.6 59.5L-64.3 14.7L-51.6 -41.2Z" fill="#3fb984"></path></g><g transform="translate(823 510)"><path d="M0 -77L60.2 -48L75.1 17.1L33.4 69.4L-33.4 69.4L-75.1 17.1L-60.2 -48Z" fill="#3fb984"></path></g><g transform="translate(896 280)"><path d="M0 -45L35.2 -28.1L43.9 10L19.5 40.5L-19.5 40.5L-43.9 10L-35.2 -28.1Z" fill="#3fb984"></path></g><g transform="translate(287 458)"><path d="M0 -58L45.3 -36.2L56.5 12.9L25.2 52.3L-25.2 52.3L-56.5 12.9L-45.3 -36.2Z" fill="#3fb984"></path></g><g transform="translate(12 380)"><path d="M0 -101L79 -63L98.5 22.5L43.8 91L-43.8 91L-98.5 22.5L-79 -63Z" fill="#3fb984"></path></g><g transform="translate(609 440)"><path d="M0 -60L46.9 -37.4L58.5 13.4L26 54.1L-26 54.1L-58.5 13.4L-46.9 -37.4Z" fill="#3fb984"></path></g><g transform="translate(457 42)"><path d="M0 -81L63.3 -50.5L79 18L35.1 73L-35.1 73L-79 18L-63.3 -50.5Z" fill="#3fb984"></path></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,80 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
useHooks,
|
||||
useStore,
|
||||
getEdgeCenter,
|
||||
getBezierPath,
|
||||
getMarkerEnd,
|
||||
ArrowHeadType,
|
||||
EdgeProps,
|
||||
ElementId,
|
||||
Position,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
const store = useStore()
|
||||
const hooks = useHooks()
|
||||
const onEdgeClick = (evt: Event, id: string) => {
|
||||
const edge = store.edges.find((edge) => edge.id === id)
|
||||
if (edge) {
|
||||
hooks.elementsRemove.trigger([edge])
|
||||
}
|
||||
evt.stopPropagation()
|
||||
alert(`remove ${id}`)
|
||||
}
|
||||
|
||||
const foreignObjectSize = 40
|
||||
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
const center = computed(() =>
|
||||
getEdgeCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
}),
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" :style="props.style" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<foreignObject
|
||||
:width="foreignObjectSize"
|
||||
:height="foreignObjectSize"
|
||||
:x="center[0] - foreignObjectSize / 2"
|
||||
:y="center[1] - foreignObjectSize / 2"
|
||||
class="edgebutton-foreignobject"
|
||||
requiredExtensions="http://www.w3.org/1999/xhtml"
|
||||
>
|
||||
<body class="p-1">
|
||||
<button class="edgebutton bg-gray-500 p-[4px] h-full w-full" @click="(event) => onEdgeClick(event, props.id)">×</button>
|
||||
</body>
|
||||
</foreignObject>
|
||||
</template>
|
||||
<style scoped>
|
||||
body {
|
||||
background: unset;
|
||||
}
|
||||
</style>
|
||||
@@ -1,38 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, Position, Connection, Edge, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface ColorSelectorNodeProps extends NodeProps {
|
||||
data: {
|
||||
color: string
|
||||
onChange: (event: any) => void
|
||||
}
|
||||
type: string
|
||||
selected?: boolean
|
||||
connectable?: boolean
|
||||
xPos?: number
|
||||
yPos?: number
|
||||
targetPosition?: Position
|
||||
sourcePosition?: Position
|
||||
dragging?: boolean
|
||||
}
|
||||
const props = defineProps<ColorSelectorNodeProps>()
|
||||
|
||||
const targetHandleStyle: CSSProperties = { background: '#555' }
|
||||
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: '10px' }
|
||||
const sourceHandleStyleB: CSSProperties = { ...targetHandleStyle, bottom: '10px', top: 'auto' }
|
||||
|
||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params)
|
||||
</script>
|
||||
<template>
|
||||
<div class="py-1 px-1 flex flex-col gap-1 justify-center items-center">
|
||||
<Handle type="target" :position="Position.Left" :style="targetHandleStyle" :on-connect="onConnect" />
|
||||
<div class="text-md font-bold">Custom Color Picker Node</div>
|
||||
<div :style="{ color: data.color }" class="text-md font-semibold">
|
||||
{{ data.color }}
|
||||
</div>
|
||||
<input class="nodrag" type="color" :value="data.color" @input="props.data.onChange" />
|
||||
<Handle id="a" type="source" :position="Position.Right" :style="sourceHandleStyleA" />
|
||||
<Handle id="b" type="source" :position="Position.Right" :style="sourceHandleStyleB" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,23 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { ConnectionLineComponentProps } from '@braks/vue-flow'
|
||||
|
||||
interface ConnectionLineProps extends ConnectionLineComponentProps {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
}
|
||||
const props = defineProps<ConnectionLineProps>()
|
||||
</script>
|
||||
<template>
|
||||
<g>
|
||||
<path
|
||||
class="animated"
|
||||
fill="none"
|
||||
stroke="#222"
|
||||
:stroke-width="1.5"
|
||||
:d="`M${props.sourceX},${props.sourceY} C ${props.sourceX} ${props.targetY} ${props.sourceX} ${props.targetY} ${props.targetX},${props.targetY}`"
|
||||
/>
|
||||
<circle :cx="props.targetX" :cy="props.targetY" fill="#fff" :r="3" stroke="#222" :stroke-width="1.5" />
|
||||
</g>
|
||||
</template>
|
||||
@@ -1,41 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { ArrowHeadType, ElementId, getBezierPath, getMarkerEnd, Position, EdgeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
source: ElementId
|
||||
target: ElementId
|
||||
sourceHandleId?: ElementId
|
||||
targetHandleId?: ElementId
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<text>
|
||||
<textPath :href="`#${props.id}`" :style="{ fontSize: '12px' }" startOffset="50%" text-anchor="middle">
|
||||
{{ props.data.text }}
|
||||
</textPath>
|
||||
</text>
|
||||
</template>
|
||||
@@ -1,65 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
getBezierPath,
|
||||
getMarkerEnd,
|
||||
ArrowHeadType,
|
||||
EdgeProps,
|
||||
ElementId,
|
||||
getEdgeCenter,
|
||||
Position,
|
||||
EdgeText,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
source: ElementId
|
||||
target: ElementId
|
||||
sourceHandleId?: ElementId
|
||||
targetHandleId?: ElementId
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
const center = computed(() =>
|
||||
getEdgeCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
}),
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<EdgeText
|
||||
:x="center[0]"
|
||||
:y="center[1]"
|
||||
:label="props.data?.text"
|
||||
:label-style="{ fill: 'white' }"
|
||||
:label-show-bg="true"
|
||||
:label-bg-style="{ fill: 'red' }"
|
||||
:label-bg-padding="[2, 4]"
|
||||
:label-bg-border-radius="2"
|
||||
@click="() => console.log(props.data)"
|
||||
/>
|
||||
</template>
|
||||
@@ -1,10 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
interface CustomLabelProps {
|
||||
text: string
|
||||
}
|
||||
|
||||
const props = defineProps<CustomLabelProps>()
|
||||
</script>
|
||||
<template>
|
||||
<tspan dy="10" x="0">{{ props.text }}</tspan>
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
const onDragStart = (event: DragEvent, nodeType: string) => {
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.setData('application/vueflow', nodeType)
|
||||
event.dataTransfer.effectAllowed = 'move'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<aside class="md:(w-[30%] max-w-[200px])">
|
||||
<div class="mb-6">You can drag these nodes to the pane on the left.</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-input"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'input')"
|
||||
>
|
||||
Input Node
|
||||
</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-default"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'default')"
|
||||
>
|
||||
Default Node
|
||||
</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-output"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'output')"
|
||||
>
|
||||
Output Node
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
<style scoped>
|
||||
aside {
|
||||
border-right: 1px solid #eee;
|
||||
padding: 15px 10px;
|
||||
font-size: 12px;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
|
||||
.droppable-node {
|
||||
@apply mb-6;
|
||||
cursor: grab;
|
||||
}
|
||||
</style>
|
||||
@@ -1,30 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
const examples = [
|
||||
{
|
||||
path: '/',
|
||||
label: 'Introduction',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<aside>
|
||||
<div class="flex flex-col text-left items-start">
|
||||
<router-link v-for="(e, i) of examples" :key="`docs-link-${i}`" class="docs-link" :to="`/docs${e.path}`">
|
||||
{{ e.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
<style scoped>
|
||||
.docs-link {
|
||||
@apply w-full text-lg text-white hover:text-yellow-500 px-3 py-2;
|
||||
}
|
||||
.router-link-active {
|
||||
@apply rounded-lg bg-white font-semibold text-yellow-500;
|
||||
}
|
||||
aside {
|
||||
@apply w-[280px] px-[10px] py-[15px];
|
||||
background: rgba(0, 0, 0, 0.25) !important;
|
||||
overflow-x: hidden; /* Disable horizontal scroll */
|
||||
}
|
||||
</style>
|
||||
@@ -1,129 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
const examples = [
|
||||
{
|
||||
path: '/',
|
||||
label: 'Overview',
|
||||
},
|
||||
{
|
||||
path: '/basic',
|
||||
label: 'Basic',
|
||||
},
|
||||
{
|
||||
path: '/custom-connectionline',
|
||||
label: 'Custom Connectionline',
|
||||
},
|
||||
{
|
||||
path: '/custom-node',
|
||||
label: 'Custom Node',
|
||||
},
|
||||
{
|
||||
path: '/drag-n-drop',
|
||||
label: 'Drag and Drop',
|
||||
},
|
||||
{
|
||||
path: '/edges',
|
||||
label: 'Edges',
|
||||
},
|
||||
{
|
||||
path: '/button-edge',
|
||||
label: 'Edge with Button',
|
||||
},
|
||||
{
|
||||
path: '/edge-types',
|
||||
label: 'Edge Types',
|
||||
},
|
||||
{
|
||||
path: '/empty',
|
||||
label: 'Empty',
|
||||
},
|
||||
{
|
||||
path: '/hidden',
|
||||
label: 'Hidden',
|
||||
},
|
||||
{
|
||||
path: '/interaction',
|
||||
label: 'Interaction',
|
||||
},
|
||||
/*
|
||||
todo: layouting example not working with dagre for some reason so it's disabled for now
|
||||
{
|
||||
path: '/layouting',
|
||||
label: 'Layouting',
|
||||
},
|
||||
*/
|
||||
{
|
||||
path: '/multi-flows',
|
||||
label: 'Multi Flows',
|
||||
},
|
||||
{
|
||||
path: '/node-type-change',
|
||||
label: 'Node Type Change',
|
||||
},
|
||||
{
|
||||
path: '/node-types-id-change',
|
||||
label: 'Node Types ID Change',
|
||||
},
|
||||
{
|
||||
path: '/provider',
|
||||
label: 'Provider',
|
||||
},
|
||||
{
|
||||
path: '/save-restore',
|
||||
label: 'Save and Restore',
|
||||
},
|
||||
{
|
||||
path: '/stress',
|
||||
label: 'Stress',
|
||||
},
|
||||
{
|
||||
path: '/switch',
|
||||
label: 'Switch',
|
||||
},
|
||||
{
|
||||
path: '/unidirectional',
|
||||
label: 'Unidirectional',
|
||||
},
|
||||
{
|
||||
path: '/updatable-edge',
|
||||
label: 'Updatable Edge',
|
||||
},
|
||||
{
|
||||
path: '/update-node',
|
||||
label: 'Update Node',
|
||||
},
|
||||
{
|
||||
path: '/update-node-internals',
|
||||
label: 'Update Node Internals',
|
||||
},
|
||||
{
|
||||
path: '/validation',
|
||||
label: 'Validation',
|
||||
},
|
||||
{
|
||||
path: '/zoom-pan-helper',
|
||||
label: 'Zoom Pan Helper',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<aside>
|
||||
<div class="flex flex-col text-left items-start">
|
||||
<router-link v-for="(e, i) of examples" :key="`example-link-${i}`" class="example-link" :to="`/examples${e.path}`">
|
||||
{{ e.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
<style scoped>
|
||||
.example-link {
|
||||
@apply w-full text-lg text-white hover:text-yellow-500 px-3 py-2 leading-tight;
|
||||
}
|
||||
.router-link-active {
|
||||
@apply rounded-lg bg-white font-semibold text-yellow-500 shadow-lg;
|
||||
}
|
||||
aside {
|
||||
@apply relative w-[280px] h-full px-[10px] py-[15px];
|
||||
background: rgba(0, 0, 0, 0.25) !important;
|
||||
overflow-x: hidden; /* Disable horizontal scroll */
|
||||
}
|
||||
</style>
|
||||
@@ -1,20 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, Background, Connection, Elements, Edge, removeElements, addEdge } from '@braks/vue-flow'
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,40 +0,0 @@
|
||||
<script setup>
|
||||
import { useStore } from '@braks/vue-flow'
|
||||
const store = useStore()
|
||||
</script>
|
||||
<template>
|
||||
<header class="flex border-b-1 border-black border-solid items-center py-4 px-8 font-semibold text-white">
|
||||
<div class="flex flex-col">
|
||||
<a class="logo text-xl" href="https://github.com/bcakmakoglu/vue-flow">
|
||||
Vue Flow <span class="text-xs">v{{ store.vueFlowVersion }}</span></a
|
||||
>
|
||||
<span class="text-xs text-gray-800 mt-2"
|
||||
>An open source library by <a href="https://github.com/bcakmakoglu/bcakmakoglu">Braks</a> <br />
|
||||
Based on <a href="https://reactflow.dev">React Flow</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<router-link class="link" to="/docs">Docs</router-link>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<router-link class="link" to="/examples">Examples</router-link>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<a class="link" href="https://github.com/bcakmakoglu/vue-flow">Github</a>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
<style scoped>
|
||||
a {
|
||||
@apply hover:text-gray-300;
|
||||
}
|
||||
|
||||
.logo {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
line-height: 1;
|
||||
}
|
||||
.link {
|
||||
@apply bg-gray-200 rounded-lg px-4 py-2 !hover:text-yellow-500 text-black;
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface NodeAProps extends NodeProps {
|
||||
nodeStyles: Record<string, any>
|
||||
}
|
||||
const props = defineProps<NodeAProps>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="props.nodeStyles">A</div>
|
||||
</template>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface NodeBPro extends NodeProps {
|
||||
nodeStyles: Record<string, any>
|
||||
}
|
||||
const props = defineProps<NodeBPro>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="props.nodeStyles">B</div>
|
||||
</template>
|
||||
@@ -1,27 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { useStore } from '@braks/vue-flow'
|
||||
const store = useStore()
|
||||
|
||||
const nodes = computed(() => store.nodes)
|
||||
const transform = computed(() => store.transform)
|
||||
|
||||
const selectAll = () => {
|
||||
store.selectedElements = nodes.value
|
||||
store.unsetUserSelection()
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<aside>
|
||||
<div class="description">This is an example of how you can access the internal state outside of the Vue Flow component.</div>
|
||||
<div class="title">Zoom & pan transform</div>
|
||||
<div class="transform">{{ [transform[0].toFixed(2), transform[1].toFixed(2), transform[2].toFixed(2)] }}</div>
|
||||
<div class="title">Nodes</div>
|
||||
<div v-for="node of nodes" :key="node.id">
|
||||
Node {{ node.id }} - x: {{ node.__rf.position.x.toFixed(2) }}, y: {{ node.__rf.position.y.toFixed(2) }}
|
||||
</div>
|
||||
|
||||
<div class="selectall">
|
||||
<button class="button" @click="selectAll">select all nodes</button>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
@@ -1,60 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import localforage from 'localforage'
|
||||
import { useZoomPanHelper, FlowInstance, FlowExportObject, Node } from '@braks/vue-flow'
|
||||
|
||||
localforage.config({
|
||||
name: 'vue-flow',
|
||||
storeName: 'flows',
|
||||
})
|
||||
|
||||
const flowKey = 'example-flow'
|
||||
|
||||
const getNodeId = () => `randomnode_${+new Date()}`
|
||||
|
||||
const { transform } = useZoomPanHelper()
|
||||
|
||||
type ControlsProps = {
|
||||
flowInstance?: FlowInstance
|
||||
}
|
||||
|
||||
const props = defineProps<ControlsProps>()
|
||||
const emit = defineEmits(['restore', 'add'])
|
||||
|
||||
const onSave = () => {
|
||||
if (props.flowInstance) {
|
||||
const flow = props.flowInstance.toObject()
|
||||
localforage.setItem(flowKey, flow)
|
||||
}
|
||||
}
|
||||
|
||||
const onRestore = () => {
|
||||
const restoreFlow = async () => {
|
||||
const flow: FlowExportObject | null = await localforage.getItem(flowKey)
|
||||
|
||||
console.log(flow)
|
||||
if (flow) {
|
||||
const [x = 0, y = 0] = flow.position
|
||||
emit('restore', flow.elements ?? [])
|
||||
transform({ x, y, zoom: flow.zoom || 0 })
|
||||
}
|
||||
}
|
||||
|
||||
restoreFlow()
|
||||
}
|
||||
|
||||
const onAdd = () => {
|
||||
const newNode = {
|
||||
id: `random_node-${getNodeId()}`,
|
||||
data: { label: 'Added node' },
|
||||
position: { x: Math.random() * window.innerWidth - 100, y: Math.random() * window.innerHeight },
|
||||
} as Node
|
||||
emit('add', newNode)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="save__controls">
|
||||
<button class="button" @click="onSave">save</button>
|
||||
<button class="button" @click="onRestore">restore</button>
|
||||
<button class="button" @click="onAdd">add node</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,19 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, NodeProps, Position } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
id: string
|
||||
}
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' }
|
||||
</script>
|
||||
<template>
|
||||
<div :style="nodeStyles">
|
||||
<div>node {{ props.id }}</div>
|
||||
<Handle id="left" type="source" :position="Position.Left" />
|
||||
<Handle id="right" type="source" :position="Position.Right" />
|
||||
<Handle id="top" type="source" :position="Position.Top" />
|
||||
<Handle id="bottom" type="source" :position="Position.Bottom" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,25 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, Position, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
data: any
|
||||
}
|
||||
const nodeStyles: CSSProperties = { padding: 10, border: '1px solid #ddd' }
|
||||
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="nodeStyles">
|
||||
<Handle type="target" :position="Position.Left" />
|
||||
<div>output handle count: {{ props.data.handleCount }}</div>
|
||||
<Handle
|
||||
v-for="i of props.data.handleCount"
|
||||
:id="`handle-${i}`"
|
||||
:key="`handle-${i}`"
|
||||
type="source"
|
||||
:position="Position.Right"
|
||||
:style="{ top: 10 * i + props.data.handlePosition * 10 }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,9 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position, Handle, Connection } from '@braks/vue-flow'
|
||||
|
||||
const isValidConnection = (connection: Connection) => connection.target === 'B'
|
||||
</script>
|
||||
<template>
|
||||
<div>Only connectable with B</div>
|
||||
<Handle type="source" :position="Position.Right" :is-valid-connection="isValidConnection" />
|
||||
</template>
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position, Handle, Connection, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
id: string
|
||||
}
|
||||
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
|
||||
const isValidConnection = (connection: Connection) => connection.target === 'B'
|
||||
</script>
|
||||
<template>
|
||||
<Handle type="target" :position="Position.Left" :is-valid-connection="isValidConnection" />
|
||||
<div>{{ props.id }}</div>
|
||||
<Handle type="source" :position="Position.Right" :is-valid-connection="isValidConnection" />
|
||||
</template>
|
||||
@@ -1,6 +0,0 @@
|
||||
<template>
|
||||
<ExamplesSidebar />
|
||||
<div id="vue-flow-examples" class="flex-1">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
<DocsSidebar />
|
||||
<div id="vue-flow-docs" class="flex-1 flex flex-col items-center justify-center">
|
||||
<div class="p-6 text-left gap-2 w-1/2">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,23 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
import { defineNuxtConfig } from 'nuxt3'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
meta: {
|
||||
title: 'Vue Flow',
|
||||
description: 'Vue Flow Documentation',
|
||||
},
|
||||
router: {
|
||||
base: '/',
|
||||
},
|
||||
vite: {
|
||||
alias: {
|
||||
vue: resolve('./node_modules/vue'),
|
||||
},
|
||||
resolve: {
|
||||
dedupe: ['vue'],
|
||||
preserveSymlinks: false,
|
||||
},
|
||||
},
|
||||
ssr: true,
|
||||
buildModules: ['nuxt-windicss'],
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxi dev",
|
||||
"build": "nuxi build",
|
||||
"start": "node .output/server/index.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braks/vue-flow": "link:..",
|
||||
"dagre": "^0.8.5",
|
||||
"localforage": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dagre": "^0.7.46",
|
||||
"nuxt-windicss": "^2.0.4",
|
||||
"nuxt3": "latest"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
layout: 'docs',
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<h1>Getting started</h1>
|
||||
<p>
|
||||
Vue Flow, just like React Flow, is a library for building node-based applications. These can be simple static diagrams or
|
||||
complex node-based editors. You can implement custom node types and edge types and it comes with components like a mini-map
|
||||
and graph controls. Feel free to check out the <router-link to="/examples">examples</router-link>.
|
||||
</p>
|
||||
</template>
|
||||
@@ -1,49 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
layout: 'docs',
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="p-4 bg-yellow-200 rounded-xl mb-4">
|
||||
<p class="italic font-bold">
|
||||
Vue Flow is not ready for production use yet. If you want to contribute getting the library ready, feel free to do so!
|
||||
Improvements need to be made on perfomance, documentation and testing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h1>Introduction</h1>
|
||||
<p>
|
||||
Vue Flow, just like React Flow, is a library for building node-based applications. These can be simple static diagrams or
|
||||
complex node-based editors. You can implement custom node types and edge types and it comes with components like a mini-map
|
||||
and graph controls. Feel free to check out the <router-link to="/examples">examples</router-link>.
|
||||
</p>
|
||||
|
||||
<h1>Key Features</h1>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="font-semibold">👶 Easy to use</span>: Seamless zooming & panning behaviour and single and multi-selections of
|
||||
elements
|
||||
</li>
|
||||
<li>
|
||||
<span class="font-semibold">🎨 Customizable</span>: Different <router-link to="/docs/api/node-types">node</router-link> and
|
||||
<router-link to="/docs/api/edge-types">edge types</router-link> and support for custom nodes with multiple handles and
|
||||
custom edges
|
||||
</li>
|
||||
<li>
|
||||
<span class="font-semibold">(🚧 Kinda, it's a work in progress) Fast rendering</span>: Only nodes that have changed are
|
||||
re-rendered and only those that are in the viewport are displayed (optionally)
|
||||
</li>
|
||||
<li>
|
||||
<span class="font-semibold">🧲 Utils</span>: Snap-to-grid and graph
|
||||
<router-link to="/docs/api/helper-functions">helper functions</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<span class="font-semibold">📦 Components</span>: <router-link to="/docs/api/background">Background</router-link>,
|
||||
<router-link to="/docs/api/minimap">Minimap</router-link> and <router-link to="/docs/api/controls">Controls</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<span class="font-semibold">🦾 Reliable</span>: Written in <a href="https://www.typescriptlang.org/">TypeScript</a>(🚧 and
|
||||
not yet tested with <a href="https://cypress.io">Cypress</a>)
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
@@ -1,91 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
addEdge,
|
||||
isNode,
|
||||
removeElements,
|
||||
Node,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStop = ({ node }: { node: Node }) => console.log('drag stop', node)
|
||||
const onElementClick = ({ node }: { node: Node }) => console.log('click', node)
|
||||
const elements = ref<Elements>([
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
])
|
||||
const rfInstance = ref<FlowInstance | null>(null)
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Edge | Connection) => (elements.value = addEdge(params, elements.value))
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance?.fitView({ padding: 0.1 })
|
||||
rfInstance.value = flowInstance
|
||||
}
|
||||
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el: FlowElement) => {
|
||||
if (isNode(el)) {
|
||||
el.position = {
|
||||
x: Math.random() * 400,
|
||||
y: Math.random() * 400,
|
||||
}
|
||||
}
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
const logToObject = () => console.log(rfInstance.value?.toObject())
|
||||
const resetTransform = () => rfInstance.value?.setTransform({ x: 0, y: 0, zoom: 1 })
|
||||
|
||||
const toggleClassnames = () => {
|
||||
elements.value = elements.value.map((el: FlowElement) => {
|
||||
if (isNode(el)) el.class = el.class === 'dark' ? 'light' : 'dark'
|
||||
return el
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
class="vue-flow-basic-example"
|
||||
:elements="elements"
|
||||
:default-zoom="1.5"
|
||||
:min-zoom="0.2"
|
||||
:max-zoom="4"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@node-click="onElementClick"
|
||||
@elementClick="onElementClick"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background color="#aaa" :gap="8" />
|
||||
<div class="absolute right-[10px] top-[10px] z-4">
|
||||
<button class="button" @click="resetTransform">reset transform</button>
|
||||
<button class="button" @click="updatePos">change pos</button>
|
||||
<button class="button" @click="toggleClassnames">toggle classnames</button>
|
||||
<button class="button" @click="logToObject">toObject</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.vue-flow--node .light {
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
.vue-flow--node .dark {
|
||||
@apply bg-black;
|
||||
}
|
||||
</style>
|
||||
@@ -1,55 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
Background,
|
||||
Connection,
|
||||
Controls,
|
||||
Edge,
|
||||
EdgeType,
|
||||
Elements,
|
||||
MiniMap,
|
||||
FlowInstance,
|
||||
removeElements,
|
||||
} from '@braks/vue-flow'
|
||||
import ButtonEdge from '../../components/ButtonEdge.vue'
|
||||
const edgeTypes = {
|
||||
buttonedge: ButtonEdge as EdgeType,
|
||||
}
|
||||
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: 'ewb-1',
|
||||
type: 'input',
|
||||
data: { label: 'Input 1' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{ id: 'ewb-2', data: { label: 'Node 2' }, position: { x: 250, y: 300 } },
|
||||
{
|
||||
id: 'edge-1-2',
|
||||
source: 'ewb-1',
|
||||
target: 'ewb-2',
|
||||
type: 'buttonedge',
|
||||
},
|
||||
])
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) =>
|
||||
(elements.value = addEdge({ ...params, type: 'buttonedge' } as Edge, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
key="edge-with-button"
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:edge-types="edgeTypes"
|
||||
@load="onLoad"
|
||||
@elementsRemove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,23 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, removeElements, addEdge, Background, BackgroundVariant, Elements, Connection, Edge } from '@braks/vue-flow'
|
||||
import CustomConnectionLine from '../../components/CustomConnectionLine.vue'
|
||||
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
])
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<template #custom-connection-line="props">
|
||||
<CustomConnectionLine v-bind="props" />
|
||||
</template>
|
||||
<Background :variant="BackgroundVariant.Lines" />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,130 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
isEdge,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Node,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Position,
|
||||
SnapGrid,
|
||||
Connection,
|
||||
ConnectionMode,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
import ColorPickerNode from '../../components/ColorPickerNode.vue'
|
||||
|
||||
const elements = ref<Elements>([])
|
||||
const bgColor = ref('#1A192B')
|
||||
const connectionLineStyle = { stroke: '#fff' }
|
||||
const snapGrid: SnapGrid = [16, 16]
|
||||
const nodeTypes = {
|
||||
selectorNode: ColorPickerNode,
|
||||
}
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log('flow loaded:', flowInstance)
|
||||
}
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
const nodeStroke = (n: Node): string => {
|
||||
if (n.type === 'input') return '#0041d0'
|
||||
if (n.type === 'selectorNode') return bgColor.value
|
||||
if (n.type === 'output') return '#ff0072'
|
||||
return '#eee'
|
||||
}
|
||||
const nodeColor = (n: Node): string => {
|
||||
if (n.type === 'selectorNode') return bgColor.value
|
||||
return '#fff'
|
||||
}
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
elements.value = elements.value.map((e: FlowElement) => {
|
||||
if (isEdge(e) || e.id !== '2') {
|
||||
return e
|
||||
}
|
||||
const color = (event.target as HTMLInputElement).value
|
||||
bgColor.value = color
|
||||
|
||||
return {
|
||||
...e,
|
||||
data: {
|
||||
...e.data,
|
||||
color,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
elements.value = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'An input node' },
|
||||
position: { x: 0, y: 50 },
|
||||
sourcePosition: Position.Right,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'selectorNode',
|
||||
data: { onChange, color: bgColor.value },
|
||||
style: { border: '1px solid #777', padding: '10px' },
|
||||
position: { x: 250, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output A' },
|
||||
position: { x: 650, y: 25 },
|
||||
targetPosition: Position.Left,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'output',
|
||||
data: { label: 'Output B' },
|
||||
position: { x: 650, y: 100 },
|
||||
targetPosition: Position.Left,
|
||||
},
|
||||
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
|
||||
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
|
||||
{ id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } },
|
||||
]
|
||||
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
|
||||
const onConnect = (params: Connection | Edge) =>
|
||||
(elements.value = addEdge(
|
||||
{
|
||||
...params,
|
||||
animated: true,
|
||||
style: { stroke: '#fff' },
|
||||
} as Edge,
|
||||
elements.value,
|
||||
))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:style="`background: ${bgColor}`"
|
||||
:node-types="nodeTypes"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
:connection-line-style="connectionLineStyle"
|
||||
:snap-to-grid="true"
|
||||
:snap-grid="snapGrid"
|
||||
:default-zoom="1.5"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap :node-stroke-color="nodeStroke" :node-color="nodeColor" />
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,70 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
removeElements,
|
||||
Controls,
|
||||
MiniMap,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
} from '@braks/vue-flow'
|
||||
import Sidebar from '../../components/DnDSidebar.vue'
|
||||
|
||||
const flowInstance = ref<FlowInstance>()
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'input node' },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
])
|
||||
|
||||
let id = 0
|
||||
const getId = (): ElementId => `dndnode_${id++}`
|
||||
|
||||
const onDragOver = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.dropEffect = 'move'
|
||||
}
|
||||
}
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onLoad = (instance: FlowInstance) => (flowInstance.value = instance)
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (flowInstance.value) {
|
||||
console.log(event.dataTransfer?.getData('application/vueflow'))
|
||||
const type = event.dataTransfer?.getData('application/vueflow')
|
||||
const position = flowInstance.value.project({ x: event.clientX - 400, y: event.clientY - 40 })
|
||||
const newNode = {
|
||||
id: getId(),
|
||||
type,
|
||||
position,
|
||||
data: { label: `${type} node` },
|
||||
}
|
||||
|
||||
elements.value.push(newNode)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col md:flex-row w-full h-full">
|
||||
<div class="flex-1 h-full" @drop="onDrop">
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @load="onLoad" @connect="onConnect" @dragover="onDragOver">
|
||||
<Controls />
|
||||
<MiniMap />
|
||||
<Background color="#aaa" :gap="8" />
|
||||
</Flow>
|
||||
</div>
|
||||
<Sidebar />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,30 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
} from '@braks/vue-flow'
|
||||
import { getElements } from './edgeTypesUtils'
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log(flowInstance.getElements())
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(getElements())
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :min-zoom="0.2" @load="onLoad" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,106 +0,0 @@
|
||||
import { ElementId, Elements, Position } from '@braks/vue-flow'
|
||||
|
||||
const nodeWidth = 80
|
||||
const nodeGapWidth = nodeWidth * 2
|
||||
const nodeStyle = { width: `${nodeWidth}px`, fontSize: '11px', color: 'white' }
|
||||
|
||||
const sourceTargetPositions = [
|
||||
{ source: Position.Bottom, target: Position.Top },
|
||||
{ source: Position.Right, target: Position.Left },
|
||||
]
|
||||
const nodeColors = [
|
||||
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
|
||||
['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8'],
|
||||
]
|
||||
const edgeTypes = ['default', 'step', 'smoothstep', 'straight']
|
||||
const offsets = [
|
||||
{
|
||||
x: 0,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: 0,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
]
|
||||
|
||||
let id = 0
|
||||
const getNodeId = (): ElementId => (id++).toString()
|
||||
|
||||
export function getElements(): Elements {
|
||||
const initialElements = []
|
||||
|
||||
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
|
||||
const currSourceTargetPos = sourceTargetPositions[sourceTargetIndex]
|
||||
|
||||
for (let edgeTypeIndex = 0; edgeTypeIndex < edgeTypes.length; edgeTypeIndex++) {
|
||||
const currEdgeType = edgeTypes[edgeTypeIndex]
|
||||
|
||||
for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) {
|
||||
const currOffset = offsets[offsetIndex]
|
||||
|
||||
const style = { ...nodeStyle, background: nodeColors[sourceTargetIndex][edgeTypeIndex] }
|
||||
const sourcePosition = {
|
||||
x: offsetIndex * nodeWidth * 4,
|
||||
y: edgeTypeIndex * 300 + sourceTargetIndex * edgeTypes.length * 300,
|
||||
}
|
||||
const sourceId = getNodeId()
|
||||
const sourceData = { label: `Source ${sourceId}` }
|
||||
const sourceNode = {
|
||||
id: sourceId,
|
||||
style,
|
||||
data: sourceData,
|
||||
position: sourcePosition,
|
||||
sourcePosition: currSourceTargetPos.source,
|
||||
targetPosition: currSourceTargetPos.target,
|
||||
}
|
||||
|
||||
const targetId = getNodeId()
|
||||
const targetData = { label: `Target ${targetId}` }
|
||||
const targetPosition = {
|
||||
x: sourcePosition.x + currOffset.x,
|
||||
y: sourcePosition.y + currOffset.y,
|
||||
}
|
||||
const targetNode = {
|
||||
id: targetId,
|
||||
style,
|
||||
data: targetData,
|
||||
position: targetPosition,
|
||||
sourcePosition: currSourceTargetPos.source,
|
||||
targetPosition: currSourceTargetPos.target,
|
||||
}
|
||||
|
||||
initialElements.push(sourceNode)
|
||||
initialElements.push(targetNode)
|
||||
|
||||
initialElements.push({ id: `${sourceId}-${targetId}`, source: sourceId, target: targetId, type: currEdgeType })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initialElements
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
Elements,
|
||||
FlowInstance,
|
||||
FlowElement,
|
||||
removeElements,
|
||||
Connection,
|
||||
Edge,
|
||||
addEdge,
|
||||
ArrowHeadType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomEdge from '../../components/CustomEdge.vue'
|
||||
import CustomEdge2 from '../../components/CustomEdge2.vue'
|
||||
import CustomLabel from '../../components/CustomLabel.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
||||
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
||||
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
||||
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
||||
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
||||
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
||||
{ id: '9', type: 'output', data: { label: 'Output 9' }, position: { x: 675, y: 500 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', class: 'normal-edge' },
|
||||
{ id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' },
|
||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
||||
{ id: 'e3-3a', source: '3', target: '3a', type: 'straight', label: 'label only edge', style: { stroke: 'none' } },
|
||||
{ id: 'e3-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
|
||||
{
|
||||
id: 'e5-6',
|
||||
source: '5',
|
||||
target: '6',
|
||||
label: {
|
||||
component: CustomLabel,
|
||||
props: {
|
||||
text: 'custom label text',
|
||||
},
|
||||
},
|
||||
labelStyle: { fill: 'red', fontWeight: 700 },
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e5-7',
|
||||
source: '5',
|
||||
target: '7',
|
||||
label: 'label with styled bg',
|
||||
labelBgPadding: [8, 4],
|
||||
labelBgBorderRadius: 4,
|
||||
labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 },
|
||||
arrowHeadType: ArrowHeadType.ArrowClosed,
|
||||
},
|
||||
{
|
||||
id: 'e5-8',
|
||||
source: '5',
|
||||
target: '8',
|
||||
type: 'custom',
|
||||
data: { text: 'custom edge' },
|
||||
arrowHeadType: ArrowHeadType.ArrowClosed,
|
||||
},
|
||||
{
|
||||
id: 'e5-9',
|
||||
source: '5',
|
||||
target: '9',
|
||||
type: 'custom2',
|
||||
data: { text: 'custom edge 2' },
|
||||
},
|
||||
]
|
||||
|
||||
const edgeTypes: Record<string, any> = {
|
||||
custom: CustomEdge,
|
||||
custom2: CustomEdge2,
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:edge-types="edgeTypes"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,54 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Elements,
|
||||
FlowElement,
|
||||
Node,
|
||||
FlowInstance,
|
||||
addEdge,
|
||||
removeElements,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const elements = ref<Elements>([])
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => console.log('flow loaded:', flowInstance)
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', left: '10px', top: '10px', zIndex: 4 }
|
||||
const addRandomNode = () => {
|
||||
const nodeId: ElementId = (elements.value.length + 1).toString()
|
||||
const newNode: Node = {
|
||||
id: nodeId,
|
||||
data: { label: `Node: ${nodeId}` },
|
||||
position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
|
||||
} as Node
|
||||
elements.value = [...elements.value, newNode]
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
@load="onLoad"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="(p) => onConnect(p)"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background :variant="BackgroundVariant.Lines" />
|
||||
|
||||
<button class="button" type="button" :style="buttonStyle" @click="addRandomNode">add node</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,39 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, MiniMap, Controls, Connection, Edge, Elements, addEdge } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const isHidden = ref<boolean>(false)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
watchEffect(() => {
|
||||
elements.value = elements.value.map((e) => {
|
||||
e.isHidden = isHidden.value
|
||||
return e
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
<div :style="{ position: 'absolute', left: '10px', top: '10px', zIndex: 4 }">
|
||||
<div>
|
||||
<label for="ishidden">
|
||||
isHidden
|
||||
<input id="ishidden" v-model="isHidden" type="checkbox" class="vue-flow__ishidden" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,172 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
isNode,
|
||||
Node,
|
||||
Elements,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
FlowTransform,
|
||||
SnapGrid,
|
||||
ArrowHeadType,
|
||||
Connection,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStart = (node: Node) => console.log('drag start', node)
|
||||
const onNodeDrag = (node: Node) => console.log('drag', node)
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
const onNodeDoubleClick = (node: Node) => console.log('node double click', node)
|
||||
const onPaneClick = (event: MouseEvent) => console.log('pane click', event)
|
||||
const onPaneScroll = (event?: MouseEvent) => console.log('pane scroll', event)
|
||||
const onPaneContextMenu = (event: MouseEvent) => console.log('pane context menu', event)
|
||||
const onSelectionDrag = (nodes: Node[]) => console.log('selection drag', nodes)
|
||||
const onSelectionDragStart = (nodes: Node[]) => console.log('selection drag start', nodes)
|
||||
const onSelectionDragStop = (nodes: Node[]) => console.log('selection drag stop', nodes)
|
||||
const onSelectionContextMenu = (event: MouseEvent, nodes: Node[]) => {
|
||||
event.preventDefault()
|
||||
console.log('selection context menu', nodes)
|
||||
}
|
||||
const onElementClick = (element: FlowElement) => console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element)
|
||||
const onSelectionChange = (elements: Elements | null) => console.log('selection change', elements)
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
console.log('flow loaded:', flowInstance)
|
||||
flowInstance.fitView()
|
||||
}
|
||||
|
||||
const onMoveEnd = (transform?: FlowTransform) => console.log('zoom/move end', transform)
|
||||
const onEdgeContextMenu = (edge: Edge) => console.log('edge context menu', edge)
|
||||
const onEdgeMouseEnter = (edge: Edge) => console.log('edge mouse enter', edge)
|
||||
const onEdgeMouseMove = (edge: Edge) => console.log('edge mouse move', edge)
|
||||
const onEdgeMouseLeave = (edge: Edge) => console.log('edge mouse leave', edge)
|
||||
const onEdgeDoubleClick = (edge: Edge) => console.log('edge double click', edge)
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: {
|
||||
label: 'Welcome to <strong>Vue Flow!</strong>',
|
||||
},
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: {
|
||||
label: 'This is a <strong>default node</strong>',
|
||||
},
|
||||
position: { x: 100, y: 100 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: {
|
||||
label: 'This one has a <strong>custom style</strong>',
|
||||
},
|
||||
position: { x: 400, y: 100 },
|
||||
style: { background: '#D6D5E6', color: '#333', border: '1px solid #222138', width: 180 },
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
position: { x: 250, y: 200 },
|
||||
data: {
|
||||
label: `You can find the docs on
|
||||
<a href="https://github.com/bcakmakoglu/vue-flow" target="_blank" rel="noopener noreferrer">
|
||||
Github
|
||||
</a>`,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
data: {
|
||||
label: 'Or check out the other <strong>examples</strong>',
|
||||
},
|
||||
position: { x: 250, y: 325 },
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
type: 'output',
|
||||
data: {
|
||||
label: 'An <strong>output node</strong>',
|
||||
},
|
||||
position: { x: 100, y: 480 },
|
||||
},
|
||||
{ id: '7', type: 'output', data: { label: 'Another output node' }, position: { x: 400, y: 450 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
|
||||
{ id: 'e4-5', source: '4', target: '5', arrowHeadType: ArrowHeadType.Arrow, label: 'edge with arrow head' },
|
||||
{ id: 'e5-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' },
|
||||
{
|
||||
id: 'e5-7',
|
||||
source: '5',
|
||||
target: '7',
|
||||
type: 'step',
|
||||
style: { stroke: '#f6ab6c' },
|
||||
label: 'a step edge',
|
||||
animated: true,
|
||||
labelStyle: { fill: '#f6ab6c', fontWeight: 700 },
|
||||
},
|
||||
]
|
||||
|
||||
const connectionLineStyle: CSSProperties = { stroke: '#ddd' }
|
||||
const snapGrid: SnapGrid = [16, 16]
|
||||
|
||||
const nodeStrokeColor = (n: Node): string => {
|
||||
if (n.style?.background) return n.style.background as string
|
||||
if (n.type === 'input') return '#0041d0'
|
||||
if (n.type === 'output') return '#ff0072'
|
||||
if (n.type === 'default') return '#1a192b'
|
||||
|
||||
return '#eee'
|
||||
}
|
||||
|
||||
const nodeColor = (n: Node): string => {
|
||||
if (n.style?.background) return n.style.background as string
|
||||
|
||||
return '#fff'
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:connection-line-style="connectionLineStyle"
|
||||
:snap-to-grid="true"
|
||||
:snap-grid="snapGrid"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@eonnect="onConnect"
|
||||
@pane-click="onPaneClick"
|
||||
@pane-scroll="onPaneScroll"
|
||||
@pane-contex-menu="onPaneContextMenu"
|
||||
@node-drag-start="onNodeDragStart"
|
||||
@node-drag="onNodeDrag"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@node-double-click="onNodeDoubleClick"
|
||||
@selection-drag-start="onSelectionDragStart"
|
||||
@selection-drag="onSelectionDrag"
|
||||
@selection-drag-stop="onSelectionDragStop"
|
||||
@selection-context-menu="onSelectionContextMenu"
|
||||
@selection-change="onSelectionChange"
|
||||
@move-end="onMoveEnd"
|
||||
@load="onLoad"
|
||||
@edge-context-menu="onEdgeContextMenu"
|
||||
@edge-mouse-enter="onEdgeMouseEnter"
|
||||
@edge-mouse-move="onEdgeMouseMove"
|
||||
@edge-mouse-leave="onEdgeMouseLeave"
|
||||
@edge-double-click="onEdgeDoubleClick"
|
||||
>
|
||||
<MiniMap :node-stroke-color="nodeStrokeColor" :node-color="nodeColor" :node-border-radius="2" />
|
||||
<Controls />
|
||||
<Background color="#aaa" gap="20" />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,152 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Elements,
|
||||
Node,
|
||||
FlowElement,
|
||||
Connection,
|
||||
Edge,
|
||||
PanOnScrollMode,
|
||||
FlowTransform,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node)
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event)
|
||||
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event)
|
||||
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event)
|
||||
const onMoveEnd = (flowTranasform?: FlowTransform) => console.log('onMoveEnd', flowTranasform)
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const isSelectable = ref(false)
|
||||
const isDraggable = ref(false)
|
||||
const isConnectable = ref(false)
|
||||
const zoomOnScroll = ref(false)
|
||||
const zoomOnPinch = ref(false)
|
||||
const panOnScroll = ref(false)
|
||||
const panOnScrollMode = ref<PanOnScrollMode>(PanOnScrollMode.Free)
|
||||
const zoomOnDoubleClick = ref(false)
|
||||
const paneMoveable = ref(true)
|
||||
const captureZoomClick = ref(false)
|
||||
const captureZoomScroll = ref(false)
|
||||
const captureElementClick = ref(false)
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:elements-selectable="isSelectable"
|
||||
:nodes-connectable="isConnectable"
|
||||
:nodes-draggable="isDraggable"
|
||||
:zoom-on-scroll="zoomOnScroll"
|
||||
:zoom-on-pinch="zoomOnPinch"
|
||||
:pan-on-scroll="panOnScroll"
|
||||
:pan-on-scroll-mode="panOnScrollMode"
|
||||
:zoom-on-double-click="zoomOnDoubleClick"
|
||||
:pane-moveable="paneMoveable"
|
||||
@connect="onConnect"
|
||||
@element-click="captureElementClick ? onElementClick : undefined"
|
||||
@node-drag-start="onNodeDragStart"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@pane-click="captureZoomClick ? onPaneClick : undefined"
|
||||
@pane-scroll="captureZoomScroll ? onPaneScroll : undefined"
|
||||
@pane-context-menu="captureZoomClick ? onPaneContextMenu : undefined"
|
||||
@move-end="onMoveEnd"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
<div :style="{ position: 'absolute', left: 10, top: 10, zIndex: 4 }">
|
||||
<div>
|
||||
<label for="draggable">
|
||||
nodesDraggable
|
||||
<input id="draggable" v-model="isDraggable" type="checkbox" class="vue-flow__draggable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="connectable">
|
||||
nodesConnectable
|
||||
<input id="connectable" v-model="isConnectable" type="checkbox" class="vue-flow__connectable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="selectable">
|
||||
elementsSelectable
|
||||
<input id="selectable" v-model="isSelectable" type="checkbox" class="vue-flow__selectable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonscroll">
|
||||
zoomOnScroll
|
||||
<input id="zoomonscroll" v-model="zoomOnScroll" type="checkbox" class="vue-flow__zoomonscroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonpinch">
|
||||
zoomOnPinch
|
||||
<input id="zoomonpinch" v-model="zoomOnPinch" type="checkbox" class="vue-flow__zoomonpinch" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panonscroll">
|
||||
panOnScroll
|
||||
<input id="panonscroll" v-model="panOnScroll" type="checkbox" class="vue-flow__panonscroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
panOnScrollMode
|
||||
<select id="panonscrollmode" v-model="panOnScrollMode" class="vue-flow__panonscrollmode">
|
||||
<option value="free">free</option>
|
||||
<option value="horizontal">horizontal</option>
|
||||
<option value="vertical">vertical</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomondbl">
|
||||
zoomOnDoubleClick
|
||||
<input id="zoomondbl" v-model="zoomOnDoubleClick" type="checkbox" class="vue-flow__zoomondbl" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panemoveable">
|
||||
paneMoveable
|
||||
<input id="panemoveable" v-model="paneMoveable" type="checkbox" class="vue-flow__panemoveable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompaneclick">
|
||||
capture onPaneClick
|
||||
<input id="capturezoompaneclick" v-model="captureZoomClick" type="checkbox" class="vue-flow__capturezoompaneclick" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompanescroll">
|
||||
capture onPaneScroll
|
||||
<input id="capturezoompanescroll" v-model="captureZoomScroll" type="checkbox" class="vue-flow__capturezoompanescroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="captureelementclick">
|
||||
capture onElementClick
|
||||
<input id="captureelementclick" v-model="captureElementClick" type="checkbox" class="vue-flow__captureelementclick" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,158 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import dagre from 'dagre'
|
||||
import {
|
||||
Flow,
|
||||
Controls,
|
||||
addEdge,
|
||||
ConnectionMode,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
isNode,
|
||||
NodeExtent,
|
||||
Position,
|
||||
removeElements,
|
||||
XYPosition,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const position: XYPosition = { x: 0, y: 0 }
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'input' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: 'node 2' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2a',
|
||||
data: { label: 'node 2a' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2b',
|
||||
data: { label: 'node 2b' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2c',
|
||||
data: { label: 'node 2c' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2d',
|
||||
data: { label: 'node 2d' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'node 3' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'node 4' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
data: { label: 'node 5' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
type: 'output',
|
||||
data: { label: 'output' },
|
||||
position,
|
||||
},
|
||||
{ id: '7', type: 'output', data: { label: 'output' }, position: { x: 400, y: 450 } },
|
||||
{ id: 'e12', source: '1', target: '2', type: 'smoothstep', animated: true },
|
||||
{ id: 'e13', source: '1', target: '3', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22a', source: '2', target: '2a', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22b', source: '2', target: '2b', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22c', source: '2', target: '2c', type: 'smoothstep', animated: true },
|
||||
{ id: 'e2c2d', source: '2c', target: '2d', type: 'smoothstep', animated: true },
|
||||
|
||||
{ id: 'e45', source: '4', target: '5', type: 'smoothstep', animated: true },
|
||||
{ id: 'e56', source: '5', target: '6', type: 'smoothstep', animated: true },
|
||||
{ id: 'e57', source: '5', target: '7', type: 'smoothstep', animated: true },
|
||||
]
|
||||
|
||||
const dagreGraph = new dagre.graphlib.Graph()
|
||||
dagreGraph.setDefaultEdgeLabel(() => ({}))
|
||||
|
||||
const nodeExtent: NodeExtent = [
|
||||
[0, 0],
|
||||
[1000, 1000],
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, animated: true }, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
|
||||
const onLayout = (direction: string) => {
|
||||
const isHorizontal = direction === 'LR'
|
||||
dagreGraph.setGraph({ rankdir: direction })
|
||||
|
||||
elements.value.forEach((el) => {
|
||||
if (isNode(el)) {
|
||||
dagreGraph.setNode(el.id, { width: 150, height: 50 })
|
||||
} else {
|
||||
dagreGraph.setEdge(el.source, el.target)
|
||||
}
|
||||
})
|
||||
|
||||
dagre.layout(dagreGraph)
|
||||
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
const nodeWithPosition = dagreGraph.node(el.id)
|
||||
el.targetPosition = isHorizontal ? Position.Left : Position.Top
|
||||
el.sourcePosition = isHorizontal ? Position.Right : Position.Bottom
|
||||
el.position = { x: nodeWithPosition.x, y: nodeWithPosition.y }
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="layoutflow">
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:node-extent="nodeExtent"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@connect="onConnect"
|
||||
@clements-remove="onElementsRemove"
|
||||
@load="() => onLayout('TB')"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
<div class="controls">
|
||||
<button class="button" :style="{ marginRight: 10 }" @click="() => onLayout('TB')">vertical layout</button>
|
||||
<button class="button" @click="() => onLayout('LR')">horizontal layout</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.layoutflow {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layoutflow .controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.controls button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,24 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import Flow from '../../components/Flow.vue'
|
||||
</script>
|
||||
<template>
|
||||
<div class="vue-flow__example-multiflows flex-1">
|
||||
<Flow />
|
||||
<Flow />
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.vue-flow__example-multiflows {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vue-flow__example-multiflows .vue-flow {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vue-flow__example-multiflows .vue-flow:first-child {
|
||||
border-right: 2px solid #333;
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Flow, addEdge, Connection, Edge, Elements, isEdge, FlowInstance, Position } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
sourcePosition: Position.Right,
|
||||
type: 'input',
|
||||
data: { label: 'Input' },
|
||||
position: { x: 0, y: 80 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'output',
|
||||
sourcePosition: Position.Right,
|
||||
targetPosition: Position.Left,
|
||||
data: { label: 'A Node' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true },
|
||||
]
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 }
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
|
||||
const changeType = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el) || el.type === 'input') return el
|
||||
|
||||
return {
|
||||
...el,
|
||||
type: el.type === 'default' ? 'output' : 'default',
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @connect="onConnect" @load="onLoad">
|
||||
<button class="button mt-2" :style="buttonStyle" @click="changeType">change type</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,60 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Flow, Elements, Position, NodeType, Connection, Edge, addEdge } from '@braks/vue-flow'
|
||||
import NodeA from '../../components/NodeA.vue'
|
||||
import NodeB from '../../components/NodeB.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
sourcePosition: Position.Right,
|
||||
type: 'input',
|
||||
data: { label: 'Input' },
|
||||
position: { x: 0, y: 80 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'a',
|
||||
sourcePosition: Position.Right,
|
||||
targetPosition: Position.Left,
|
||||
data: { label: 'A Node' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
]
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 }
|
||||
|
||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' }
|
||||
type NodeTypesObject = {
|
||||
[key: string]: Record<string, NodeType>
|
||||
}
|
||||
|
||||
const nodeTypesObjects: NodeTypesObject = {
|
||||
a: {
|
||||
a: NodeA as NodeType,
|
||||
},
|
||||
b: {
|
||||
b: NodeB as NodeType,
|
||||
},
|
||||
}
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const nodeTypesId = ref('a')
|
||||
const changeType = () => {
|
||||
const id = nodeTypesId.value === 'a' ? 'b' : 'a'
|
||||
elements.value[1].type = id
|
||||
nodeTypesId.value = id
|
||||
}
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :node-types="nodeTypesObjects[nodeTypesId]" :node-types-id="nodeTypesId" @connect="onConnect">
|
||||
<template #node-a>
|
||||
<NodeA :node-styles="nodeStyles" />
|
||||
</template>
|
||||
<template #node-b>
|
||||
<NodeB :node-styles="nodeStyles" />
|
||||
</template>
|
||||
<button class="button mt-2" :style="buttonStyle" @click="changeType">change type</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,97 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
removeElements,
|
||||
Controls,
|
||||
FlowInstance,
|
||||
FlowElement,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
ConnectionMode,
|
||||
useStore,
|
||||
} from '@braks/vue-flow'
|
||||
import Sidebar from '../../components/ProviderSidebar.vue'
|
||||
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onLoad = (flowInstance: FlowInstance) => console.log('flow loaded:', flowInstance)
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
useStore()
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<div class="providerflow">
|
||||
<Sidebar />
|
||||
<div class="vue-flow-wrapper">
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@element-click="onElementClick"
|
||||
@connect="onConnect"
|
||||
@elements-remove="onElementsRemove"
|
||||
@load="onLoad"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.providerflow {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.providerflow aside {
|
||||
border-right: 1px solid #eee;
|
||||
padding: 15px 10px;
|
||||
font-size: 12px;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
|
||||
.providerflow aside .description {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.providerflow aside .title {
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.providerflow aside .transform {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.providerflow .vue-flow-wrapper {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.providerflow .selectall {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.providerflow {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.providerflow aside {
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,37 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, addEdge, Connection, Node, Edge, Elements, FlowInstance, removeElements } from '@braks/vue-flow'
|
||||
import Controls from '../../components/SaveControls.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
]
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const flowInstance = ref()
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onLoad = (instance: FlowInstance) => (flowInstance.value = instance)
|
||||
const onRestore = (els: Elements) => (elements.value = els)
|
||||
const onAdd = (el: Node) => (elements.value = elements.value.concat(el))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect" @load="onLoad">
|
||||
<Controls :flow-instance="flowInstance" @restore="onRestore" @add="onAdd" />
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.save__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.save__controls button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,88 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
isNode,
|
||||
Controls,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
function getElements(xElements = 10, yElements = 10): Elements {
|
||||
const initialElements = []
|
||||
let nodeId = 1
|
||||
let recentNodeId = null
|
||||
|
||||
for (let y = 0; y < yElements; y++) {
|
||||
for (let x = 0; x < xElements; x++) {
|
||||
const position = { x: x * 100, y: y * 50 }
|
||||
const data = { label: `Node ${nodeId}` }
|
||||
const node = {
|
||||
id: nodeId.toString(),
|
||||
style: { width: 50, fontSize: 11 },
|
||||
data,
|
||||
position,
|
||||
}
|
||||
initialElements.push(node)
|
||||
|
||||
if (recentNodeId && nodeId <= xElements * yElements) {
|
||||
initialElements.push({ id: `${x}-${y}`, source: recentNodeId.toString(), target: nodeId.toString() })
|
||||
}
|
||||
|
||||
recentNodeId = nodeId
|
||||
nodeId++
|
||||
}
|
||||
}
|
||||
|
||||
return initialElements
|
||||
}
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log(flowInstance.getElements())
|
||||
}
|
||||
|
||||
const initialElements: Elements = getElements(10, 10)
|
||||
const elements = ref(initialElements)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
return {
|
||||
...el,
|
||||
position: {
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
const updateElements = () => {
|
||||
const grid = Math.ceil(Math.random() * 10)
|
||||
elements.value = getElements(grid, grid)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @load="onLoad" @elementsRemove="onElementsRemove" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
|
||||
<div class="absolute right-[10px] top-[10px] z-4">
|
||||
<button class="button" @click="updatePos">change pos</button>
|
||||
<button class="button" @click="updateElements">update elements</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, removeElements, addEdge, Node, FlowElement, Elements, Connection, Edge } from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
|
||||
const elementsA: Elements = [
|
||||
{ id: '1a', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2a', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3a', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4a', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1a', target: '2a' },
|
||||
{ id: 'e1-3', source: '1a', target: '3a' },
|
||||
]
|
||||
|
||||
const elementsB: Elements = [
|
||||
{ id: 'inputb', type: 'input', data: { label: 'Input' }, position: { x: 300, y: 5 }, class: 'light' },
|
||||
{ id: '1b', data: { label: 'Node 1' }, position: { x: 0, y: 100 }, class: 'light' },
|
||||
{ id: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, class: 'light' },
|
||||
{ id: '3b', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4b', data: { label: 'Node 4' }, position: { x: 600, y: 100 }, class: 'light' },
|
||||
|
||||
{ id: 'e1b', source: 'inputb', target: '1b' },
|
||||
{ id: 'e2b', source: 'inputb', target: '2b' },
|
||||
{ id: 'e3b', source: 'inputb', target: '3b' },
|
||||
{ id: 'e4b', source: 'inputb', target: '4b' },
|
||||
]
|
||||
|
||||
const elements = ref(elementsA)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
>
|
||||
<div :style="{ position: 'absolute', right: '10px', top: '10px', zIndex: 4 }">
|
||||
<button class="button" style="margin-right: 5px" @click="() => (elements = elementsA)">flow a</button>
|
||||
<button class="button" @click="() => (elements = elementsB)">flow b</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,205 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
NodeType,
|
||||
addEdge,
|
||||
useZoomPanHelper,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Node,
|
||||
ConnectionLineType,
|
||||
ConnectionMode,
|
||||
updateEdge,
|
||||
ArrowHeadType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomNode from '../../components/UnidirectionalCustomNode.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '00',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 250 },
|
||||
},
|
||||
{
|
||||
id: '01',
|
||||
type: 'custom',
|
||||
position: { x: 100, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '02',
|
||||
type: 'custom',
|
||||
position: { x: 500, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '03',
|
||||
type: 'custom',
|
||||
position: { x: 500, y: 500 },
|
||||
},
|
||||
{
|
||||
id: '04',
|
||||
type: 'custom',
|
||||
position: { x: 100, y: 500 },
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 5 },
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
type: 'custom',
|
||||
position: { x: 600, y: 250 },
|
||||
},
|
||||
{
|
||||
id: '30',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 600 },
|
||||
},
|
||||
{
|
||||
id: '40',
|
||||
type: 'custom',
|
||||
position: { x: 5, y: 250 },
|
||||
},
|
||||
{
|
||||
id: 'e0-1a',
|
||||
source: '00',
|
||||
target: '01',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-1b',
|
||||
source: '00',
|
||||
target: '01',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-2a',
|
||||
source: '00',
|
||||
target: '02',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-2b',
|
||||
source: '00',
|
||||
target: '02',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-3a',
|
||||
source: '00',
|
||||
target: '03',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-3b',
|
||||
source: '00',
|
||||
target: '03',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-4a',
|
||||
source: '00',
|
||||
target: '04',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-4b',
|
||||
source: '00',
|
||||
target: '04',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-10',
|
||||
source: '00',
|
||||
target: '10',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-20',
|
||||
source: '00',
|
||||
target: '20',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-30',
|
||||
source: '00',
|
||||
target: '30',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-40',
|
||||
source: '00',
|
||||
target: '40',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
]
|
||||
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custom: CustomNode as NodeType,
|
||||
}
|
||||
|
||||
let id = 4
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, type: 'smoothstep' }, elements.value))
|
||||
const { project } = useZoomPanHelper()
|
||||
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
||||
(elements.value = updateEdge(oldEdge, newConnection, elements.value))
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) =>
|
||||
(elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: project({ x: evt.clientX, y: evt.clientY - 40 }),
|
||||
type: 'custom',
|
||||
} as Node))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:node-types="nodeTypes"
|
||||
:connection-line-type="ConnectionLineType.SmoothStep"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@connect="onConnect"
|
||||
@pane-click="onPaneClick"
|
||||
@edge-pdate="onEdgeUpdate"
|
||||
/>
|
||||
</template>
|
||||
@@ -1,89 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
Controls,
|
||||
updateEdge,
|
||||
addEdge,
|
||||
Elements,
|
||||
FlowInstance,
|
||||
Connection,
|
||||
Edge,
|
||||
removeElements,
|
||||
FlowEvents,
|
||||
ConnectionMode,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: {
|
||||
label: 'Node <strong>A</strong>',
|
||||
},
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: {
|
||||
label: 'Node <strong>B</strong>',
|
||||
},
|
||||
position: { x: 100, y: 100 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: {
|
||||
label: 'Node <strong>C</strong>',
|
||||
},
|
||||
position: { x: 400, y: 100 },
|
||||
style: { background: '#D6D5E6', color: '#333', border: '1px solid #222138', width: 180 },
|
||||
},
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'Updateable edge' },
|
||||
]
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onEdgeUpdateStart = (edge: Edge) => console.log('start update', edge)
|
||||
const onEdgeUpdateEnd = (edge: Edge) => console.log('end update', edge)
|
||||
const onEdgeUpdate = ({ edge, connection }: FlowEvents['edgeUpdate']) =>
|
||||
(elements.value = updateEdge(edge, connection, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@load="onLoad"
|
||||
@edge-update="onEdgeUpdate"
|
||||
@connect="onConnect"
|
||||
@edge-update-start="onEdgeUpdateStart"
|
||||
@elements-remove="onElementsRemove"
|
||||
@edge-update-end="onEdgeUpdateEnd"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.updatenode__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.updatenode__controls label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.updatenode__bglabel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.updatenode__checkboxwrapper {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,83 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
NodeType,
|
||||
addEdge,
|
||||
useZoomPanHelper,
|
||||
Node,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Position,
|
||||
isEdge,
|
||||
FlowInstance,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomNode from '../../components/UpdateNodeInternalsCustomNode.vue'
|
||||
|
||||
const initialHandleCount = 1
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'custom',
|
||||
data: { label: 'Node 1', handleCount: initialHandleCount, handlePosition: 0 },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
]
|
||||
|
||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: '10px', top: '10px', zIndex: 10 }
|
||||
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custom: CustomNode as NodeType,
|
||||
}
|
||||
|
||||
let id = 5
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const flowInstance = ref<FlowInstance>()
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const { project } = useZoomPanHelper()
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) =>
|
||||
(elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: project({ x: evt.clientX, y: evt.clientY - 40 }),
|
||||
data: { label: 'new node' },
|
||||
targetPosition: Position.Left,
|
||||
sourcePosition: Position.Right,
|
||||
} as Node))
|
||||
|
||||
const toggleHandleCount = () =>
|
||||
(elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el)) {
|
||||
return el
|
||||
}
|
||||
|
||||
return { ...el, data: { ...el.data, handleCount: el.data?.handleCount === 1 ? 2 : 1 } }
|
||||
}))
|
||||
|
||||
const toggleHandlePosition = () =>
|
||||
(elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el)) return el
|
||||
return { ...el, data: { ...el.data, handlePosition: el.data?.handlePosition === 0 ? 1 : 0 } }
|
||||
}))
|
||||
|
||||
const onLoad = (instance: FlowInstance) => {
|
||||
instance.fitView()
|
||||
flowInstance.value = instance
|
||||
}
|
||||
|
||||
const updateNodeInternals = () => flowInstance.value?.updateNodeInternals('1')
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :node-types="nodeTypes" @connect="onConnect" @pane-click="onPaneClick" @load="onLoad">
|
||||
<div :style="buttonWrapperStyles">
|
||||
<button class="button" @click="toggleHandleCount">toggle handle count</button>
|
||||
<button class="button" @click="toggleHandlePosition">toggle handle position</button>
|
||||
<button class="button" @click="updateNodeInternals">update node internals</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,73 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, Elements } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const nodeName = ref<string>('Node 1')
|
||||
const nodeBg = ref<string>('#eee')
|
||||
const nodeHidden = ref<boolean>(false)
|
||||
|
||||
const updateNode = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (el.id === '1') {
|
||||
// it's important that you create a new object here in order to notify react flow about the change
|
||||
el.data = {
|
||||
...el.data,
|
||||
label: nodeName.value,
|
||||
}
|
||||
el.style = { backgroundColor: nodeBg.value }
|
||||
el.isHidden = nodeHidden.value
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
updateNode()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :default-zoom="1.5" :min-zoom="0.2" :max-zoom="4">
|
||||
<div class="updatenode__controls p-4 bg-gray-300 rounded-xl">
|
||||
<label>label:</label>
|
||||
<input v-model="nodeName" />
|
||||
|
||||
<label class="updatenode__bglabel">background:</label>
|
||||
<input v-model="nodeBg" type="color" />
|
||||
|
||||
<div class="updatenode__checkboxwrapper">
|
||||
<label>hidden:</label>
|
||||
<input v-model="nodeHidden" type="checkbox" />
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.updatenode__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.updatenode__controls label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.updatenode__bglabel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.updatenode__checkboxwrapper {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,84 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
Handle,
|
||||
Connection,
|
||||
Position,
|
||||
Elements,
|
||||
Edge,
|
||||
OnConnectStartParams,
|
||||
NodeProps,
|
||||
FlowInstance,
|
||||
NodeType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomInput from '../../components/ValidationCustomInput.vue'
|
||||
import CustomNode from '../../components/ValidationCustomNode.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '0', type: 'custominput', position: { x: 0, y: 150 } },
|
||||
{ id: 'A', type: 'customnode', position: { x: 250, y: 0 } },
|
||||
{ id: 'B', type: 'customnode', position: { x: 250, y: 150 } },
|
||||
{ id: 'C', type: 'customnode', position: { x: 250, y: 300 } },
|
||||
]
|
||||
|
||||
const onLoad = (reactFlowInstance: FlowInstance) => reactFlowInstance.fitView()
|
||||
const onConnectStart = ({ nodeId, handleType }: OnConnectStartParams) => console.log('on connect start', { nodeId, handleType })
|
||||
const onConnectStop = (event: MouseEvent) => console.log('on connect stop', event)
|
||||
const onConnectEnd = (event: MouseEvent) => console.log('on connect end', event)
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => {
|
||||
console.log('on connect', params)
|
||||
elements.value = addEdge(params, elements.value)
|
||||
}
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custominput: CustomInput as NodeType,
|
||||
customnode: CustomNode as NodeType,
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:select-nodes-on-drag="false"
|
||||
class="validationflow"
|
||||
:node-types="nodeTypes"
|
||||
@connect="onConnect"
|
||||
@oad="onLoad"
|
||||
@connect-start="onConnectStart"
|
||||
@connect-stop="onConnectStop"
|
||||
@connect-end="onConnectEnd"
|
||||
/>
|
||||
</template>
|
||||
<style>
|
||||
.validationflow .vue-flow__node {
|
||||
width: 150px;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
color: #555;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__node-customnode {
|
||||
background: #e6e6e9;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.vue-flow__node-custominput .vue-flow__handle {
|
||||
background: #e6e6e9;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__node-custominput {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__handle-connecting {
|
||||
background: #ff6060;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__handle-valid {
|
||||
background: #55dd99;
|
||||
}
|
||||
</style>
|
||||
@@ -1,51 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
Background,
|
||||
MiniMap,
|
||||
useZoomPanHelper,
|
||||
Elements,
|
||||
ElementId,
|
||||
Connection,
|
||||
Edge,
|
||||
Node,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
let id = 5
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const { project } = useZoomPanHelper()
|
||||
|
||||
const elements = ref(initialElements)
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) => {
|
||||
const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 })
|
||||
|
||||
elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: projectedPosition,
|
||||
data: {
|
||||
label: `${projectedPosition.x}-${projectedPosition.y}`,
|
||||
},
|
||||
} as Node)
|
||||
}
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect" @pane-click="onPaneClick">
|
||||
<Background />
|
||||
<MiniMap />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,6 +0,0 @@
|
||||
<script lang="ts" setup></script>
|
||||
<template>
|
||||
<div class="flex justify-center items-center h-full w-full">
|
||||
<h1 class="text-5xl">Vue Flow</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./.nuxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
}
|
||||
6118
docs/yarn.lock
6118
docs/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user