fix: edge anchor

This commit is contained in:
Braks
2021-10-20 22:39:54 +02:00
parent 8c54daedc0
commit 7ecbcba7eb
9 changed files with 54 additions and 68 deletions
+8 -6
View File
@@ -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>
-2
View File
@@ -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 {
+7 -5
View File
@@ -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 -16
View File
@@ -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>
+14 -1
View File
@@ -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)) {
+1 -2
View File
@@ -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),
+8 -14
View File
@@ -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">
-15
View File
@@ -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
}
}
}