fix: custom node example not fitting view

* fit view can't work (for the onLoad event) for elements assigned after the host has mounted (onMounted hook) as we can't calculate a rect of elements that don't exist at flow creation
* in this case just trigger fit view __after__ elements have been created/passed to the flow

Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Braks
2021-11-06 08:54:35 +01:00
parent a8f7cc2389
commit 5437d48325
5 changed files with 144 additions and 156 deletions
+49 -51
View File
@@ -43,60 +43,58 @@ const nodeColor = (n: Node): string => {
return '#fff' return '#fff'
} }
onMounted(() => { const onChange = (event: Event) => {
const onChange = (event: Event) => { elements.value = elements.value.map((e: FlowElement) => {
elements.value = elements.value.map((e: FlowElement) => { 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 {
...e, ...e,
data: { data: {
...e.data, ...e.data,
color, color,
}, },
} }
}) })
} }
elements.value = [ elements.value = [
{ {
id: '1', id: '1',
type: 'input', type: 'input',
data: { label: 'An input node' }, data: { label: 'An input node' },
position: { x: 0, y: 50 }, position: { x: 0, y: 50 },
sourcePosition: Position.Right, sourcePosition: Position.Right,
}, },
{ {
id: '2', id: '2',
type: 'selectorNode', type: 'selectorNode',
data: { onChange, color: bgColor.value }, data: { onChange, color: bgColor.value },
style: { border: '1px solid #777', padding: '10px' }, style: { border: '1px solid #777', padding: '10px' },
position: { x: 250, y: 50 }, position: { x: 250, y: 50 },
}, },
{ {
id: '3', id: '3',
type: 'output', type: 'output',
data: { label: 'Output A' }, data: { label: 'Output A' },
position: { x: 650, y: 25 }, position: { x: 650, y: 25 },
targetPosition: Position.Left, targetPosition: Position.Left,
}, },
{ {
id: '4', id: '4',
type: 'output', type: 'output',
data: { label: 'Output B' }, data: { label: 'Output B' },
position: { x: 650, y: 100 }, position: { x: 650, y: 100 },
targetPosition: Position.Left, targetPosition: Position.Left,
}, },
{ id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } }, { id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } }, { id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
{ id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } }, { id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } },
] ]
})
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value)) const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
-1
View File
@@ -27,7 +27,6 @@ const elements = ref<Elements>(initialElements)
const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, animated: true }, elements.value)) const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, animated: true }, elements.value))
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value)) const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
// todo changing elements not properly updating flowchart...
const onLayout = (direction: string) => { const onLayout = (direction: string) => {
const isHorizontal = direction === 'LR' const isHorizontal = direction === 'LR'
dagreGraph.setGraph({ rankdir: direction }) dagreGraph.setGraph({ rankdir: direction })
+3 -3
View File
@@ -23,9 +23,9 @@ export default (store = useStore()): UseZoomPanHelper => {
bounds, bounds,
store.dimensions.width, store.dimensions.width,
store.dimensions.height, store.dimensions.height,
options.minZoom || store.minZoom, options.minZoom ?? store.minZoom,
options.maxZoom || store.maxZoom, options.maxZoom ?? store.maxZoom,
options.padding || DEFAULT_PADDING, options.padding ?? DEFAULT_PADDING,
) )
const transform = zoomIdentity.translate(x, y).scale(zoom) const transform = zoomIdentity.translate(x, y).scale(zoom)
+91 -100
View File
@@ -69,122 +69,114 @@ until(zoomPaneEl)
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler }) store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k] store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k]
const applyZoomHandlers = () => { d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => { if (viewChanged(transform.value, event.transform)) {
if (viewChanged(transform.value, event.transform)) { const flowTransform = eventToFlowTransform(event.transform)
const flowTransform = eventToFlowTransform(event.transform) transform.value = flowTransform
transform.value = flowTransform
hooks.moveStart.trigger(flowTransform) hooks.moveStart.trigger(flowTransform)
} }
}) })
d3z.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => { d3z.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
if (viewChanged(transform.value, event.transform)) { if (viewChanged(transform.value, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform) const flowTransform = eventToFlowTransform(event.transform)
transform.value = flowTransform transform.value = flowTransform
hooks.moveEnd.trigger(flowTransform) hooks.moveEnd.trigger(flowTransform)
} }
}) })
useKeyPress(props.selectionKeyCode, (keyPress) => { useKeyPress(props.selectionKeyCode, (keyPress) => {
if (keyPress) { if (keyPress) {
d3z.on('zoom', null) d3z.on('zoom', null)
} else { } else {
d3z.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => { d3z.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
if (viewChanged(transform.value, event.transform)) { if (viewChanged(transform.value, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform) const flowTransform = eventToFlowTransform(event.transform)
transform.value = flowTransform transform.value = flowTransform
hooks.move.trigger(flowTransform) hooks.move.trigger(flowTransform)
}
})
}
})
useKeyPress(props.zoomActivationKeyCode, (keyPress) => {
if (props.panOnScroll && keyPress) {
d3s
?.on('wheel', (event: WheelEvent) => {
event.preventDefault()
event.stopImmediatePropagation()
const currentZoom = d3s?.property('__zoom').k || 1
if (event.ctrlKey && props.zoomOnPinch) {
const point = pointer(event)
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10
const zoom = currentZoom * Math.pow(2, pinchDelta)
if (d3s) d3z.scaleTo(d3s, zoom, point)
return
} }
// increase scroll speed in firefox
// firefox: deltaMode === 1; chrome: deltaMode === 0
const deltaNormalize = event.deltaMode === 1 ? 20 : 1
const deltaX = props.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize
const deltaY = props.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize
if (d3s && props.panOnScrollSpeed)
d3z?.translateBy(
d3s,
-(deltaX / currentZoom) * props.panOnScrollSpeed,
-(deltaY / currentZoom) * props.panOnScrollSpeed,
)
}) })
} .on('wheel.zoom', null)
}) } else if (typeof d3ZoomHandler !== 'undefined') {
d3s?.on('wheel', null).on('wheel.zoom', d3ZoomHandler)
}
})
useKeyPress(props.zoomActivationKeyCode, (keyPress) => { const keyPress = useKeyPress(props.selectionKeyCode)
if (props.panOnScroll && keyPress) { d3z.filter((event: MouseEvent) => {
d3s const zoomScroll = props.zoomOnScroll
?.on('wheel', (event: WheelEvent) => { const pinchZoom = props.zoomOnPinch && event.ctrlKey
event.preventDefault()
event.stopImmediatePropagation()
const currentZoom = d3s?.property('__zoom').k || 1 // if all interactions are disabled, we prevent all zoom events
if (!props.paneMoveable && !zoomScroll && !props.panOnScroll && !props.zoomOnDoubleClick && !props.zoomOnPinch) return false
if (event.ctrlKey && props.zoomOnPinch) { // during a selection we prevent all other interactions
const point = pointer(event) if (keyPress.value) return false
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10
const zoom = currentZoom * Math.pow(2, pinchDelta)
if (d3s) d3z.scaleTo(d3s, zoom, point)
return // if zoom on double click is disabled, we prevent the double click event
} if (!props.zoomOnDoubleClick && event.type === 'dblclick') return false
// increase scroll speed in firefox if ((event.target as Element).closest('.nowheel') && event.type === 'wheel') return false
// firefox: deltaMode === 1; chrome: deltaMode === 0
const deltaNormalize = event.deltaMode === 1 ? 20 : 1
const deltaX = props.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize
const deltaY = props.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize
if (d3s && props.panOnScrollSpeed) // when the target element is a node, we still allow zooming
d3z?.translateBy( if (
d3s, ((event.target as Element).closest('.vue-flow__node') || (event.target as Element).closest('.vue-flow__edge')) &&
-(deltaX / currentZoom) * props.panOnScrollSpeed, event.type !== 'wheel'
-(deltaY / currentZoom) * props.panOnScrollSpeed, )
) return false
})
.on('wheel.zoom', null)
} else if (typeof d3ZoomHandler !== 'undefined') {
d3s?.on('wheel', null).on('wheel.zoom', d3ZoomHandler)
}
})
}
const applyZoomFilter = () => { // when the target element is a node selection, we still allow zooming
const keyPress = useKeyPress(props.selectionKeyCode) if ((event.target as Element).closest('.vue-flow__nodesselection') && event.type !== 'wheel') return false
d3z.filter((event: MouseEvent) => {
const zoomScroll = props.zoomOnScroll
const pinchZoom = props.zoomOnPinch && event.ctrlKey
// if all interactions are disabled, we prevent all zoom events if (!props.zoomOnPinch && event.ctrlKey && event.type === 'wheel') return false
if (!props.paneMoveable && !zoomScroll && !props.panOnScroll && !props.zoomOnDoubleClick && !props.zoomOnPinch)
return false
// during a selection we prevent all other interactions // when there is no scroll handling enabled, we prevent all wheel events
if (keyPress.value) return false if (!zoomScroll && !props.panOnScroll && !pinchZoom && event.type === 'wheel') return false
// if zoom on double click is disabled, we prevent the double click event // if the pane is not movable, we prevent dragging it with mousestart or touchstart
if (!props.zoomOnDoubleClick && event.type === 'dblclick') return false if (!props.paneMoveable && (event.type === 'mousedown' || event.type === 'touchstart')) return false
if ((event.target as Element).closest('.nowheel') && event.type === 'wheel') return false // default filter for d3-zoom
return (!event.ctrlKey || event.type === 'wheel') && !event.button
// when the target element is a node, we still allow zooming })
if (
((event.target as Element).closest('.vue-flow__node') || (event.target as Element).closest('.vue-flow__edge')) &&
event.type !== 'wheel'
)
return false
// when the target element is a node selection, we still allow zooming
if ((event.target as Element).closest('.vue-flow__nodesselection') && event.type !== 'wheel') return false
if (!props.zoomOnPinch && event.ctrlKey && event.type === 'wheel') return false
// when there is no scroll handling enabled, we prevent all wheel events
if (!zoomScroll && !props.panOnScroll && !pinchZoom && event.type === 'wheel') return false
// if the pane is not movable, we prevent dragging it with mousestart or touchstart
if (!props.paneMoveable && (event.type === 'mousedown' || event.type === 'touchstart')) return false
// default filter for d3-zoom
return (!event.ctrlKey || event.type === 'wheel') && !event.button
})
}
applyZoomHandlers()
applyZoomFilter()
}) })
const { width, height } = useElementBounding(zoomPaneEl) const { width, height } = useElementBounding(zoomPaneEl)
@@ -197,9 +189,8 @@ watch(width, (val) => (store.dimensions.width = val))
watch(height, (val) => (store.dimensions.height = val)) watch(height, (val) => (store.dimensions.height = val))
watch(transform, (val) => (store.transform = [val.x, val.y, val.zoom])) watch(transform, (val) => (store.transform = [val.x, val.y, val.zoom]))
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
onMounted(() => { onMounted(() => {
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
watchOnce( watchOnce(
() => width.value && height.value, () => width.value && height.value,
() => { () => {
+1 -1
View File
@@ -222,7 +222,7 @@ export const getRectOfNodes = (nodes: Node[]): Rect => {
...position, ...position,
width, width,
height, height,
} as any), }),
), ),
{ x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity }, { x: Infinity, y: Infinity, x2: -Infinity, y2: -Infinity },
) )