refactor(options)!: remove worker and store option

* either unnecessary, broken or needs more work

Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Braks
2021-11-25 15:21:36 +01:00
parent 725dc8acb7
commit 708fa1f970
8 changed files with 83 additions and 206 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ interface CustomEdgeProps<T = any> extends EdgeProps<T> {
const props = defineProps<CustomEdgeProps>() const props = defineProps<CustomEdgeProps>()
const store = useVueFlow() const store = useVueFlow()
const onEdgeClick = (evt: Event, id: string) => { const onEdgeClick = (evt: Event, id: string) => {
const edge = store.edges.find((edge) => edge.id === id) const edge = store.getEdges.find((edge) => edge.id === id)
if (edge) { if (edge) {
store.hooks.elementsRemove.trigger([edge]) store.hooks.elementsRemove.trigger([edge])
} }
-1
View File
@@ -51,7 +51,6 @@ const updateElements = () => {
<template> <template>
<VueFlow <VueFlow
v-model="elements" v-model="elements"
:worker="true"
:loading="{ label: 'Loading...', transition: { name: 'fade', mode: 'out-in' } }" :loading="{ label: 'Loading...', transition: { name: 'fade', mode: 'out-in' } }"
@load="onLoad" @load="onLoad"
@elementsRemove="onElementsRemove" @elementsRemove="onElementsRemove"
+17 -21
View File
@@ -11,7 +11,6 @@ import {
NodeExtent, NodeExtent,
NodeTypes, NodeTypes,
EdgeTypes, EdgeTypes,
FlowStore,
FlowState, FlowState,
FlowInstance, FlowInstance,
Loading, Loading,
@@ -24,11 +23,9 @@ import EdgeRenderer from '../EdgeRenderer/EdgeRenderer.vue'
import LoadingIndicator from '../../components/Loading/LoadingIndicator.vue' import LoadingIndicator from '../../components/Loading/LoadingIndicator.vue'
import { createHooks, initFlow, useWindow, useZoomPanHelper } from '../../composables' import { createHooks, initFlow, useWindow, useZoomPanHelper } from '../../composables'
import { onLoadGetElements, onLoadProject, onLoadToObject } from '../../utils' import { onLoadGetElements, onLoadProject, onLoadToObject } from '../../utils'
import microDiff from 'microdiff'
interface FlowProps extends FlowOptions { interface FlowProps extends FlowOptions {
id?: string id?: string
store?: FlowStore
modelValue?: Elements modelValue?: Elements
nodeTypes?: NodeTypes nodeTypes?: NodeTypes
edgeTypes?: EdgeTypes edgeTypes?: EdgeTypes
@@ -65,10 +62,9 @@ interface FlowProps extends FlowOptions {
edgeUpdaterRadius?: number edgeUpdaterRadius?: number
storageKey?: string storageKey?: string
loading?: Loading loading?: Loading
worker?: boolean
} }
const emit = defineEmits([...Object.keys(createHooks()), 'update:elements', 'update:modelValue']) const emit = defineEmits([...Object.keys(createHooks()), 'update:modelValue'])
const props = withDefaults(defineProps<FlowProps>(), { const props = withDefaults(defineProps<FlowProps>(), {
modelValue: () => [], modelValue: () => [],
@@ -110,7 +106,7 @@ const props = withDefaults(defineProps<FlowProps>(), {
loading: false, loading: false,
worker: false, worker: false,
}) })
const store = initFlow(emit, typeof props.storageKey === 'string' ? props.storageKey : props.id, props.store) const store = initFlow(emit, typeof props.storageKey === 'string' ? props.storageKey : props.id)
const elements = useVModel(props, 'modelValue', emit) const elements = useVModel(props, 'modelValue', emit)
// if there are preloaded elements we overwrite the current elements with the stored ones // if there are preloaded elements we overwrite the current elements with the stored ones
@@ -139,7 +135,7 @@ onBeforeUnmount(() => store?.$dispose())
invoke(async () => { invoke(async () => {
init(options) init(options)
await store.setElements(elements.value) store.setElements(elements.value)
store.isReady = true store.isReady = true
// if ssr we can't wait for dimensions, they'll never really exist // if ssr we can't wait for dimensions, they'll never really exist
@@ -167,15 +163,20 @@ invoke(async () => {
) )
}) })
watch(props.modelValue, (val) => { watch(
const diff = microDiff(val, store.elements, { cyclesFix: false }) () => props.modelValue.length,
if (diff.length) store.setElements(val) () => store.setElements(elements.value),
}, { flush: 'post' }) )
watch(elements, (val) =>{ const { pause, resume } = pausableWatch(elements, store.setElements, { flush: 'post' })
const diff = microDiff(val, store.elements, { cyclesFix: false }) watch(
if (diff.length) store.setElements(val) () => store.elements,
}, { flush: 'post' }) (val) => {
watch(store.elements, (val) => (elements.value = val), { flush: 'post' }) pause()
elements.value = val
nextTick(resume)
},
{ flush: 'post', deep: true },
)
const transitionName = computed(() => { const transitionName = computed(() => {
let name = '' let name = ''
@@ -186,11 +187,6 @@ const transitionName = computed(() => {
return name return name
}) })
</script> </script>
<script lang="ts">
export default {
name: 'VueFlow'
}
</script>
<template> <template>
<div class="vue-flow"> <div class="vue-flow">
<Transition :key="`vue-flow-transition-${store.$id}`" :name="transitionName"> <Transition :key="`vue-flow-transition-${store.$id}`" :name="transitionName">
+32 -61
View File
@@ -1,21 +1,17 @@
import microDiff from 'microdiff' import microDiff from 'microdiff'
import { setActivePinia, createPinia, defineStore, StoreDefinition, acceptHMRUpdate } from 'pinia' import { setActivePinia, createPinia, defineStore, StoreDefinition, acceptHMRUpdate } from 'pinia'
import { FlowState, FlowActions, Elements, FlowGetters, GraphNode, NextElements, GraphEdge } from '~/types' import { FlowState, FlowActions, Elements, FlowGetters, GraphNode, GraphEdge, Edge } from '~/types'
import { import {
clampPosition,
getConnectedEdges, getConnectedEdges,
getNodesInside, getNodesInside,
getRectOfNodes, getRectOfNodes,
parseElements, parseElements,
defaultNodeTypes, defaultNodeTypes,
defaultEdgeTypes, defaultEdgeTypes,
deepUnref,
isGraphNode, isGraphNode,
getSourceTargetNodes, getSourceTargetNodes,
isEdge, isEdge,
isGraphEdge,
} from '~/utils' } from '~/utils'
import parseElementsWorker from '~/workers/parseElements'
const pinia = createPinia() const pinia = createPinia()
@@ -43,31 +39,31 @@ export default (id: string, preloadedState: FlowState) => {
return nodeTypes return nodeTypes
}, },
getNodes(): GraphNode[] { getNodes(): GraphNode[] {
const nodes = this.elements.filter(isGraphNode) if (this.isReady) {
const n = this.onlyRenderVisibleElements const nodes = this.elements.filter((n) => isGraphNode(n) && !n.isHidden) as GraphNode[]
? nodes && return this.onlyRenderVisibleElements
getNodesInside( ? nodes &&
nodes, getNodesInside(
{ nodes,
x: 0, {
y: 0, x: 0,
width: this.dimensions.width, y: 0,
height: this.dimensions.height, width: this.dimensions.width,
}, height: this.dimensions.height,
this.transform, },
true, this.transform,
) true,
: nodes )
: nodes ?? []
return n.filter((node) => !node.isHidden) ?? [] }
return []
}, },
getEdges(): GraphEdge[] { getEdges(): GraphEdge[] {
const edges = this.elements.filter(isEdge) const edges = this.elements.filter((e) => isEdge(e) && !e.isHidden) as Edge[]
return ( if (this.isReady) {
edges return (
.filter((edge) => !edge.isHidden) edges
.map((edge) => { .map((edge) => {
if (!isGraphEdge(edge)) {
const { sourceNode, targetNode } = getSourceTargetNodes(edge, this.getNodes) const { sourceNode, targetNode } = getSourceTargetNodes(edge, this.getNodes)
if (!sourceNode) console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`) if (!sourceNode) console.warn(`couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
if (!targetNode) console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`) if (!targetNode) console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
@@ -79,43 +75,19 @@ export default (id: string, preloadedState: FlowState) => {
targetNode, targetNode,
}, },
} }
} })
return edge .filter(({ sourceTargetNodes: { sourceNode, targetNode } }) => !!(sourceNode && targetNode)) ?? []
}) )
.filter(({ sourceTargetNodes: { sourceNode, targetNode } }) => !!(sourceNode && targetNode)) ?? [] }
) return []
}, },
getSelectedNodes(): GraphNode[] { getSelectedNodes(): GraphNode[] {
return this.selectedElements?.filter(isGraphNode) ?? [] return this.selectedElements?.filter(isGraphNode) ?? []
}, },
}, },
actions: { actions: {
async setElements(elements) { setElements(elements) {
let next: NextElements = { this.elements = parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent)
nextEdges: [],
nextNodes: [],
}
if (!this.worker || import.meta.env.SSR || typeof window === 'undefined') {
next = await parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent)
} else if (this.worker) {
const { workerFn, workerTerminate } = parseElementsWorker()
const res = await workerFn(
deepUnref(elements),
deepUnref(this.getNodes),
deepUnref(this.getEdges),
deepUnref(this.nodeExtent),
).catch((err) => {
console.error(err)
workerTerminate('ERROR')
})
if (res) {
workerTerminate('SUCCESS')
next = res
} else next = await parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent)
} else {
next = await parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent)
}
this.elements = [...next.nextNodes, ...next.nextEdges]
}, },
setUserSelection(mousePos) { setUserSelection(mousePos) {
this.selectionActive = true this.selectionActive = true
@@ -204,8 +176,7 @@ export default (id: string, preloadedState: FlowState) => {
this.elementsSelectable = isInteractive this.elementsSelectable = isInteractive
}, },
async addElements(elements: Elements) { async addElements(elements: Elements) {
const { nextNodes, nextEdges } = await parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent) this.elements = [...this.elements, ...parseElements(elements, this.getNodes, this.getEdges, this.nodeExtent)]
this.elements = [...this.elements, ...nextNodes, ...nextEdges]
}, },
}, },
}) })
-7
View File
@@ -3,16 +3,11 @@ import { Edge, EdgeTypes } from './edge'
import { NodeExtent, GraphNode, NodeTypes, TranslateExtent, Node } from './node' import { NodeExtent, GraphNode, NodeTypes, TranslateExtent, Node } from './node'
import { ConnectionLineType, ConnectionMode } from './connection' import { ConnectionLineType, ConnectionMode } from './connection'
import { KeyCode, PanOnScrollMode } from './zoom' import { KeyCode, PanOnScrollMode } from './zoom'
import { FlowStore } from './store'
export type ElementId = string export type ElementId = string
export type FlowElement<T = any> = GraphNode<T> | Edge<T> export type FlowElement<T = any> = GraphNode<T> | Edge<T>
export type FlowElements<T = any> = FlowElement<T>[] export type FlowElements<T = any> = FlowElement<T>[]
export type Elements<T = any> = (Node<T> | Edge<T>)[] export type Elements<T = any> = (Node<T> | Edge<T>)[]
export type NextElements = {
nextNodes: GraphNode[]
nextEdges: Edge[]
}
export type Transform = [number, number, number] export type Transform = [number, number, number]
@@ -148,6 +143,4 @@ export interface FlowOptions {
edgeUpdaterRadius?: number edgeUpdaterRadius?: number
storageKey?: string storageKey?: string
loading?: Loading loading?: Loading
worker?: boolean
store?: FlowStore
} }
+2 -2
View File
@@ -21,7 +21,7 @@ import {
OnConnectStopFunc, OnConnectStopFunc,
SetConnectionId, SetConnectionId,
} from './connection' } from './connection'
import { Edge, EdgeComponent, GraphEdge } from './edge' import { EdgeComponent, GraphEdge } from './edge'
import { NodeComponent, NodeExtent, GraphNode, TranslateExtent } from './node' import { NodeComponent, NodeExtent, GraphNode, TranslateExtent } from './node'
import { D3Selection, D3Zoom, D3ZoomHandler, InitD3ZoomPayload } from './zoom' import { D3Selection, D3Zoom, D3ZoomHandler, InitD3ZoomPayload } from './zoom'
import { FlowHooks } from './hooks' import { FlowHooks } from './hooks'
@@ -73,7 +73,7 @@ export interface FlowState extends FlowOptions {
} }
export interface FlowActions { export interface FlowActions {
setElements: (elements: Elements) => Promise<void> setElements: (elements: Elements) => void
setUserSelection: (mousePos: XYPosition) => void setUserSelection: (mousePos: XYPosition) => void
updateUserSelection: (mousePos: XYPosition) => void updateUserSelection: (mousePos: XYPosition) => void
unsetUserSelection: () => void unsetUserSelection: () => void
+31 -37
View File
@@ -3,7 +3,6 @@ import {
ConnectionMode, ConnectionMode,
Elements, Elements,
FlowState, FlowState,
NextElements,
NodeExtent, NodeExtent,
GraphNode, GraphNode,
PanOnScrollMode, PanOnScrollMode,
@@ -97,48 +96,43 @@ export const initialState = (): FlowState => ({
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-', vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
}) })
export const parseElements = async (elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent) => export const parseElements = (elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent) => {
new Promise<NextElements>((resolve) => { const parsedElements = []
const { nextEdges, nextNodes }: NextElements = { for (const element of elements) {
nextNodes: [], if (isNode(element)) {
nextEdges: [], const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
}
for (const element of elements) {
if (isNode(element)) {
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
if (storeNode) { if (storeNode) {
const updatedNode = { const updatedNode = {
...storeNode, ...storeNode,
...element, ...element,
} as GraphNode } as GraphNode
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) { if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
// we reset the elements dimensions here in order to force a re-calculation of the bounds. // we reset the elements dimensions here in order to force a re-calculation of the bounds.
// When the type of a node changes it is possible that the number or positions of handles changes too. // When the type of a node changes it is possible that the number or positions of handles changes too.
updatedNode.__vf.width = 0 updatedNode.__vf.width = 0
}
nextNodes.push(updatedNode)
} else {
nextNodes.push(parseNode(element, nodeExtent))
} }
} else if (isEdge(element)) {
const storeEdge = edges[edges.map((x) => x.id).indexOf(element.id)]
if (storeEdge) { parsedElements.push(updatedNode)
nextEdges.push({ } else {
...storeEdge, parsedElements.push(parseNode(element, nodeExtent))
...element, }
}) } else if (isEdge(element)) {
} else { const storeEdge = edges[edges.map((x) => x.id).indexOf(element.id)]
nextEdges.push(parseEdge(element))
} if (storeEdge) {
parsedElements.push({
...storeEdge,
...element,
})
} else {
parsedElements.push(parseEdge(element))
} }
} }
resolve({ nextEdges, nextNodes }) }
}) return parsedElements
}
const isObject = (val: any) => val !== null && typeof val === 'object' const isObject = (val: any) => val !== null && typeof val === 'object'
const isArray = Array.isArray const isArray = Array.isArray
-76
View File
@@ -1,76 +0,0 @@
import { Connection, Edge, Elements, Node, NodeExtent, GraphNode, XYPosition, NextElements, FlowElement } from '~/types'
export default () =>
useWebWorkerFn((elements: Elements, nodes: GraphNode[], edges: Edge[], nodeExtent: NodeExtent): NextElements => {
const clamp = (val: number, min = 0, max = 1): number => Math.min(Math.max(val, min), max)
const clampPosition = (position: XYPosition, extent: NodeExtent): XYPosition => ({
x: clamp(position.x, extent[0][0], extent[1][0]),
y: clamp(position.y, extent[0][1], extent[1][1]),
})
const parseNode = (node: Node, nodeExtent: NodeExtent): GraphNode =>
Object.assign(node as GraphNode, {
id: node.id.toString(),
type: node.type || 'default',
__vf: {
position: clampPosition(node.position, nodeExtent),
width: 0,
height: 0,
handleBounds: {},
isDragging: false,
},
})
const parseEdge = (edge: Edge): Edge =>
Object.assign(edge, {
source: edge.source.toString(),
target: edge.target.toString(),
sourceHandle: edge.sourceHandle ? edge.sourceHandle.toString() : null,
targetHandle: edge.targetHandle ? edge.targetHandle.toString() : null,
id: edge.id.toString(),
type: edge.type || 'default',
})
const isEdge = (element: Node | FlowElement | Connection): element is Edge =>
'id' in element && 'source' in element && 'target' in element
const isNode = (element: Node | FlowElement | Connection): element is Node =>
'id' in element && !('source' in element) && !('target' in element)
const nextElements: NextElements = {
nextNodes: [],
nextEdges: [],
}
for (const element of elements) {
if (isNode(element)) {
const storeNode = nodes[nodes.map((x) => x.id).indexOf(element.id)]
if (storeNode) {
const updatedNode = Object.assign(storeNode, element)
updatedNode.__vf!.position = element.position
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
// When the type of a node changes it is possible that the number or positions of handles changes too.
updatedNode.__vf!.width = 0
}
nextElements.nextNodes.push(updatedNode)
} else {
nextElements.nextNodes.push(parseNode(element, nodeExtent))
}
} else if (isEdge(element)) {
const storeEdge = edges[edges.map((x) => x.id).indexOf(element.id)]
if (storeEdge) {
nextElements.nextEdges.push(Object.assign(storeEdge, element))
} else {
nextElements.nextEdges.push(parseEdge(element))
}
}
}
return nextElements
})