refactor: controlled computed in minimap
# What's changed? * Use controlled computed properties in Minimap to improve performance
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useZoomPanHelper, useVueFlow } from '../../composables'
|
import { useVueFlow } from '../../composables'
|
||||||
import type { ControlProps } from '../../types/components'
|
import type { ControlProps } from '../../types/components'
|
||||||
import ControlButton from './ControlButton.vue'
|
import ControlButton from './ControlButton.vue'
|
||||||
import PlusIcon from '~/assets/icons/plus.svg'
|
import PlusIcon from '~/assets/icons/plus.svg'
|
||||||
@@ -20,23 +20,22 @@ const emit = defineEmits<{
|
|||||||
(event: 'interaction-change', active: boolean): void
|
(event: 'interaction-change', active: boolean): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { store } = useVueFlow()
|
const { store, instance } = useVueFlow()
|
||||||
const { zoomIn, zoomOut, fitView } = useZoomPanHelper()
|
|
||||||
|
|
||||||
const isInteractive = computed(() => store.nodesDraggable && store.nodesConnectable && store.elementsSelectable)
|
const isInteractive = computed(() => store.nodesDraggable && store.nodesConnectable && store.elementsSelectable)
|
||||||
|
|
||||||
const onZoomInHandler = () => {
|
const onZoomInHandler = () => {
|
||||||
zoomIn()
|
instance.value?.zoomIn()
|
||||||
emit('zoom-in')
|
emit('zoom-in')
|
||||||
}
|
}
|
||||||
|
|
||||||
const onZoomOutHandler = () => {
|
const onZoomOutHandler = () => {
|
||||||
zoomOut()
|
instance.value?.zoomOut()
|
||||||
emit('zoom-out')
|
emit('zoom-out')
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFitViewHandler = () => {
|
const onFitViewHandler = () => {
|
||||||
fitView(props.fitViewParams)
|
instance.value?.fitView(props.fitViewParams)
|
||||||
emit('fit-view')
|
emit('fit-view')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,14 +33,18 @@ const nodeClassNameFunc =
|
|||||||
|
|
||||||
const shapeRendering: ShapeRendering = typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'
|
const shapeRendering: ShapeRendering = typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'
|
||||||
|
|
||||||
const bb = computed(() => getRectOfNodes(store.getNodes))
|
const bb = computed(() => {
|
||||||
const viewBB = computed(() => ({
|
return getRectOfNodes(store.getNodes)
|
||||||
|
})
|
||||||
|
|
||||||
|
const viewBB = controlledComputed(bb, () => ({
|
||||||
x: -store.viewport.x / store.viewport.zoom,
|
x: -store.viewport.x / store.viewport.zoom,
|
||||||
y: -store.viewport.y / store.viewport.zoom,
|
y: -store.viewport.y / store.viewport.zoom,
|
||||||
width: store.dimensions.width / store.viewport.zoom,
|
width: store.dimensions.width / store.viewport.zoom,
|
||||||
height: store.dimensions.height / store.viewport.zoom,
|
height: store.dimensions.height / store.viewport.zoom,
|
||||||
}))
|
}))
|
||||||
const viewBox = computed(() => {
|
|
||||||
|
const viewBox = controlledComputed(viewBB, () => {
|
||||||
const boundingRect = store.getNodes && store.getNodes.length ? getBoundsofRects(bb.value, viewBB.value) : viewBB.value
|
const boundingRect = store.getNodes && store.getNodes.length ? getBoundsofRects(bb.value, viewBB.value) : viewBB.value
|
||||||
const scaledWidth = boundingRect.width / elementWidth
|
const scaledWidth = boundingRect.width / elementWidth
|
||||||
const scaledHeight = boundingRect.height / elementHeight
|
const scaledHeight = boundingRect.height / elementHeight
|
||||||
@@ -57,7 +61,7 @@ const viewBox = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const d = computed(() => {
|
const d = controlledComputed(viewBox, () => {
|
||||||
if (viewBox.value.x && viewBox.value.y)
|
if (viewBox.value.x && viewBox.value.y)
|
||||||
return `
|
return `
|
||||||
M${viewBox.value.x - viewBox.value.offset},${viewBox.value.y - viewBox.value.offset}
|
M${viewBox.value.x - viewBox.value.offset},${viewBox.value.y - viewBox.value.offset}
|
||||||
@@ -78,6 +82,8 @@ const onNodeClick = (event: MouseEvent, node: GraphNode) => {
|
|||||||
const onNodeDblClick = (event: MouseEvent, node: GraphNode) => {
|
const onNodeDblClick = (event: MouseEvent, node: GraphNode) => {
|
||||||
store.hooks.miniMapNodeDoubleClick.trigger({ event, node })
|
store.hooks.miniMapNodeDoubleClick.trigger({ event, node })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRenderTriggered(console.log)
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
@@ -88,12 +94,32 @@ export default {
|
|||||||
<svg
|
<svg
|
||||||
:width="elementWidth"
|
:width="elementWidth"
|
||||||
:height="elementHeight"
|
:height="elementHeight"
|
||||||
:viewBox="`${viewBox.x || 0} ${viewBox.y || 0} ${viewBox.width || 0} ${viewBox.height || 0}`"
|
:viewBox="[viewBox.x, viewBox.y, viewBox.width, viewBox.height]"
|
||||||
class="vue-flow__minimap"
|
class="vue-flow__minimap"
|
||||||
>
|
>
|
||||||
<template v-for="node of store.getNodes" :key="`mini-map-node-${node.id}`">
|
<MiniMapNode
|
||||||
<MiniMapNode
|
v-for="node of store.getNodes"
|
||||||
|
:id="node.id"
|
||||||
|
:key="node.id"
|
||||||
|
v-memo="[node.computedPosition, node.dimensions]"
|
||||||
|
:position="node.computedPosition"
|
||||||
|
:dimensions="node.dimensions"
|
||||||
|
:style="node.style"
|
||||||
|
:class="nodeClassNameFunc(node)"
|
||||||
|
:color="nodeColorFunc(node)"
|
||||||
|
:border-radius="props.nodeBorderRadius"
|
||||||
|
:stroke-color="nodeStrokeColorFunc(node)"
|
||||||
|
:stroke-width="props.nodeStrokeWidth"
|
||||||
|
:shape-rendering="shapeRendering"
|
||||||
|
@click="(e) => onNodeClick(e, node)"
|
||||||
|
@dblclick="(e) => onNodeDblClick(e, node)"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
:id="node.id"
|
:id="node.id"
|
||||||
|
:name="`node-${node.type}`"
|
||||||
|
:parent-node="node.parentNode"
|
||||||
|
:selected="node.selected"
|
||||||
|
:dragging="node.dragging"
|
||||||
:position="node.computedPosition"
|
:position="node.computedPosition"
|
||||||
:dimensions="node.dimensions"
|
:dimensions="node.dimensions"
|
||||||
:style="node.style"
|
:style="node.style"
|
||||||
@@ -103,27 +129,8 @@ export default {
|
|||||||
:stroke-color="nodeStrokeColorFunc(node)"
|
:stroke-color="nodeStrokeColorFunc(node)"
|
||||||
:stroke-width="props.nodeStrokeWidth"
|
:stroke-width="props.nodeStrokeWidth"
|
||||||
:shape-rendering="shapeRendering"
|
:shape-rendering="shapeRendering"
|
||||||
@click="(e) => onNodeClick(e, node)"
|
/>
|
||||||
@dblclick="(e) => onNodeDblClick(e, node)"
|
</MiniMapNode>
|
||||||
>
|
|
||||||
<slot
|
|
||||||
:id="node.id"
|
|
||||||
:name="`node-${node.type}`"
|
|
||||||
:parent-node="node.parentNode"
|
|
||||||
:selected="node.selected"
|
|
||||||
:dragging="node.dragging"
|
|
||||||
:position="node.computedPosition"
|
|
||||||
:dimensions="node.dimensions"
|
|
||||||
:style="node.style"
|
|
||||||
:class="nodeClassNameFunc(node)"
|
|
||||||
:color="nodeColorFunc(node)"
|
|
||||||
:border-radius="props.nodeBorderRadius"
|
|
||||||
:stroke-color="nodeStrokeColorFunc(node)"
|
|
||||||
:stroke-width="props.nodeStrokeWidth"
|
|
||||||
:shape-rendering="shapeRendering"
|
|
||||||
/>
|
|
||||||
</MiniMapNode>
|
|
||||||
</template>
|
|
||||||
<path class="vue-flow__minimap-mask" :d="d" :fill="props.maskColor" fill-rule="evenodd" />
|
<path class="vue-flow__minimap-mask" :d="d" :fill="props.maskColor" fill-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user