fix: edge anchor
This commit is contained in:
@@ -25,11 +25,13 @@ const sourceHandleStyleB: CSSProperties = { ...targetHandleStyle, bottom: '10px'
|
|||||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params)
|
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Handle type="target" :position="Position.Left" :style="targetHandleStyle" :on-connect="onConnect" />
|
<div class="revue-flow__node-color-selector">
|
||||||
<div>
|
<Handle type="target" :position="Position.Left" :style="targetHandleStyle" :on-connect="onConnect" />
|
||||||
Custom Color Picker Node: <strong>{{ data.color }}</strong>
|
<div>
|
||||||
|
Custom Color Picker Node: <strong>{{ data.color }}</strong>
|
||||||
|
</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>
|
</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" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -47,9 +47,7 @@ onMounted(() => {
|
|||||||
if (isEdge(e) || e.id !== '2') {
|
if (isEdge(e) || e.id !== '2') {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = (event.target as HTMLInputElement).value
|
const color = (event.target as HTMLInputElement).value
|
||||||
|
|
||||||
bgColor.value = color
|
bgColor.value = color
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -87,7 +87,9 @@ const onEdgeUpdaterTargetMouseDown = (event: MouseEvent) => {
|
|||||||
|
|
||||||
const updating = ref<boolean>(false)
|
const updating = ref<boolean>(false)
|
||||||
const onEdgeUpdaterMouseEnter = () => (updating.value = true)
|
const onEdgeUpdaterMouseEnter = () => (updating.value = true)
|
||||||
|
|
||||||
const onEdgeUpdaterMouseOut = () => (updating.value = false)
|
const onEdgeUpdaterMouseOut = () => (updating.value = false)
|
||||||
|
|
||||||
const isVisible = ({ sourceX, sourceY, targetX, targetY }: ReturnType<typeof getEdgePositions>) => {
|
const isVisible = ({ sourceX, sourceY, targetX, targetY }: ReturnType<typeof getEdgePositions>) => {
|
||||||
return store.onlyRenderVisibleElements
|
return store.onlyRenderVisibleElements
|
||||||
? isEdgeVisible({
|
? isEdgeVisible({
|
||||||
@@ -99,14 +101,14 @@ const isVisible = ({ sourceX, sourceY, targetX, targetY }: ReturnType<typeof get
|
|||||||
})
|
})
|
||||||
: true
|
: true
|
||||||
}
|
}
|
||||||
|
|
||||||
const edgePos = computed(() =>
|
const edgePos = computed(() =>
|
||||||
getEdgePositions(props.nodes.sourceNode, sourceHandle, sourcePosition, props.nodes.targetNode, targetHandle, targetPosition),
|
getEdgePositions(props.nodes.sourceNode, sourceHandle, sourcePosition, props.nodes.targetNode, targetHandle, targetPosition),
|
||||||
)
|
)
|
||||||
const visible = computed(() => !props.edge.isHidden && isVisible(edgePos.value))
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<g
|
<g
|
||||||
v-if="visible"
|
v-if="!props.edge.isHidden && isVisible(edgePos)"
|
||||||
:class="[
|
:class="[
|
||||||
'revue-flow__edge',
|
'revue-flow__edge',
|
||||||
`revue-flow__edge-${props.type.name || 'default'}`,
|
`revue-flow__edge-${props.type.name || 'default'}`,
|
||||||
@@ -189,9 +191,9 @@ const visible = computed(() => !props.edge.isHidden && isVisible(edgePos.value))
|
|||||||
</g>
|
</g>
|
||||||
<g @mousedown="onEdgeUpdaterTargetMouseDown" @mouseenter="onEdgeUpdaterMouseEnter" @mouseout="onEdgeUpdaterMouseOut">
|
<g @mousedown="onEdgeUpdaterTargetMouseDown" @mouseenter="onEdgeUpdaterMouseEnter" @mouseout="onEdgeUpdaterMouseOut">
|
||||||
<EdgeAnchor
|
<EdgeAnchor
|
||||||
:position="sourcePosition"
|
:position="targetPosition"
|
||||||
:center-x="edgePos.sourceX"
|
:center-x="edgePos.targetX"
|
||||||
:center-y="edgePos.sourceY"
|
:center-y="edgePos.targetY"
|
||||||
:radius="props.edgeUpdaterRadius"
|
:radius="props.edgeUpdaterRadius"
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
|
|||||||
@@ -29,16 +29,12 @@ const selectedNodes = computed(() =>
|
|||||||
: [],
|
: [],
|
||||||
)
|
)
|
||||||
|
|
||||||
const style = computed(() => ({
|
const innerStyle = {
|
||||||
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const innerStyle = computed(() => ({
|
|
||||||
width: `${store.selectedNodesBbox.width}px`,
|
width: `${store.selectedNodesBbox.width}px`,
|
||||||
height: `${store.selectedNodesBbox.height}px`,
|
height: `${store.selectedNodesBbox.height}px`,
|
||||||
top: `${store.selectedNodesBbox.y}px`,
|
top: `${store.selectedNodesBbox.y}px`,
|
||||||
left: `${store.selectedNodesBbox.x}px`,
|
left: `${store.selectedNodesBbox.x}px`,
|
||||||
}))
|
}
|
||||||
|
|
||||||
const onStart: DraggableEventListener = ({ event }) => {
|
const onStart: DraggableEventListener = ({ event }) => {
|
||||||
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value })
|
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value })
|
||||||
@@ -73,7 +69,12 @@ const onContextMenu = (event: MouseEvent) => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="revue-flow__nodesselection" :style="style">
|
<div
|
||||||
|
class="revue-flow__nodesselection"
|
||||||
|
:style="{
|
||||||
|
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
<Draggable
|
<Draggable
|
||||||
:scale="store.transform[2]"
|
:scale="store.transform[2]"
|
||||||
:grid="store.snapToGrid ? store.snapGrid : undefined"
|
:grid="store.snapToGrid ? store.snapGrid : undefined"
|
||||||
|
|||||||
@@ -8,21 +8,15 @@ const el = templateRef('user-selection', null)
|
|||||||
|
|
||||||
const onMouseDown = (event: MouseEvent) => {
|
const onMouseDown = (event: MouseEvent) => {
|
||||||
const mousePos = getMousePosition(event)
|
const mousePos = getMousePosition(event)
|
||||||
if (!mousePos) {
|
if (!mousePos) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
store.setUserSelection(mousePos)
|
store.setUserSelection(mousePos)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMouseMove = (event: MouseEvent) => {
|
const onMouseMove = (event: MouseEvent) => {
|
||||||
if (!store.selectionActive) {
|
if (!store.selectionActive) return
|
||||||
return
|
|
||||||
}
|
|
||||||
const mousePos = getMousePosition(event)
|
const mousePos = getMousePosition(event)
|
||||||
if (!mousePos) {
|
if (!mousePos) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
store.updateUserSelection(mousePos)
|
store.updateUserSelection(mousePos)
|
||||||
}
|
}
|
||||||
@@ -41,17 +35,15 @@ useEventListener(el, 'mousemove', onMouseMove)
|
|||||||
useEventListener(el, 'click', onMouseUp)
|
useEventListener(el, 'click', onMouseUp)
|
||||||
useEventListener(el, 'mouseup', onMouseUp)
|
useEventListener(el, 'mouseup', onMouseUp)
|
||||||
useEventListener(el, 'mouseleave', onMouseLeave)
|
useEventListener(el, 'mouseleave', onMouseLeave)
|
||||||
|
|
||||||
const userSelectionRect = computed(() => store.userSelectionRect)
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div ref="user-selection" class="revue-flow__selectionpane">
|
<div ref="user-selection" class="revue-flow__selectionpane">
|
||||||
<SelectionRect
|
<SelectionRect
|
||||||
v-if="userSelectionRect.draw"
|
v-if="store.userSelectionRect.draw"
|
||||||
:width="userSelectionRect.width"
|
:width="store.userSelectionRect.width"
|
||||||
:height="userSelectionRect.height"
|
:height="store.userSelectionRect.height"
|
||||||
:x="userSelectionRect.x"
|
:x="store.userSelectionRect.x"
|
||||||
:y="userSelectionRect.y"
|
:y="store.userSelectionRect.y"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import { pointer, select } from 'd3-selection'
|
|||||||
import { Ref } from 'vue'
|
import { Ref } from 'vue'
|
||||||
import { get } from '@vueuse/core'
|
import { get } from '@vueuse/core'
|
||||||
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
||||||
import { clamp } from '~/utils'
|
import { clamp, onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils'
|
||||||
import useKeyPress from '~/composables/useKeyPress'
|
import useKeyPress from '~/composables/useKeyPress'
|
||||||
import { Hooks, Store } from '~/context'
|
import { Hooks, Store } from '~/context'
|
||||||
|
import { useZoomPanHelper } from '~/composables/index'
|
||||||
|
|
||||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||||
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
||||||
@@ -59,6 +60,18 @@ export default function (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZ
|
|||||||
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom)
|
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom)
|
||||||
d3z.transform(d3s, updatedTransform)
|
d3z.transform(d3s, updatedTransform)
|
||||||
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
|
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
|
||||||
|
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper(store)
|
||||||
|
hooks.load.trigger({
|
||||||
|
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||||
|
zoomIn,
|
||||||
|
zoomOut,
|
||||||
|
zoomTo,
|
||||||
|
setTransform,
|
||||||
|
project: onLoadProject(store),
|
||||||
|
getElements: onLoadGetElements(store),
|
||||||
|
toObject: onLoadToObject(store),
|
||||||
|
})
|
||||||
|
|
||||||
const applyZoomHandlers = () => {
|
const applyZoomHandlers = () => {
|
||||||
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
if (viewChanged(prevTransform.value, event.transform)) {
|
if (viewChanged(prevTransform.value, event.transform)) {
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import { Store } from '~/context'
|
|||||||
|
|
||||||
const DEFAULT_PADDING = 0.1
|
const DEFAULT_PADDING = 0.1
|
||||||
|
|
||||||
export default function (): UseZoomPanHelper {
|
export default function (store = inject(Store)!): UseZoomPanHelper {
|
||||||
const store = inject(Store)!
|
|
||||||
return {
|
return {
|
||||||
zoomIn: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1.2),
|
zoomIn: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1.2),
|
||||||
zoomOut: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1 / 1.2),
|
zoomOut: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1 / 1.2),
|
||||||
|
|||||||
@@ -37,21 +37,15 @@ const hooks = inject(Hooks)!
|
|||||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
||||||
const { transform } = useZoom(zoomPaneEl, props)
|
const { transform } = useZoom(zoomPaneEl, props)
|
||||||
const { width, height } = useElementBounding(zoomPaneEl)
|
const { width, height } = useElementBounding(zoomPaneEl)
|
||||||
watch(width, (val) => (store.dimensions.width = val), { flush: 'post' })
|
watch(width, (val) => (store.dimensions.width = val))
|
||||||
watch(height, (val) => (store.dimensions.height = val), { flush: 'post' })
|
watch(height, (val) => (store.dimensions.height = val))
|
||||||
watch(transform, (val) => (store.transform = val), { flush: 'post' })
|
watch(transform, (val) => (store.transform = val))
|
||||||
|
|
||||||
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
|
store.transform = transform.value
|
||||||
hooks.load.trigger({
|
store.dimensions = {
|
||||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
width: width.value,
|
||||||
zoomIn,
|
height: height.value,
|
||||||
zoomOut,
|
}
|
||||||
zoomTo,
|
|
||||||
setTransform,
|
|
||||||
project: onLoadProject(store),
|
|
||||||
getElements: onLoadGetElements(store),
|
|
||||||
toObject: onLoadToObject(store),
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
|
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
|
||||||
|
|||||||
Vendored
-15
@@ -1,15 +0,0 @@
|
|||||||
import Vue, { VNode } from 'vue'
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
namespace JSX {
|
|
||||||
// tslint:disable no-empty-interface
|
|
||||||
interface Element extends VNode {}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
interface ElementClass extends Vue {}
|
|
||||||
|
|
||||||
interface IntrinsicAttributes {
|
|
||||||
[prop: string]: any
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user