feat(utils): add vanilla drag and panzoom (#3108)
* refactor(panzoom): create vanilla helper * feat(svelte): add interaction example * refactor(panzoom): cleanup * Update function-runner.ts * refactor(panzoom): cleanup * refactor(panzoom): rename functions * feat(utils): add vanilla drag helper (#3107) * feat(utils): add vanilla drag helper * refactor(drag): cleanup * refactor(drag): cleanup * chore(packages): cleanup * refactor(panzoom): cleanup and simplify
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
selectionRectMode,
|
||||
selectionKeyPressed,
|
||||
selectionMode,
|
||||
resetSelectedElements,
|
||||
unselectNodesAndEdges,
|
||||
} = useStore();
|
||||
|
||||
let container: HTMLDivElement;
|
||||
@@ -61,7 +61,7 @@
|
||||
function onClick(event: MouseEvent) {
|
||||
dispatch('pane:click', event);
|
||||
|
||||
resetSelectedElements();
|
||||
unselectNodesAndEdges();
|
||||
selectionRectMode.set(null);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
const { x, y } = getEventPosition(event, containerBounds);
|
||||
|
||||
resetSelectedElements();
|
||||
unselectNodesAndEdges();
|
||||
|
||||
selectionRect.set({
|
||||
width: 0,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import cc from 'classcat';
|
||||
import { PanOnScrollMode, type CoordinateExtent, type Viewport } from '@reactflow/system';
|
||||
|
||||
import { Zoom } from '$lib/container/Zoom';
|
||||
import { Pane } from '$lib/container/Pane';
|
||||
import { Viewport } from '$lib/container/Viewport';
|
||||
import { Viewport as ViewportComponent } from '$lib/container/Viewport';
|
||||
import { NodeRenderer } from '$lib/container/NodeRenderer';
|
||||
import { EdgeRenderer } from '$lib/container/EdgeRenderer';
|
||||
import { UserSelection } from '$lib/components/UserSelection';
|
||||
@@ -14,6 +15,7 @@
|
||||
import { Attribution } from '$lib/components/Attribution';
|
||||
import { useStore } from '$lib/store';
|
||||
import type { SvelteFlowProps } from './types';
|
||||
import type { EdgeTypes, NodeTypes } from '$lib/types';
|
||||
|
||||
type $$Props = SvelteFlowProps;
|
||||
|
||||
@@ -21,7 +23,7 @@
|
||||
export let fitView: $$Props['fitView'] = undefined;
|
||||
export let minZoom: $$Props['minZoom'] = undefined;
|
||||
export let maxZoom: $$Props['maxZoom'] = undefined;
|
||||
export let initialViewport: $$Props['initialViewport'] = undefined;
|
||||
export let initialViewport: Viewport = { x:0, y: 0, zoom: 1 };
|
||||
export let nodeTypes: $$Props['nodeTypes'] = undefined;
|
||||
export let edgeTypes: $$Props['edgeTypes'] = undefined;
|
||||
export let selectionKey: $$Props['selectionKey'] = undefined;
|
||||
@@ -37,6 +39,15 @@
|
||||
export let onMove: $$Props['onMove'] = undefined;
|
||||
export let onMoveEnd: $$Props['onMoveEnd'] = undefined;
|
||||
export let isValidConnection: $$Props['isValidConnection'] = undefined;
|
||||
export let translateExtent: $$Props['translateExtent'] = undefined;
|
||||
export let panOnScrollMode: PanOnScrollMode = PanOnScrollMode.Free;
|
||||
export let preventScrolling: boolean = true;
|
||||
export let zoomOnScroll: boolean = true;
|
||||
export let zoomOnDoubleClick: boolean = true;
|
||||
export let zoomOnPinch: boolean = true;
|
||||
export let panOnScroll: boolean = false;
|
||||
export let panOnDrag: boolean | number[] = true;
|
||||
|
||||
export let defaultMarkerColor = '#b1b1b7';
|
||||
|
||||
export let style: $$Props['style'] = undefined;
|
||||
@@ -53,6 +64,15 @@
|
||||
store.height.set(height);
|
||||
store.domNode.set(domNode);
|
||||
|
||||
updateStore({
|
||||
nodeTypes,
|
||||
edgeTypes,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
translateExtent,
|
||||
fitView
|
||||
});
|
||||
|
||||
return () => {
|
||||
store.reset();
|
||||
}
|
||||
@@ -81,7 +101,14 @@
|
||||
})
|
||||
}
|
||||
|
||||
$: {
|
||||
function updateStore({ nodeTypes, edgeTypes, minZoom, maxZoom, translateExtent, fitView }: {
|
||||
nodeTypes?: NodeTypes,
|
||||
edgeTypes?: EdgeTypes,
|
||||
minZoom?: number,
|
||||
maxZoom?: number,
|
||||
translateExtent?: CoordinateExtent,
|
||||
fitView?: boolean
|
||||
}) {
|
||||
if (nodeTypes !== undefined) {
|
||||
store.setNodeTypes(nodeTypes);
|
||||
}
|
||||
@@ -98,10 +125,23 @@
|
||||
store.setMaxZoom(maxZoom);
|
||||
}
|
||||
|
||||
if (translateExtent !== undefined) {
|
||||
store.setTranslateExtent(translateExtent)
|
||||
}
|
||||
|
||||
if (fitView !== undefined) {
|
||||
store.fitViewOnInit.set(fitView);
|
||||
}
|
||||
}
|
||||
|
||||
$: updateStore({
|
||||
nodeTypes,
|
||||
edgeTypes,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
translateExtent,
|
||||
fitView
|
||||
})
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -114,9 +154,21 @@
|
||||
{...$$restProps}
|
||||
>
|
||||
<KeyHandler {selectionKey} {deleteKey} />
|
||||
<Zoom {initialViewport} {onMoveStart} {onMove} {onMoveEnd}>
|
||||
<Zoom
|
||||
{initialViewport}
|
||||
{onMoveStart}
|
||||
{onMove}
|
||||
{onMoveEnd}
|
||||
{panOnScrollMode}
|
||||
{preventScrolling}
|
||||
{zoomOnScroll}
|
||||
{zoomOnDoubleClick}
|
||||
{zoomOnPinch}
|
||||
{panOnScroll}
|
||||
{panOnDrag}
|
||||
>
|
||||
<Pane on:pane:click>
|
||||
<Viewport>
|
||||
<ViewportComponent>
|
||||
<EdgeRenderer on:edge:click />
|
||||
<ConnectionLine />
|
||||
<div class="svelte-flow__edgelabel-renderer" />
|
||||
@@ -130,7 +182,7 @@
|
||||
on:connect:end
|
||||
/>
|
||||
<NodeSelection />
|
||||
</Viewport>
|
||||
</ViewportComponent>
|
||||
<UserSelection />
|
||||
</Pane>
|
||||
</Zoom>
|
||||
|
||||
@@ -9,7 +9,9 @@ import type {
|
||||
SnapGrid,
|
||||
OnMoveStart,
|
||||
OnMove,
|
||||
OnMoveEnd
|
||||
OnMoveEnd,
|
||||
CoordinateExtent,
|
||||
PanOnScrollMode
|
||||
} from '@reactflow/system';
|
||||
|
||||
import type {
|
||||
@@ -39,6 +41,14 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
||||
nodesDraggable?: boolean;
|
||||
nodesConnectable?: boolean;
|
||||
elementsSelectable?: boolean;
|
||||
translateExtent?: CoordinateExtent;
|
||||
panOnScrollMode?: PanOnScrollMode;
|
||||
preventScrolling?: boolean;
|
||||
zoomOnScroll?: boolean;
|
||||
zoomOnDoubleClick?: boolean;
|
||||
zoomOnPinch?: boolean;
|
||||
panOnScroll?: boolean;
|
||||
panOnDrag?: boolean | number[];
|
||||
|
||||
class?: string;
|
||||
style?: string;
|
||||
|
||||
@@ -1,32 +1,60 @@
|
||||
<script lang="ts">
|
||||
import { PanOnScrollMode } from '@reactflow/system';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import zoom from '$lib/actions/zoom';
|
||||
import type { ZoomProps } from './types';
|
||||
|
||||
type $$Props = ZoomProps;
|
||||
|
||||
export let initialViewport: $$Props['initialViewport'] = undefined;
|
||||
export let initialViewport: $$Props['initialViewport'];
|
||||
export let onMoveStart: $$Props['onMoveStart'] = undefined;
|
||||
export let onMove: $$Props['onMove'] = undefined;
|
||||
export let onMoveEnd: $$Props['onMoveEnd'] = undefined;
|
||||
export let panOnScrollMode: $$Props['panOnScrollMode'];
|
||||
export let preventScrolling: $$Props['preventScrolling'];;
|
||||
export let zoomOnScroll: $$Props['zoomOnScroll'];;
|
||||
export let zoomOnDoubleClick: $$Props['zoomOnDoubleClick'];;
|
||||
export let zoomOnPinch: $$Props['zoomOnPinch'];;
|
||||
export let panOnDrag: $$Props['panOnDrag'];
|
||||
export let panOnScroll: $$Props['panOnScroll'];;
|
||||
|
||||
const { transform, d3, selectionKeyPressed, selectionRectMode, minZoom, maxZoom, dragging } = useStore();
|
||||
const {
|
||||
transform,
|
||||
panZoom,
|
||||
selectionKeyPressed,
|
||||
minZoom,
|
||||
maxZoom,
|
||||
dragging,
|
||||
translateExtent
|
||||
} = useStore();
|
||||
|
||||
$: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 };
|
||||
$: selecting = $selectionKeyPressed || $selectionRectMode === 'user';
|
||||
</script>
|
||||
|
||||
<div class="svelte-flow__zoom" use:zoom={{
|
||||
transform,
|
||||
d3,
|
||||
selecting,
|
||||
minZoom: $minZoom,
|
||||
maxZoom: $maxZoom,
|
||||
initialViewport: viewPort,
|
||||
dragging,
|
||||
onMoveStart,
|
||||
onMove,
|
||||
onMoveEnd
|
||||
panZoom,
|
||||
onPanZoomStart: onMoveStart,
|
||||
onPanZoom: onMove,
|
||||
onPanZoomEnd: onMoveEnd,
|
||||
zoomOnScroll,
|
||||
zoomOnDoubleClick,
|
||||
zoomOnPinch,
|
||||
panOnScroll,
|
||||
panOnDrag,
|
||||
panOnScrollSpeed: 0.5,
|
||||
panOnScrollMode: panOnScrollMode || PanOnScrollMode.Free,
|
||||
zoomActivationKeyPressed: false,
|
||||
preventScrolling: typeof preventScrolling === 'boolean' ? preventScrolling : true,
|
||||
noPanClassName: 'nopan',
|
||||
noWheelClassName: 'nowheel',
|
||||
userSelectionActive: $selectionKeyPressed,
|
||||
translateExtent: $translateExtent
|
||||
}}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import type { OnMove, OnMoveStart, OnMoveEnd, Viewport } from '@reactflow/system';
|
||||
import type { OnMoveStart, OnMove, OnMoveEnd, PanOnScrollMode, Viewport } from '@reactflow/system';
|
||||
|
||||
export type ZoomProps = {
|
||||
initialViewport?: Viewport;
|
||||
initialViewport: Viewport;
|
||||
panOnScrollMode: PanOnScrollMode;
|
||||
onMove?: OnMove;
|
||||
onMoveStart?: OnMoveStart;
|
||||
onMoveEnd?: OnMoveEnd;
|
||||
preventScrolling: boolean;
|
||||
zoomOnScroll: boolean;
|
||||
zoomOnDoubleClick: boolean;
|
||||
zoomOnPinch: boolean;
|
||||
panOnScroll: boolean;
|
||||
panOnDrag: boolean | number[];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user