refactor(core,edges): add div based edge label renderer

This commit is contained in:
braks
2022-11-04 22:10:40 +01:00
committed by Braks
parent 0f2bc10fd2
commit 43ff2a42e6
10 changed files with 168 additions and 107 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@vue-flow/core': patch
---
Teleport edge labels into separate svg container (fixes edges overlapping edge labels)
@@ -0,0 +1,23 @@
<script lang="ts" setup>
import { useVueFlow } from '../../composables'
const { viewportRef } = useVueFlow()
const teleportTarget = $computed(() => viewportRef.value?.getElementsByClassName('vue-flow__edge-labels')[0])
</script>
<script lang="ts">
export default {
name: 'EdgeLabelRenderer',
}
</script>
<template>
<svg>
<foreignObject height="0" width="0">
<Teleport :to="teleportTarget" :disabled="!teleportTarget">
<slot />
</Teleport>
</foreignObject>
</svg>
</template>
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { isString } from '@vueuse/core'
import type { EdgeTextProps } from '../../types/components'
import type { Rect as RectType } from '../../types'
@@ -55,10 +56,8 @@ export default {
/>
<text v-bind="$attrs" ref="el" class="vue-flow__edge-text" :y="box.height / 2" dy="0.3em" :style="labelStyle">
<slot>
<component :is="label" v-if="typeof label !== 'string' && typeof label" />
<template v-else>
{{ label }}
</template>
<component :is="label" v-if="!isString(label)" />
<template v-else> {{ label }} </template>
</slot>
</text>
</g>
@@ -7,3 +7,4 @@ export { default as StraightEdge } from './StraightEdge'
export { default as EdgeAnchor } from './EdgeAnchor'
export { default as EdgeText } from './EdgeText.vue'
export { default as EdgeWrapper } from './Wrapper'
export { default as EdgeLabelRenderer } from './EdgeLabelRenderer.vue'
@@ -127,7 +127,8 @@ export default {
</script>
<template>
<svg v-for="group of groups" :key="group.level" class="vue-flow__edges vue-flow__container" :style="`z-index: ${group.level}`">
<template v-for="group of groups" :key="group.level">
<svg class="vue-flow__edges vue-flow__container" :style="`z-index: ${group.level}`">
<MarkerDefinitions v-if="group.isMaxLevel" />
<g>
<EdgeWrapper
@@ -145,6 +146,8 @@ export default {
/>
</g>
</svg>
</template>
<svg v-if="connectionLineVisible && !!sourceNode" class="vue-flow__edges vue-flow__connectionline vue-flow__container">
<ConnectionLine :source-node="sourceNode" />
</svg>
@@ -53,6 +53,9 @@ export default {
:style="{ transform: `translate(${viewport.x}px,${viewport.y}px) scale(${viewport.zoom})`, opacity: ready ? undefined : 0 }"
>
<EdgeRenderer />
<div class="vue-flow__edge-labels" />
<NodeRenderer />
<slot />
</div>
+10 -1
View File
@@ -7,7 +7,16 @@ export { default as VueFlow } from './container/VueFlow/VueFlow.vue'
export { default as Handle } from './components/Handle/Handle.vue'
export { StraightEdge, StepEdge, BezierEdge, SimpleBezierEdge, SmoothStepEdge, BaseEdge, EdgeText } from './components/Edges'
export {
StraightEdge,
StepEdge,
BezierEdge,
SimpleBezierEdge,
SmoothStepEdge,
BaseEdge,
EdgeText,
EdgeLabelRenderer,
} from './components/Edges'
export { getBezierPath, getSimpleBezierPath, getSmoothStepPath, getStraightPath } from './components/Edges/utils'
+7
View File
@@ -39,6 +39,13 @@
z-index: 5;
}
.vue-flow__edge-labels {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
}
.vue-flow__nodesselection-rect:focus,
.vue-flow__nodesselection-rect:focus-visible {
outline: none;
+1 -1
View File
@@ -106,7 +106,7 @@ export const parseEdge = (edge: Edge, defaults?: Partial<GraphEdge>): GraphEdge
selectable: edge.selectable,
data: shallowReactive(edge.data || {}),
events: shallowReactive(edge.events || {}),
label: edge.label && !isString(edge.label) ? markRaw(edge.label) : undefined,
label: edge.label && !isString(edge.label) ? markRaw(edge.label) : edge.label,
...defaults,
} as GraphEdge)
: defaults
+36 -25
View File
@@ -17,7 +17,7 @@
z-index: 1;
cursor: grab;
&.dragging {
&.dragging {
cursor: grabbing;
}
}
@@ -36,6 +36,13 @@
z-index: 5;
}
.vue-flow__edge-labels {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
}
.vue-flow__nodesselection-rect:focus,
.vue-flow__nodesselection-rect:focus-visible {
outline: none;
@@ -57,36 +64,36 @@
pointer-events: visibleStroke;
cursor: pointer;
&.animated path {
&.animated path {
stroke-dasharray: 5;
animation: dashdraw 0.5s linear infinite;
}
&.inactive {
&.inactive {
pointer-events: none;
}
&.selected,
&:focus,
&:focus-visible {
&.selected,
&:focus,
&:focus-visible {
outline: none;
}
&.selected .vue-flow__edge-path,
&:focus .vue-flow__edge-path,
&:focus-visible .vue-flow__edge-path {
&.selected .vue-flow__edge-path,
&:focus .vue-flow__edge-path,
&:focus-visible .vue-flow__edge-path {
stroke: #555;
}
&-textwrapper {
&-textwrapper {
pointer-events: all;
}
&-textbg {
&-textbg {
fill: white;
}
.vue-flow__edge-text {
&-text {
pointer-events: none;
user-select: none;
}
@@ -95,7 +102,7 @@
.vue-flow__connection {
pointer-events: none;
&.animated {
&.animated {
stroke-dasharray: 5;
animation: dashdraw 0.5s linear infinite;
}
@@ -118,7 +125,7 @@
box-sizing: border-box;
cursor: grab;
&.dragging {
&.dragging {
cursor: grabbing;
}
}
@@ -128,12 +135,16 @@
transform-origin: left top;
pointer-events: none;
&-rect {
&-rect {
position: absolute;
pointer-events: all;
cursor: grab;
&.dragging {
cursor: grabbing;
}
}
}
.vue-flow__handle {
position: absolute;
@@ -141,31 +152,31 @@
min-width: 5px;
min-height: 5px;
&.connectable {
&.connectable {
pointer-events: all;
cursor: crosshair;
}
&-bottom {
&-bottom {
top: auto;
left: 50%;
bottom: -4px;
transform: translate(-50%, 0);
}
&-top {
&-top {
left: 50%;
top: -4px;
transform: translate(-50%, 0);
}
&-left {
&-left {
top: 50%;
left: -4px;
transform: translate(0, -50%);
}
&-right {
&-right {
right: -4px;
top: 50%;
transform: translate(0, -50%);
@@ -182,23 +193,23 @@
z-index: 5;
margin: 15px;
&.top {
&.top {
top: 0;
}
&.bottom {
&.bottom {
bottom: 0;
}
&.left {
&.left {
left: 0;
}
&.right {
&.right {
right: 0;
}
&.center {
&.center {
left: 50%;
transform: translateX(-50%);
}