fix: inject store instance components

chore: update revue-draggable to next tag
This commit is contained in:
Braks
2021-07-20 20:01:10 +02:00
parent 8cfbc89d23
commit b4fcab4004
15 changed files with 152 additions and 140 deletions
+2 -1
View File
@@ -2,8 +2,9 @@ import { createApp } from 'vue';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import { router } from './router'; import { router } from './router';
import { DraggablePlugin } from '@braks/revue-draggable';
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';
import { DraggablePlugin } from '@braks/revue-draggable';
const app = createApp(App); const app = createApp(App);
app.config.performance = true; app.config.performance = true;
+1 -1
View File
@@ -28,7 +28,7 @@
"lint": "yarn lint:js" "lint": "yarn lint:js"
}, },
"dependencies": { "dependencies": {
"@braks/revue-draggable": "^0.1.13", "@braks/revue-draggable": "^0.2.1-5",
"@types/d3": "^7.0.0", "@types/d3": "^7.0.0",
"d3": "^7.0.0", "d3": "^7.0.0",
"d3-selection": "^3.0.0", "d3-selection": "^3.0.0",
+10 -11
View File
@@ -1,7 +1,6 @@
import { BackgroundVariant } from '../../types'; import { BackgroundVariant, RevueFlowStore } from '../../types';
import { createGridDotsPath, createGridLinesPath } from './utils'; import { createGridDotsPath, createGridLinesPath } from './utils';
import { computed, defineComponent, HTMLAttributes, PropType } from 'vue'; import { computed, defineComponent, HTMLAttributes, inject, PropType } from 'vue';
import store from '../../store';
export interface BackgroundProps extends HTMLAttributes { export interface BackgroundProps extends HTMLAttributes {
variant?: BackgroundVariant; variant?: BackgroundVariant;
@@ -26,7 +25,7 @@ const Background = defineComponent({
gap: { gap: {
type: Number as PropType<BackgroundProps['gap']>, type: Number as PropType<BackgroundProps['gap']>,
required: false, required: false,
default: 15 default: 10
}, },
color: { color: {
type: String as PropType<BackgroundProps['color']>, type: String as PropType<BackgroundProps['color']>,
@@ -40,8 +39,8 @@ const Background = defineComponent({
} }
}, },
setup(props) { setup(props) {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const transform = computed(() => pinia.transform); const transform = computed(() => store.transform);
// when there are multiple flows on a page we need to make sure that every background gets its own pattern. // when there are multiple flows on a page we need to make sure that every background gets its own pattern.
const patternId = `pattern-${Math.floor(Math.random() * 100000)}`; const patternId = `pattern-${Math.floor(Math.random() * 100000)}`;
@@ -50,12 +49,12 @@ const Background = defineComponent({
const xOffset = computed(() => scaledGap.value && transform.value[0] % scaledGap.value); const xOffset = computed(() => scaledGap.value && transform.value[0] % scaledGap.value);
const yOffset = computed(() => scaledGap.value && transform.value[1] % scaledGap.value); const yOffset = computed(() => scaledGap.value && transform.value[1] % scaledGap.value);
const isLines = props.variant === BackgroundVariant.Lines; const isLines = computed(() => props.variant === BackgroundVariant.Lines);
const bgColor = props.color ? props.color : defaultColors[props.variant || BackgroundVariant.Dots]; const bgColor = computed(() => (props.color ? props.color : defaultColors[props.variant || BackgroundVariant.Dots]));
const path = computed(() => const path = computed(() =>
isLines isLines.value
? scaledGap.value && props.size && createGridLinesPath(scaledGap.value, props.size, bgColor) ? scaledGap.value && props.size && createGridLinesPath(scaledGap.value, props.size, bgColor.value)
: createGridDotsPath(props.size || 0.4 * transform.value[2], bgColor) : createGridDotsPath(props.size || 0.4 * transform.value[2], bgColor.value)
); );
return () => ( return () => (
+5 -6
View File
@@ -1,7 +1,6 @@
import { defineComponent, HTMLAttributes, onMounted, PropType, ref } from 'vue'; import { defineComponent, HTMLAttributes, inject, onMounted, PropType, ref } from 'vue';
import useZoomPanHelper from '../../hooks/useZoomPanHelper'; import useZoomPanHelper from '../../hooks/useZoomPanHelper';
import { FitViewParams } from '../../types'; import { FitViewParams, RevueFlowStore } from '../../types';
import store from '../../store';
import PlusIcon from '../../../assets/icons/plus.svg'; import PlusIcon from '../../../assets/icons/plus.svg';
import MinusIcon from '../../../assets/icons/minus.svg'; import MinusIcon from '../../../assets/icons/minus.svg';
import Fitview from '../../../assets/icons/fitview.svg'; import Fitview from '../../../assets/icons/fitview.svg';
@@ -88,7 +87,7 @@ const Controls = defineComponent({
} }
}, },
setup(props, { slots }) { setup(props, { slots }) {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const isVisible = ref<boolean>(false); const isVisible = ref<boolean>(false);
const zoomHelper = ref(useZoomPanHelper()); const zoomHelper = ref(useZoomPanHelper());
@@ -96,7 +95,7 @@ const Controls = defineComponent({
zoomHelper.value = useZoomPanHelper(); zoomHelper.value = useZoomPanHelper();
}); });
const isInteractive = pinia.nodesDraggable && pinia.nodesConnectable && pinia.elementsSelectable; const isInteractive = store.nodesDraggable && store.nodesConnectable && store.elementsSelectable;
const mapClasses = ['revue-flow__controls']; const mapClasses = ['revue-flow__controls'];
const onZoomInHandler = () => { const onZoomInHandler = () => {
@@ -115,7 +114,7 @@ const Controls = defineComponent({
}; };
const onInteractiveChangeHandler = () => { const onInteractiveChangeHandler = () => {
pinia.setInteractive?.(!isInteractive); store.setInteractive?.(!isInteractive);
props.onInteractiveChange?.(!isInteractive); props.onInteractiveChange?.(!isInteractive);
}; };
+9 -10
View File
@@ -1,8 +1,7 @@
import { getRectOfNodes, getBoundsofRects } from '../../utils/graph'; import { getRectOfNodes, getBoundsofRects } from '../../utils/graph';
import { Node, Rect } from '../../types'; import { Node, Rect, RevueFlowStore } from '../../types';
import MiniMapNode from './MiniMapNode'; import MiniMapNode from './MiniMapNode';
import { computed, defineComponent, HTMLAttributes, PropType } from 'vue'; import { computed, defineComponent, HTMLAttributes, inject, PropType } from 'vue';
import store from '../../store';
type StringFunc = (node: Node) => string; type StringFunc = (node: Node) => string;
@@ -55,8 +54,8 @@ const MiniMap = defineComponent({
} }
}, },
setup(props, { attrs }: { attrs: Record<string, any> }) { setup(props, { attrs }: { attrs: Record<string, any> }) {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const transform = computed(() => pinia.transform); const transform = computed(() => store.transform);
const elementWidth = computed(() => (attrs.style?.width || defaultWidth)! as number); const elementWidth = computed(() => (attrs.style?.width || defaultWidth)! as number);
const elementHeight = computed(() => (attrs.style?.height || defaultHeight)! as number); const elementHeight = computed(() => (attrs.style?.height || defaultHeight)! as number);
const nodeColorFunc = computed(() => (props.nodeColor instanceof Function ? props.nodeColor : () => props.nodeColor) as StringFunc); const nodeColorFunc = computed(() => (props.nodeColor instanceof Function ? props.nodeColor : () => props.nodeColor) as StringFunc);
@@ -66,13 +65,13 @@ const MiniMap = defineComponent({
const nodeClassNameFunc = computed( const nodeClassNameFunc = computed(
() => (props.nodeClassName instanceof Function ? props.nodeClassName : () => props.nodeClassName) as StringFunc () => (props.nodeClassName instanceof Function ? props.nodeClassName : () => props.nodeClassName) as StringFunc
); );
const hasNodes = computed(() => pinia.nodes && pinia.nodes.length); const hasNodes = computed(() => store.nodes && store.nodes.length);
const bb = computed(() => getRectOfNodes(pinia.nodes)); const bb = computed(() => getRectOfNodes(store.nodes));
const viewBB = computed<Rect>(() => ({ const viewBB = computed<Rect>(() => ({
x: -transform.value[0] / transform.value[2], x: -transform.value[0] / transform.value[2],
y: -transform.value[1] / transform.value[2], y: -transform.value[1] / transform.value[2],
width: pinia.width / transform.value[2], width: store.width / transform.value[2],
height: pinia.height / transform.value[2] height: store.height / transform.value[2]
})); }));
const boundingRect = computed(() => (hasNodes.value ? getBoundsofRects(bb.value, viewBB.value) : viewBB.value)); const boundingRect = computed(() => (hasNodes.value ? getBoundsofRects(bb.value, viewBB.value) : viewBB.value));
const scaledWidth = computed(() => boundingRect.value.width / elementWidth.value); const scaledWidth = computed(() => boundingRect.value.width / elementWidth.value);
@@ -94,7 +93,7 @@ const MiniMap = defineComponent({
viewBox={`${x.value} ${y.value} ${width.value} ${height.value}`} viewBox={`${x.value} ${y.value} ${width.value} ${height.value}`}
class="revue-flow__minimap" class="revue-flow__minimap"
> >
{pinia.nodes {store.nodes
.filter((node) => !node.isHidden) .filter((node) => !node.isHidden)
.map((node) => ( .map((node) => (
<MiniMapNode <MiniMapNode
+9 -11
View File
@@ -1,11 +1,9 @@
import { Component, computed, defineComponent, PropType, ref } from 'vue'; import { computed, DefineComponent, defineComponent, inject, PropType, ref } from 'vue';
import { Edge, EdgeProps, Position, RevueFlowStore, WrapEdgeProps } from '../../types';
import store from '../../store';
import { Edge, EdgeProps, Position, WrapEdgeProps } from '../../types';
import { onMouseDown } from '../Handle/handler'; import { onMouseDown } from '../Handle/handler';
import { EdgeAnchor } from './EdgeAnchor'; import { EdgeAnchor } from './EdgeAnchor';
export default (EdgeComponent: any): Component<EdgeProps> => { export default (EdgeComponent: DefineComponent<EdgeProps>) => {
return defineComponent({ return defineComponent({
components: { EdgeComponent }, components: { EdgeComponent },
props: { props: {
@@ -187,7 +185,7 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
} }
}, },
setup(props) { setup(props) {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const updating = ref<boolean>(false); const updating = ref<boolean>(false);
const inactive = computed(() => !props.elementsSelectable && !props.onClick); const inactive = computed(() => !props.elementsSelectable && !props.onClick);
const edgeClasses = computed(() => [ const edgeClasses = computed(() => [
@@ -221,8 +219,8 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
const onEdgeClick = (event: MouseEvent) => { const onEdgeClick = (event: MouseEvent) => {
if (props.elementsSelectable) { if (props.elementsSelectable) {
pinia.unsetNodesSelection(); store.unsetNodesSelection();
pinia.addSelectedElements(edgeElement.value as any); store.addSelectedElements(edgeElement.value as any);
} }
if (typeof props.onClick === 'function') props.onClick(event, edgeElement.value); if (typeof props.onClick === 'function') props.onClick(event, edgeElement.value);
@@ -262,12 +260,12 @@ export default (EdgeComponent: any): Component<EdgeProps> => {
event, event,
handleId, handleId,
nodeId, nodeId,
pinia.setConnectionNodeId, store.setConnectionNodeId,
pinia.setConnectionPosition, store.setConnectionPosition,
props.onConnectEdge as any, props.onConnectEdge as any,
isTarget, isTarget,
isValidConnection, isValidConnection,
pinia.connectionMode, store.connectionMode,
isSourceHandle ? 'target' : 'source', isSourceHandle ? 'target' : 'source',
_onEdgeUpdate _onEdgeUpdate
); );
+8 -9
View File
@@ -1,12 +1,12 @@
import { Node, RevueFlowStore, WrapNodeProps } from '../../types'; import { Node, RevueFlowStore, WrapNodeProps } from '../../types';
import { computed, CSSProperties, DefineComponent, defineComponent, inject, onMounted, provide, ref } from 'vue'; import { computed, CSSProperties, DefineComponent, defineComponent, inject, onMounted, provide, ref, watchEffect } from 'vue';
import { DraggableCore, DraggableEventHandler } from '@braks/revue-draggable'; import { DraggableEventHandler, DraggableCore } from '@braks/revue-draggable';
export default (NodeComponent: DefineComponent<WrapNodeProps>) => { export default (NodeComponent: DefineComponent<WrapNodeProps>) => {
return defineComponent({ return defineComponent({
props: WrapNodeProps, props: WrapNodeProps,
setup(props) { setup(props) {
const store = inject<RevueFlowStore>('store'); const store = inject<RevueFlowStore>('store')!;
provide('NodeIdContext', props.id); provide('NodeIdContext', props.id);
const nodeElement = ref<HTMLDivElement | undefined>(); const nodeElement = ref<HTMLDivElement | undefined>();
@@ -134,7 +134,7 @@ export default (NodeComponent: DefineComponent<WrapNodeProps>) => {
props.onNodeDragStop?.(event as MouseEvent, node.value as Node); props.onNodeDragStop?.(event as MouseEvent, node.value as Node);
}; };
onMounted(() => { watchEffect(() => {
if (nodeElement.value && !props.isHidden) { if (nodeElement.value && !props.isHidden) {
store?.updateNodeDimensions([{ id: props.id || '', nodeElement: nodeElement.value, forceUpdate: true }]); store?.updateNodeDimensions([{ id: props.id || '', nodeElement: nodeElement.value, forceUpdate: true }]);
} }
@@ -164,14 +164,13 @@ export default (NodeComponent: DefineComponent<WrapNodeProps>) => {
return () => ( return () => (
<DraggableCore <DraggableCore
onStart={onDragStart} start={onDragStart}
onDrag={onDrag} move={onDrag}
onStop={onDragStop} stop={onDragStop}
scale={props.scale} scale={store.transform[2]}
disabled={!props.isDraggable} disabled={!props.isDraggable}
cancel=".nodrag" cancel=".nodrag"
grid={grid.value} grid={grid.value}
nodeRef={nodeElement.value}
enableUserSelectHack={false} enableUserSelectHack={false}
> >
<div <div
+9 -9
View File
@@ -4,8 +4,8 @@
*/ */
import { isNode } from '../../utils/graph'; import { isNode } from '../../utils/graph';
import { Node, RevueFlowStore } from '../../types'; import { Node, RevueFlowStore } from '../../types';
import { computed, defineComponent, inject, PropType, ref } from 'vue'; import { computed, defineComponent, inject, PropType } from 'vue';
import Draggable, { DraggableEventHandler } from '@braks/revue-draggable'; import { Draggable, DraggableEventHandler } from '@braks/revue-draggable';
export interface NodesSelectionProps { export interface NodesSelectionProps {
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void; onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
@@ -39,7 +39,6 @@ const NodesSelection = defineComponent({
}, },
setup(props) { setup(props) {
const store = inject<RevueFlowStore>('store')!; const store = inject<RevueFlowStore>('store')!;
const nodeRef = ref<HTMLElement | undefined>();
const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number]); const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number]);
const selectedNodes = computed(() => const selectedNodes = computed(() =>
@@ -67,10 +66,12 @@ const NodesSelection = defineComponent({
})); }));
const onStart: DraggableEventHandler = (event: MouseEvent) => { const onStart: DraggableEventHandler = (event: MouseEvent) => {
console.log('ondragstart');
props.onSelectionDragStart?.(event, selectedNodes.value); props.onSelectionDragStart?.(event, selectedNodes.value);
}; };
const onDrag: DraggableEventHandler = (event, data) => { const onDrag: DraggableEventHandler = (event, data) => {
console.log('ondrag');
props.onSelectionDrag?.(event, selectedNodes.value); props.onSelectionDrag?.(event, selectedNodes.value);
store.updateNodePosDiff({ store.updateNodePosDiff({
@@ -83,6 +84,7 @@ const NodesSelection = defineComponent({
}; };
const onStop: DraggableEventHandler = (event: MouseEvent) => { const onStop: DraggableEventHandler = (event: MouseEvent) => {
console.log('ondragend');
store.updateNodePosDiff({ store.updateNodePosDiff({
isDragging: false isDragging: false
}); });
@@ -104,16 +106,14 @@ const NodesSelection = defineComponent({
) : ( ) : (
<div class="revue-flow__nodesselection" style={style.value}> <div class="revue-flow__nodesselection" style={style.value}>
<Draggable <Draggable
start={onStart}
move={onDrag}
stop={onStop}
scale={store.transform[2]} scale={store.transform[2]}
grid={grid.value} grid={grid.value}
onStart={onStart}
onDrag={onDrag}
onStop={onStop}
nodeRef={nodeRef.value}
enableUserSelectHack={false} enableUserSelectHack={false}
nodeRef={nodeRef.value}
> >
<div ref={nodeRef} class="revue-flow__nodesselection-rect" onContextmenu={onContextMenu} style={innerStyle.value} /> <div class="revue-flow__nodesselection-rect" onContextmenu={onContextMenu} style={innerStyle.value} />
</Draggable> </Draggable>
</div> </div>
); );
+16 -1
View File
@@ -1,4 +1,14 @@
import { computed, CSSProperties, defineComponent, HTMLAttributes, onBeforeUnmount, PropType, provide, watchEffect } from 'vue'; import {
computed,
CSSProperties,
defineComponent,
HTMLAttributes,
onBeforeUnmount,
onUpdated,
PropType,
provide,
watchEffect
} from 'vue';
import GraphView from '../GraphView'; import GraphView from '../GraphView';
import DefaultNode from '../../components/Nodes/DefaultNode'; import DefaultNode from '../../components/Nodes/DefaultNode';
import InputNode from '../../components/Nodes/InputNode'; import InputNode from '../../components/Nodes/InputNode';
@@ -547,6 +557,11 @@ const RevueFlow = defineComponent({
props.onSelectionChange?.(store.selectedElements); props.onSelectionChange?.(store.selectedElements);
}); });
onUpdated(() => {
store.setElements(props.elements);
props.onSelectionChange?.(store.selectedElements);
});
onBeforeUnmount(() => { onBeforeUnmount(() => {
store.$reset(); store.$reset();
store.setElements([]); store.setElements([]);
+36 -37
View File
@@ -2,9 +2,8 @@ import { zoom, zoomIdentity } from 'd3-zoom';
import { select, pointer } from 'd3-selection'; import { select, pointer } from 'd3-selection';
import { clamp } from '../../utils'; import { clamp } from '../../utils';
import { FlowTransform, TranslateExtent, PanOnScrollMode, KeyCode } from '../../types'; import { FlowTransform, TranslateExtent, PanOnScrollMode, KeyCode, RevueFlowStore } from '../../types';
import { defineComponent, PropType, ref, watch, watchEffect } from 'vue'; import { defineComponent, inject, PropType, ref, watchEffect } from 'vue';
import store from '../../store';
import useKeyPress from '../../hooks/useKeyPress'; import useKeyPress from '../../hooks/useKeyPress';
import useResizeHandler from '../../hooks/useResizeHandler'; import useResizeHandler from '../../hooks/useResizeHandler';
@@ -39,19 +38,19 @@ const eventToFlowTransform = (eventTransform: any): FlowTransform => ({
const ZoomPane = defineComponent({ const ZoomPane = defineComponent({
props: { props: {
onMove: { onMove: {
type: Function() as PropType<ZoomPaneProps['onMove']>, type: Function as unknown as PropType<ZoomPaneProps['onMove']>,
required: false, required: false,
default: undefined as any default: () => {}
}, },
onMoveStart: { onMoveStart: {
type: Function() as PropType<ZoomPaneProps['onMoveStart']>, type: Function as unknown as PropType<ZoomPaneProps['onMoveStart']>,
required: false, required: false,
default: undefined as any default: () => {}
}, },
onMoveEnd: { onMoveEnd: {
type: Function() as PropType<ZoomPaneProps['onMoveEnd']>, type: Function as unknown as PropType<ZoomPaneProps['onMoveEnd']>,
required: false, required: false,
default: undefined as any default: () => {}
}, },
zoomOnScroll: { zoomOnScroll: {
type: Boolean as PropType<ZoomPaneProps['zoomOnScroll']>, type: Boolean as PropType<ZoomPaneProps['zoomOnScroll']>,
@@ -120,30 +119,30 @@ const ZoomPane = defineComponent({
} }
}, },
setup(props, { slots }) { setup(props, { slots }) {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const zoomPane = ref<HTMLDivElement | null>(null); const zoomPane = ref<HTMLDivElement | null>(null);
const prevTransform = ref<FlowTransform>({ x: 0, y: 0, zoom: 0 }); const prevTransform = ref<FlowTransform>({ x: 0, y: 0, zoom: 0 });
const zoomActivationKeyPressed = useKeyPress(props.zoomActivationKeyCode); const zoomActivationKeyPressed = useKeyPress(props.zoomActivationKeyCode);
watch(zoomPane, () => { watchEffect(() => {
if (zoomPane.value) useResizeHandler(zoomPane.value); if (zoomPane.value) useResizeHandler(zoomPane.value, store.updateSize);
}); });
watchEffect(() => { watchEffect(() => {
if (zoomPane.value && props.defaultPosition && props.defaultZoom) { if (zoomPane.value && props.defaultPosition && props.defaultZoom) {
const currentTranslateExtent = const currentTranslateExtent =
typeof props.translateExtent !== 'undefined' ? props.translateExtent : pinia.translateExtent; typeof props.translateExtent !== 'undefined' ? props.translateExtent : store.translateExtent;
const d3ZoomInstance = zoom().scaleExtent([pinia.minZoom, pinia.maxZoom]).translateExtent(currentTranslateExtent); const d3ZoomInstance = zoom().scaleExtent([store.minZoom, store.maxZoom]).translateExtent(currentTranslateExtent);
const selection = select(zoomPane.value as Element).call(d3ZoomInstance); const selection = select(zoomPane.value as Element).call(d3ZoomInstance);
const clampedX = clamp(props.defaultPosition[0], currentTranslateExtent[0][0], currentTranslateExtent[1][0]); const clampedX = clamp(props.defaultPosition[0], currentTranslateExtent[0][0], currentTranslateExtent[1][0]);
const clampedY = clamp(props.defaultPosition[1], currentTranslateExtent[0][1], currentTranslateExtent[1][1]); const clampedY = clamp(props.defaultPosition[1], currentTranslateExtent[0][1], currentTranslateExtent[1][1]);
const clampedZoom = clamp(props.defaultZoom, pinia.minZoom, pinia.maxZoom); const clampedZoom = clamp(props.defaultZoom, store.minZoom, store.maxZoom);
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom); const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom);
d3ZoomInstance.transform(selection, updatedTransform); d3ZoomInstance.transform(selection, updatedTransform);
pinia.initD3Zoom({ store.initD3Zoom({
d3Zoom: d3ZoomInstance, d3Zoom: d3ZoomInstance,
d3Selection: selection, d3Selection: selection,
d3ZoomHandler: selection.on('wheel.zoom'), d3ZoomHandler: selection.on('wheel.zoom'),
@@ -154,21 +153,21 @@ const ZoomPane = defineComponent({
}); });
watchEffect(() => { watchEffect(() => {
if (pinia.d3Selection && pinia.d3Zoom) { if (store.d3Selection && store.d3Zoom) {
if (props.panOnScroll && zoomActivationKeyPressed) { if (props.panOnScroll && zoomActivationKeyPressed) {
pinia.d3Selection store.d3Selection
.on('wheel', (event: any) => { .on('wheel', (event: any) => {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
const currentZoom = pinia.d3Selection?.property('__zoom').k || 1; const currentZoom = store.d3Selection?.property('__zoom').k || 1;
if (event.ctrlKey && props.zoomOnPinch) { if (event.ctrlKey && props.zoomOnPinch) {
const point = pointer(event); const point = pointer(event);
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js // 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 pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10;
const zoom = currentZoom * Math.pow(2, pinchDelta); const zoom = currentZoom * Math.pow(2, pinchDelta);
if (pinia.d3Selection) pinia.d3Zoom?.scaleTo(pinia.d3Selection, zoom, point); if (store.d3Selection) store.d3Zoom?.scaleTo(store.d3Selection, zoom, point);
return; return;
} }
@@ -179,27 +178,27 @@ const ZoomPane = defineComponent({
const deltaX = props.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize; const deltaX = props.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;
const deltaY = props.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize; const deltaY = props.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;
if (pinia.d3Selection && props.panOnScrollSpeed) if (store.d3Selection && props.panOnScrollSpeed)
pinia.d3Zoom?.translateBy( store.d3Zoom?.translateBy(
pinia.d3Selection, store.d3Selection,
-(deltaX / currentZoom) * props.panOnScrollSpeed, -(deltaX / currentZoom) * props.panOnScrollSpeed,
-(deltaY / currentZoom) * props.panOnScrollSpeed -(deltaY / currentZoom) * props.panOnScrollSpeed
); );
}) })
.on('wheel.zoom', null); .on('wheel.zoom', null);
} else if (typeof pinia.d3ZoomHandler !== 'undefined') { } else if (typeof store.d3ZoomHandler !== 'undefined') {
pinia.d3Selection.on('wheel', null).on('wheel.zoom', pinia.d3ZoomHandler); store.d3Selection.on('wheel', null).on('wheel.zoom', store.d3ZoomHandler);
} }
} }
}); });
watchEffect(() => { watchEffect(() => {
if (pinia.d3Zoom) { if (store.d3Zoom) {
if (props.selectionKeyPressed) { if (props.selectionKeyPressed) {
pinia.d3Zoom.on('zoom', null); store.d3Zoom.on('zoom', null);
} else { } else {
pinia.d3Zoom.on('zoom', (event: any) => { store.d3Zoom.on('zoom', (event: any) => {
pinia.updateTransform([event.transform.x, event.transform.y, event.transform.k]); store.updateTransform([event.transform.x, event.transform.y, event.transform.k]);
if (props.onMove) { if (props.onMove) {
const flowTransform = eventToFlowTransform(event.transform); const flowTransform = eventToFlowTransform(event.transform);
@@ -211,9 +210,9 @@ const ZoomPane = defineComponent({
}); });
watchEffect(() => { watchEffect(() => {
if (pinia.d3Zoom) { if (store.d3Zoom) {
if (props.onMoveStart) { if (props.onMoveStart) {
pinia.d3Zoom.on('start', (event: any) => { store.d3Zoom.on('start', (event: any) => {
if (viewChanged(prevTransform.value, event.transform)) { if (viewChanged(prevTransform.value, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform); const flowTransform = eventToFlowTransform(event.transform);
prevTransform.value = flowTransform; prevTransform.value = flowTransform;
@@ -222,15 +221,15 @@ const ZoomPane = defineComponent({
} }
}); });
} else { } else {
pinia.d3Zoom.on('start', null); store.d3Zoom.on('start', null);
} }
} }
}); });
watchEffect(() => { watchEffect(() => {
if (pinia.d3Zoom) { if (store.d3Zoom) {
if (props.onMoveEnd) { if (props.onMoveEnd) {
pinia.d3Zoom.on('end', (event: any) => { store.d3Zoom.on('end', (event: any) => {
if (viewChanged(prevTransform.value, event.transform)) { if (viewChanged(prevTransform.value, event.transform)) {
const flowTransform = eventToFlowTransform(event.transform); const flowTransform = eventToFlowTransform(event.transform);
prevTransform.value = flowTransform; prevTransform.value = flowTransform;
@@ -239,14 +238,14 @@ const ZoomPane = defineComponent({
} }
}); });
} else { } else {
pinia.d3Zoom.on('end', null); store.d3Zoom.on('end', null);
} }
} }
}); });
watchEffect(() => { watchEffect(() => {
if (pinia.d3Zoom) { if (store.d3Zoom) {
pinia.d3Zoom.filter((event: any) => { store.d3Zoom.filter((event: any) => {
const zoomScroll = props.zoomOnScroll; const zoomScroll = props.zoomOnScroll;
const pinchZoom = props.zoomOnPinch && event.ctrlKey; const pinchZoom = props.zoomOnPinch && event.ctrlKey;
+3 -15
View File
@@ -1,9 +1,7 @@
import { getDimensions } from '../utils'; import { getDimensions } from '../utils';
import store from '../store'; import { Dimensions } from '../types';
export default (rendererNode: HTMLDivElement) => {
const pinia = store();
export default (rendererNode: HTMLDivElement, updateSize: (size: Dimensions) => any) => {
let resizeObserver: ResizeObserver; let resizeObserver: ResizeObserver;
const updateDimensions = () => { const updateDimensions = () => {
@@ -17,7 +15,7 @@ export default (rendererNode: HTMLDivElement) => {
console.log('The revue Flow parent container needs a width and a height to render the graph.'); console.log('The revue Flow parent container needs a width and a height to render the graph.');
} }
pinia.updateSize(size); updateSize(size);
}; };
updateDimensions(); updateDimensions();
@@ -27,14 +25,4 @@ export default (rendererNode: HTMLDivElement) => {
resizeObserver = new ResizeObserver(() => updateDimensions()); resizeObserver = new ResizeObserver(() => updateDimensions());
resizeObserver.observe(rendererNode); resizeObserver.observe(rendererNode);
} }
/*
return () => {
window.onresize = null;
if (resizeObserver && rendererNode) {
resizeObserver.unobserve(rendererNode);
}
};
*/
}; };
+4 -4
View File
@@ -1,14 +1,14 @@
import { ElementId, UpdateNodeInternals } from '../types'; import { ElementId, RevueFlowStore, UpdateNodeInternals } from '../types';
import store from '../store'; import { inject } from 'vue';
function useUpdateNodeInternals(): UpdateNodeInternals { function useUpdateNodeInternals(): UpdateNodeInternals {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
return (id: ElementId) => { return (id: ElementId) => {
const nodeElement: HTMLDivElement | null = document.querySelector(`.revue-flow__node[data-id="${id}"]`); const nodeElement: HTMLDivElement | null = document.querySelector(`.revue-flow__node[data-id="${id}"]`);
if (nodeElement) { if (nodeElement) {
pinia.updateNodeDimensions([{ id, nodeElement, forceUpdate: true }]); store.updateNodeDimensions([{ id, nodeElement, forceUpdate: true }]);
} }
}; };
} }
+15 -15
View File
@@ -1,7 +1,7 @@
import { zoomIdentity } from 'd3-zoom'; import { zoomIdentity } from 'd3-zoom';
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '../utils/graph'; import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, XYPosition } from '../types'; import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, XYPosition, RevueFlowStore } from '../types';
import store from '../store'; import { inject } from 'vue';
const DEFAULT_PADDING = 0.1; const DEFAULT_PADDING = 0.1;
@@ -18,20 +18,20 @@ const initialZoomPanHelper: ZoomPanHelperFunctions = {
}; };
const useZoomPanHelper = (): ZoomPanHelperFunctions => { const useZoomPanHelper = (): ZoomPanHelperFunctions => {
const pinia = store(); const store = inject<RevueFlowStore>('store')!;
const zoomPanHelperFunctions = () => { const zoomPanHelperFunctions = () => {
if (pinia.d3Selection && pinia.d3Zoom) { if (store.d3Selection && store.d3Zoom) {
return { return {
zoomIn: () => pinia.d3Zoom?.scaleBy(pinia.d3Selection as any, 1.2), zoomIn: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1.2),
zoomOut: () => pinia.d3Zoom?.scaleBy(pinia.d3Selection as any, 1 / 1.2), zoomOut: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1 / 1.2),
zoomTo: (zoomLevel: number) => pinia.d3Zoom?.scaleTo(pinia.d3Selection as any, zoomLevel), zoomTo: (zoomLevel: number) => store.d3Zoom?.scaleTo(store.d3Selection as any, zoomLevel),
transform: (transform: FlowTransform) => { transform: (transform: FlowTransform) => {
const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom); const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom);
pinia.d3Zoom?.transform(pinia.d3Selection as any, nextTransform); store.d3Zoom?.transform(store.d3Selection as any, nextTransform);
}, },
fitView: (options: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => { fitView: (options: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {
const { nodes, width, height, minZoom, maxZoom } = pinia; const { nodes, width, height, minZoom, maxZoom } = store;
if (!nodes.length) { if (!nodes.length) {
return; return;
@@ -48,27 +48,27 @@ const useZoomPanHelper = (): ZoomPanHelperFunctions => {
); );
const transform = zoomIdentity.translate(x, y).scale(zoom); const transform = zoomIdentity.translate(x, y).scale(zoom);
pinia.d3Zoom?.transform(pinia.d3Selection as any, transform); store.d3Zoom?.transform(store.d3Selection as any, transform);
}, },
setCenter: (x: number, y: number, zoom?: number) => { setCenter: (x: number, y: number, zoom?: number) => {
const { width, height, maxZoom } = pinia; const { width, height, maxZoom } = store;
const nextZoom = typeof zoom !== 'undefined' ? zoom : maxZoom; const nextZoom = typeof zoom !== 'undefined' ? zoom : maxZoom;
const centerX = width / 2 - x * nextZoom; const centerX = width / 2 - x * nextZoom;
const centerY = height / 2 - y * nextZoom; const centerY = height / 2 - y * nextZoom;
const transform = zoomIdentity.translate(centerX, centerY).scale(nextZoom); const transform = zoomIdentity.translate(centerX, centerY).scale(nextZoom);
pinia.d3Zoom?.transform(pinia.d3Selection as any, transform); store.d3Zoom?.transform(store.d3Selection as any, transform);
}, },
fitBounds: (bounds: Rect, padding = DEFAULT_PADDING) => { fitBounds: (bounds: Rect, padding = DEFAULT_PADDING) => {
const { width, height, minZoom, maxZoom } = pinia; const { width, height, minZoom, maxZoom } = store;
const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom, maxZoom, padding); const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom, maxZoom, padding);
const transform = zoomIdentity.translate(x, y).scale(zoom); const transform = zoomIdentity.translate(x, y).scale(zoom);
pinia.d3Zoom?.transform(pinia.d3Selection as any, transform); store.d3Zoom?.transform(store.d3Selection as any, transform);
}, },
project: (position: XYPosition) => { project: (position: XYPosition) => {
const { transform, snapToGrid, snapGrid } = pinia; const { transform, snapToGrid, snapGrid } = store;
return pointToRendererPoint(position, transform, snapToGrid, snapGrid); return pointToRendererPoint(position, transform, snapToGrid, snapGrid);
}, },
initialized: true initialized: true
-6
View File
@@ -1,5 +1,3 @@
import configureStore from './configure-store';
import { RevueFlowState, ConnectionMode } from '../types'; import { RevueFlowState, ConnectionMode } from '../types';
export const initialState: RevueFlowState = { export const initialState: RevueFlowState = {
@@ -55,7 +53,3 @@ export const initialState: RevueFlowState = {
revueFlowVersion: typeof __REVUE_FLOW_VERSION__ !== 'undefined' ? __REVUE_FLOW_VERSION__ : '-' revueFlowVersion: typeof __REVUE_FLOW_VERSION__ !== 'undefined' ? __REVUE_FLOW_VERSION__ : '-'
}; };
const store = configureStore(initialState);
export default store;
+25 -4
View File
@@ -262,11 +262,12 @@
"@babel/helper-validator-identifier" "^7.14.5" "@babel/helper-validator-identifier" "^7.14.5"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@braks/revue-draggable@^0.1.13": "@braks/revue-draggable@^0.2.1-5":
version "0.1.13" version "0.2.1-5"
resolved "https://registry.yarnpkg.com/@braks/revue-draggable/-/revue-draggable-0.1.13.tgz#cff5a9ac21c488de5b0c3fef6cdbd3f8f828dd21" resolved "https://registry.yarnpkg.com/@braks/revue-draggable/-/revue-draggable-0.2.1-5.tgz#280f9cb4dfd5c3bc88dff0f8c70ffa8966536328"
integrity sha512-unczSXZNK3ZnHoIj5w45a4eN7iQH6s0Ot33G2s7zkdMRHcoGh8Cc0ltw5m5XlrEgk4ch0vAEIU+MQiS8/D27uw== integrity sha512-+oDuUvTVd5ST6brdtfXYJMnFrmyQat9W7yUKpKBTI0od3ycfaGgMCT9w+OoQ3rlBi2cV6gFXlhZVIeLi+v55aA==
dependencies: dependencies:
"@vueuse/core" "^5.1.3"
vue-demi latest vue-demi latest
"@eslint/eslintrc@^0.4.2": "@eslint/eslintrc@^0.4.2":
@@ -911,6 +912,21 @@
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.4.tgz#c14c461ec42ea2c1556e86f60b0354341d91adc3" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.4.tgz#c14c461ec42ea2c1556e86f60b0354341d91adc3"
integrity sha512-6O45kZAmkLvzGLToBxEz4lR2W6kXohCtebV2UxjH9GXjd8X9AhEn68FN9eNanFtWNzvgw1hqd6HkPRVQalqf7Q== integrity sha512-6O45kZAmkLvzGLToBxEz4lR2W6kXohCtebV2UxjH9GXjd8X9AhEn68FN9eNanFtWNzvgw1hqd6HkPRVQalqf7Q==
"@vueuse/core@^5.1.3":
version "5.1.4"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.1.4.tgz#c590bd1ff5cdd3d2caa033b65ed8cb42fc12a534"
integrity sha512-iuRhSaScI1GJS4N3CFPc1GajOr6F6J1Nng1I6ocNOjLx+evss6egImx9wnuX45fxqQstnh7Vfqe3FF7+0NgoWg==
dependencies:
"@vueuse/shared" "5.1.4"
vue-demi "*"
"@vueuse/shared@5.1.4":
version "5.1.4"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-5.1.4.tgz#35e3aa8ce7e52b447191915ee8b4afa481838c43"
integrity sha512-C0xiMv8+sFI3WhXdlrcLKI4d4dFnouHe4Te51cxWgcmpW7S8eUiM8fXPaQVxUQZ4E9PCx3zEZpNpCLzQa+6Lag==
dependencies:
vue-demi "*"
acorn-jsx@^5.2.0, acorn-jsx@^5.3.1: acorn-jsx@^5.2.0, acorn-jsx@^5.3.1:
version "5.3.2" version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@@ -5625,6 +5641,11 @@ vite@^2.3.8:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
vue-demi@*:
version "0.11.2"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.11.2.tgz#faa06da53887c493a695b997f4fcb4784a667990"
integrity sha512-J+X8Au6BhQdcej6LY4O986634hZLu55L0ewU2j8my7WIKlu8cK0dqmdUxqVHHMd/cMrKKZ9SywB/id6aLhwCtA==
vue-demi@latest: vue-demi@latest:
version "0.10.1" version "0.10.1"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.10.1.tgz#229b81395510f02f4ee255344557a12cc0120930" resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.10.1.tgz#229b81395510f02f4ee255344557a12cc0120930"