fix: basic vueflow using custom node & edge

This commit is contained in:
Shariq Ansari 2023-05-02 12:28:49 +05:30
parent c61be69ca2
commit 42247bc31f
5 changed files with 205 additions and 3 deletions

View file

@ -1,15 +1,45 @@
<script setup>
import { VueFlow } from "@vue-flow/core";
import { VueFlow, useVueFlow, Panel, PanelPosition } from "@vue-flow/core";
import { Background } from "@vue-flow/background";
import TransitionEdge from "./components/TransitionEdge.vue";
import StateNode from "./components/StateNode.vue";
import { useStore } from "./store";
let store = useStore();
let { nodes, onConnect, addNodes, addEdges } = useVueFlow();
function add_state() {
let state_id = (nodes.value.length + 1).toString();
addNodes([
{
id: state_id,
type: "state",
label: "State " + state_id,
position: { x: 250, y: 100 }
}
]);
}
onConnect(params => {
params.animated = true;
params.type = "transition";
addEdges([params]);
});
</script>
<template>
<div class="workflow-container">
<VueFlow v-model="store.workflow.elements">
<VueFlow v-model="store.workflow.elements" connection-mode="loose">
<Background pattern-color="#aaa" gap="10" />
<Panel :position="PanelPosition.TopRight">
<button @click="add_state">Add State</button>
</Panel>
<template #node-state="node">
<StateNode :node="node" />
</template>
<template #edge-transition="props">
<TransitionEdge v-bind="props" />
</template>
</VueFlow>
</div>
</template>
@ -25,4 +55,16 @@ let store = useStore();
border: 1px solid var(--border-color);
background-color: var(--fg-color);
}
:deep(.transition-edge) {
stroke: var(--gray-600);
stroke-width: 1.5px;
}
:deep(.selected) {
.transition-edge {
stroke: var(--primary);
stroke-width: 2px;
}
}
</style>

View file

@ -0,0 +1,64 @@
<script setup>
import { Handle, Position } from "@vue-flow/core";
const props = defineProps({
node: {
type: Object,
required: true
}
});
</script>
<template>
<div class="node" tabindex="0">
<div v-if="node.label" class="node-label">{{ node.label }}</div>
<div v-else class="node-placeholder text-muted">{{ __("No Label") }}</div>
<Handle class="handle handle-a" type="source" :position="Position.Top" id="a" />
<Handle class="handle handle-b" type="source" :position="Position.Right" id="b" />
<Handle class="handle handle-c" type="source" :position="Position.Bottom" id="c" />
<Handle class="handle handle-d" type="source" :position="Position.Left" id="d" />
</div>
</template>
<style lang="scss" scoped>
.node {
position: relative;
background-color: var(--fg-color);
font-weight: 500;
border-radius: 50%;
padding: 25px;
color: var(--gray-600);
border: 1px solid var(--gray-600);
box-shadow: var(--shadow-base);
}
.vue-flow__node.selected .node {
outline: 1.5px solid var(--primary);
outline-offset: 2px;
}
.handle {
position: absolute;
width: 7px;
height: 7px;
background-color: var(--gray-600);
border-radius: 50%;
transition: all 0.2s ease-in-out;
&.handle-a {
top: -12px;
}
&.handle-b {
right: -12px;
}
&.handle-c {
bottom: -12px;
}
&.handle-d {
left: -12px;
}
}
</style>

View file

@ -0,0 +1,84 @@
<script setup>
import { computed, watch } from "vue";
import { getSmoothStepPath, SmoothStepEdge, useVueFlow } from "@vue-flow/core";
let { findEdge } = useVueFlow();
const props = defineProps({
id: { type: String, required: true },
sourceX: { type: Number, required: true },
sourceY: { type: Number, required: true },
targetX: { type: Number, required: true },
targetY: { type: Number, required: true },
sourcePosition: { type: String, required: false },
targetPosition: { type: String, required: false },
sourceHandle: { type: String, required: false },
targetHandle: { type: String, required: false },
sourceNode: { type: Object, required: true },
targetNode: { type: Object, required: true },
markerEnd: { type: String, required: false },
selected: { type: Boolean, required: false },
data: { type: Object, required: false }
});
let marker_end = {
type: "arrow",
width: 20,
height: 20,
strokeWidth: 1.5,
color: "#687178"
};
let marker_end_primary = {
type: "arrow",
width: 15,
height: 15,
strokeWidth: 1.5,
color: "#2490ef"
};
watch(
() => props.selected,
() => {
findEdge(props.id).markerEnd = props.selected ? marker_end_primary : marker_end;
},
{ immediate: true }
);
const d = computed(() => {
return getSmoothStepPath({
sourceX: props.sourceX,
sourceY: props.sourceY,
targetX: props.targetX,
targetY: props.targetY,
sourceHandle: props.sourceHandle,
targetHandle: props.targetHandle,
sourcePosition: props.sourcePosition,
targetPosition: props.targetPosition,
targetNode: props.targetNode,
borderRadius: 30
});
});
</script>
<script>
export default {
inheritAttrs: false
};
</script>
<template>
<SmoothStepEdge class="transition-edge" :id="id" :path="d[0]" :markerEnd="markerEnd" />
</template>
<style lang="scss" scoped>
.access {
pointer-events: all;
cursor: pointer;
position: absolute;
font-size: var(--text-sm);
padding: 2px 6px;
border-radius: 16px;
background-color: var(--fg-color);
border: 1px solid var(--gray-600);
box-shadow: var(--shadow-base);
}
</style>

View file

@ -3,7 +3,19 @@ import { ref } from "vue";
export const useStore = defineStore("workflow-builder-store", () => {
let workflow = ref({
elements: [],
elements: [
{ id: "1", label: "Open", type: "state", position: { x: 300, y: 150 } },
{ id: "2", label: "Approved", type: "state", position: { x: 700, y: 150 } },
{
id: "edge-1-2",
source: "1",
target: "2",
type: "transition",
sourceHandle: "b",
targetHandle: "d",
animated: true,
},
],
});
return {