chore: add vueuse/core to deps
feat: Implement onKeystrok of vueuse * Implement useEventlistener fix: node selection not properly selecting underlying nodes
This commit is contained in:
+3
-2
@@ -30,12 +30,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braks/revue-draggable": "^0.2.4",
|
"@braks/revue-draggable": "^0.2.4",
|
||||||
"@types/d3": "^7.0.0",
|
"@types/d3": "^7.0.0",
|
||||||
|
"@vueuse/core": "^5.1.4",
|
||||||
"d3": "^7.0.0",
|
"d3": "^7.0.0",
|
||||||
"d3-selection": "^3.0.0",
|
"d3-selection": "^3.0.0",
|
||||||
"d3-zoom": "^3.0.0",
|
"d3-zoom": "^3.0.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"pinia": "^2.0.0-beta.3",
|
"pinia": "^2.0.0-beta.3"
|
||||||
"vue": "^3.0.5"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.6",
|
"@babel/core": "^7.14.6",
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
"vite": "^2.3.8",
|
"vite": "^2.3.8",
|
||||||
"vite-svg-loader": "^2.1.0",
|
"vite-svg-loader": "^2.1.0",
|
||||||
|
"vue": "^3.0.5",
|
||||||
"vue-router": "4",
|
"vue-router": "4",
|
||||||
"vue-tsc": "^0.0.24"
|
"vue-tsc": "^0.0.24"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ const NodesSelection = defineComponent({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const onStart: DraggableEventListener = ({ event }) => {
|
const onStart: DraggableEventListener = ({ event }) => {
|
||||||
event.stopPropagation();
|
|
||||||
props.onSelectionDragStart?.(event, selectedNodes.value);
|
props.onSelectionDragStart?.(event, selectedNodes.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
import { RevueFlowStore, XYPosition } from '../../types';
|
import { RevueFlowStore, XYPosition } from '../../types';
|
||||||
import { computed, defineComponent, inject } from 'vue';
|
import { computed, defineComponent, inject } from 'vue';
|
||||||
|
import { templateRef, useEventListener } from '@vueuse/core';
|
||||||
|
|
||||||
function getMousePosition(event: MouseEvent): XYPosition | void {
|
function getMousePosition(event: MouseEvent): XYPosition | void {
|
||||||
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
||||||
@@ -18,39 +19,30 @@ function getMousePosition(event: MouseEvent): XYPosition | void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const SelectionRect = defineComponent({
|
const SelectionRect = (props: { width: number; height: number; x: number; y: number }) => {
|
||||||
setup() {
|
return (
|
||||||
const store = inject<RevueFlowStore>('store');
|
<div
|
||||||
|
class="revue-flow__selection"
|
||||||
return () => {
|
style={{
|
||||||
return store?.userSelectionRect.draw ? (
|
width: `${props.width}px`,
|
||||||
<div
|
height: `${props.height}px`,
|
||||||
class="revue-flow__selection"
|
transform: `translate(${props.x}px, ${props.y}px)`
|
||||||
style={{
|
}}
|
||||||
width: `${store?.userSelectionRect.width}px`,
|
/>
|
||||||
height: `${store?.userSelectionRect.height}px`,
|
);
|
||||||
transform: `translate(${store?.userSelectionRect.x}px, ${store?.userSelectionRect.y}px)`
|
};
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { SelectionRect },
|
components: { SelectionRect },
|
||||||
setup() {
|
setup() {
|
||||||
const store = inject<RevueFlowStore>('store')!;
|
const store = inject<RevueFlowStore>('store')!;
|
||||||
|
const el = templateRef('user-selection', null);
|
||||||
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable);
|
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable);
|
||||||
|
|
||||||
if (!shouldRender.value) {
|
if (!shouldRender.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMouseDown = (event: MouseEvent): void => {
|
const onMouseDown = (event: MouseEvent) => {
|
||||||
const mousePos = getMousePosition(event);
|
const mousePos = getMousePosition(event);
|
||||||
if (!mousePos) {
|
if (!mousePos) {
|
||||||
return;
|
return;
|
||||||
@@ -59,7 +51,8 @@ export default defineComponent({
|
|||||||
store.setUserSelection(mousePos);
|
store.setUserSelection(mousePos);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseMove = (event: MouseEvent): void => {
|
const onMouseMove = (event: MouseEvent) => {
|
||||||
|
|
||||||
if (!store.selectionActive) {
|
if (!store.selectionActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -72,23 +65,33 @@ export default defineComponent({
|
|||||||
store.updateUserSelection(mousePos);
|
store.updateUserSelection(mousePos);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = () => store.unsetUserSelection();
|
const onMouseUp = () => {
|
||||||
|
store.unsetUserSelection();
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseLeave = () => {
|
const onMouseLeave = () => {
|
||||||
store.unsetUserSelection();
|
store.unsetUserSelection();
|
||||||
store.unsetNodesSelection();
|
store.unsetNodesSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEventListener(el, 'mousedown', onMouseDown);
|
||||||
|
useEventListener(el, 'mousemove', onMouseMove);
|
||||||
|
useEventListener(el, 'click', onMouseUp);
|
||||||
|
useEventListener(el, 'mouseup', onMouseUp);
|
||||||
|
useEventListener(el, 'mouseleave', onMouseLeave);
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div class="revue-flow__selectionpane" ref="user-selection">
|
||||||
class="revue-flow__selectionpane"
|
{store?.userSelectionRect.draw ? (
|
||||||
onMousedown={onMouseDown}
|
<SelectionRect
|
||||||
onMousemove={onMouseMove}
|
width={store.userSelectionRect.width}
|
||||||
onClick={onMouseUp}
|
height={store.userSelectionRect.height}
|
||||||
onMouseup={onMouseUp}
|
x={store.userSelectionRect.x}
|
||||||
onMouseleave={onMouseLeave}
|
y={store.userSelectionRect.y}
|
||||||
>
|
/>
|
||||||
<SelectionRect />
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { GraphViewProps } from '../GraphView';
|
import { defineComponent, inject, PropType } from 'vue';
|
||||||
import ZoomPane from '../ZoomPane';
|
import ZoomPane from '../ZoomPane';
|
||||||
import UserSelection from '../../components/UserSelection';
|
import UserSelection from '../../components/UserSelection';
|
||||||
import NodesSelection from '../../components/NodesSelection';
|
import NodesSelection from '../../components/NodesSelection';
|
||||||
import { defineComponent, inject, PropType } from 'vue';
|
import { RevueFlowStore, GraphViewProps } from '../../types';
|
||||||
import { RevueFlowStore } from '../../types';
|
|
||||||
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
import useGlobalKeyHandler from '../../hooks/useGlobalKeyHandler';
|
||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
|
|
||||||
@@ -199,7 +198,7 @@ const FlowRenderer = defineComponent({
|
|||||||
zoomActivationKeyCode={props.zoomActivationKeyCode}
|
zoomActivationKeyCode={props.zoomActivationKeyCode}
|
||||||
>
|
>
|
||||||
{slots.default ? slots.default() : ''}
|
{slots.default ? slots.default() : ''}
|
||||||
{keyPressed.value ? <UserSelection track-by={'selection'} /> : ''}
|
{keyPressed.value ? <UserSelection /> : ''}
|
||||||
{store?.nodesSelectionActive && (
|
{store?.nodesSelectionActive && (
|
||||||
<NodesSelection
|
<NodesSelection
|
||||||
onSelectionDragStart={props.onSelectionDragStart}
|
onSelectionDragStart={props.onSelectionDragStart}
|
||||||
|
|||||||
@@ -3,26 +3,9 @@ import FlowRenderer from '../FlowRenderer';
|
|||||||
import NodeRenderer from '../NodeRenderer';
|
import NodeRenderer from '../NodeRenderer';
|
||||||
import EdgeRenderer from '../EdgeRenderer';
|
import EdgeRenderer from '../EdgeRenderer';
|
||||||
import { onLoadProject, onLoadGetElements, onLoadToObject } from '../../utils/graph';
|
import { onLoadProject, onLoadGetElements, onLoadToObject } from '../../utils/graph';
|
||||||
import { RevueFlowProps } from '../RevueFlow';
|
import { GraphViewProps, RevueFlowStore } from '../../types';
|
||||||
import { NodeTypesType, EdgeTypesType, ConnectionLineType, KeyCode, RevueFlowStore } from '../../types';
|
|
||||||
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
import useZoomPanHelper from '../../hooks/useZoomPanHelper';
|
||||||
|
|
||||||
export interface GraphViewProps extends Omit<RevueFlowProps, 'onSelectionChange' | 'elements'> {
|
|
||||||
nodeTypes: NodeTypesType;
|
|
||||||
edgeTypes: EdgeTypesType;
|
|
||||||
selectionKeyCode: KeyCode;
|
|
||||||
deleteKeyCode: KeyCode;
|
|
||||||
multiSelectionKeyCode: KeyCode;
|
|
||||||
connectionLineType: ConnectionLineType;
|
|
||||||
snapToGrid: boolean;
|
|
||||||
snapGrid: [number, number];
|
|
||||||
onlyRenderVisibleElements: boolean;
|
|
||||||
defaultZoom: number;
|
|
||||||
defaultPosition: [number, number];
|
|
||||||
arrowHeadColor: string;
|
|
||||||
selectNodesOnDrag: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GraphView = defineComponent({
|
const GraphView = defineComponent({
|
||||||
name: 'GraphView',
|
name: 'GraphView',
|
||||||
components: { NodeRenderer, EdgeRenderer },
|
components: { NodeRenderer, EdgeRenderer },
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
import {
|
import { computed, defineComponent, onBeforeUnmount, PropType, provide, watch } from 'vue';
|
||||||
computed,
|
import '../../style.css';
|
||||||
CSSProperties,
|
import '../../theme-default.css';
|
||||||
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';
|
||||||
@@ -16,30 +8,7 @@ import OutputNode from '../../components/Nodes/OutputNode';
|
|||||||
import { createNodeTypes } from '../NodeRenderer/utils';
|
import { createNodeTypes } from '../NodeRenderer/utils';
|
||||||
import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges';
|
import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../components/Edges';
|
||||||
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
import { createEdgeTypes } from '../EdgeRenderer/utils';
|
||||||
import {
|
import { ConnectionMode, ConnectionLineType, PanOnScrollMode, RevueFlowStore, RevueFlowProps } from '../../types';
|
||||||
Elements,
|
|
||||||
NodeTypesType,
|
|
||||||
EdgeTypesType,
|
|
||||||
OnLoadFunc,
|
|
||||||
Node,
|
|
||||||
Edge,
|
|
||||||
Connection,
|
|
||||||
ConnectionMode,
|
|
||||||
ConnectionLineType,
|
|
||||||
ConnectionLineComponent,
|
|
||||||
FlowTransform,
|
|
||||||
OnConnectStartFunc,
|
|
||||||
OnConnectStopFunc,
|
|
||||||
OnConnectEndFunc,
|
|
||||||
TranslateExtent,
|
|
||||||
KeyCode,
|
|
||||||
PanOnScrollMode,
|
|
||||||
OnEdgeUpdateFunc,
|
|
||||||
NodeExtent,
|
|
||||||
RevueFlowStore
|
|
||||||
} from '../../types';
|
|
||||||
import '../../style.css';
|
|
||||||
import '../../theme-default.css';
|
|
||||||
import { initialState } from '../../store';
|
import { initialState } from '../../store';
|
||||||
import configureStore from '../../store/configure-store';
|
import configureStore from '../../store/configure-store';
|
||||||
|
|
||||||
@@ -56,79 +25,6 @@ const defaultEdgeTypes = {
|
|||||||
smoothstep: SmoothStepEdge
|
smoothstep: SmoothStepEdge
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface RevueFlowProps extends Omit<HTMLAttributes, 'onLoad'> {
|
|
||||||
elements: Elements;
|
|
||||||
onElementClick?: (event: MouseEvent, element: Node | Edge) => void;
|
|
||||||
onElementsRemove?: (elements: Elements) => void;
|
|
||||||
onNodeDoubleClick?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseEnter?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseMove?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeMouseLeave?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeContextMenu?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeDrag?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
|
|
||||||
onConnect?: (connection: Edge | Connection) => void;
|
|
||||||
onConnectStart?: OnConnectStartFunc;
|
|
||||||
onConnectStop?: OnConnectStopFunc;
|
|
||||||
onConnectEnd?: OnConnectEndFunc;
|
|
||||||
onLoad?: OnLoadFunc;
|
|
||||||
onMove?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
|
||||||
onSelectionChange?: (elements: Elements | null) => void;
|
|
||||||
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void;
|
|
||||||
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void;
|
|
||||||
onPaneScroll?: (event?: WheelEvent) => void;
|
|
||||||
onPaneClick?: (event: MouseEvent) => void;
|
|
||||||
onPaneContextMenu?: (event: MouseEvent) => void;
|
|
||||||
nodeTypes?: NodeTypesType;
|
|
||||||
edgeTypes?: EdgeTypesType;
|
|
||||||
connectionMode?: ConnectionMode;
|
|
||||||
connectionLineType?: ConnectionLineType;
|
|
||||||
connectionLineStyle?: CSSProperties;
|
|
||||||
connectionLineComponent?: ConnectionLineComponent;
|
|
||||||
deleteKeyCode?: KeyCode;
|
|
||||||
selectionKeyCode?: KeyCode;
|
|
||||||
multiSelectionKeyCode?: KeyCode;
|
|
||||||
zoomActivationKeyCode?: KeyCode;
|
|
||||||
snapToGrid?: boolean;
|
|
||||||
snapGrid?: [number, number];
|
|
||||||
onlyRenderVisibleElements?: boolean;
|
|
||||||
nodesDraggable?: boolean;
|
|
||||||
nodesConnectable?: boolean;
|
|
||||||
elementsSelectable?: boolean;
|
|
||||||
selectNodesOnDrag?: boolean;
|
|
||||||
paneMoveable?: boolean;
|
|
||||||
minZoom?: number;
|
|
||||||
maxZoom?: number;
|
|
||||||
defaultZoom?: number;
|
|
||||||
defaultPosition?: [number, number];
|
|
||||||
translateExtent?: TranslateExtent;
|
|
||||||
nodeExtent?: NodeExtent;
|
|
||||||
arrowHeadColor?: string;
|
|
||||||
markerEndId?: string;
|
|
||||||
zoomOnScroll?: boolean;
|
|
||||||
zoomOnPinch?: boolean;
|
|
||||||
panOnScroll?: boolean;
|
|
||||||
panOnScrollSpeed?: number;
|
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
|
||||||
zoomOnDoubleClick?: boolean;
|
|
||||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
|
||||||
onEdgeContextMenu?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseEnter?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseMove?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeMouseLeave?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeDoubleClick?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeUpdateStart?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void;
|
|
||||||
edgeUpdaterRadius?: number;
|
|
||||||
nodeTypesId?: string;
|
|
||||||
edgeTypesId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RevueFlow = defineComponent({
|
const RevueFlow = defineComponent({
|
||||||
name: 'RevueFlow',
|
name: 'RevueFlow',
|
||||||
components: { GraphView },
|
components: { GraphView },
|
||||||
@@ -552,14 +448,8 @@ const RevueFlow = defineComponent({
|
|||||||
provide<RevueFlowStore>('store', store);
|
provide<RevueFlowStore>('store', store);
|
||||||
store.setElements(props.elements);
|
store.setElements(props.elements);
|
||||||
|
|
||||||
watchEffect(() => {
|
watch(props, () => {
|
||||||
store.setElements(props.elements);
|
store.setElements(props.elements);
|
||||||
props.onSelectionChange?.(store.selectedElements);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUpdated(() => {
|
|
||||||
store.setElements(props.elements);
|
|
||||||
props.onSelectionChange?.(store.selectedElements);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|||||||
+26
-33
@@ -1,44 +1,37 @@
|
|||||||
import { isInputDOMNode } from '../utils';
|
import { ref, Ref } from 'vue';
|
||||||
import { KeyCode } from '../types';
|
import { KeyCode } from '../types';
|
||||||
import { onBeforeUnmount, onMounted, ref, Ref } from 'vue';
|
import { onKeyStroke, useEventListener } from '@vueuse/core';
|
||||||
|
|
||||||
export default (keyCode?: KeyCode): Ref<boolean> => {
|
export default (keyCode?: KeyCode): Ref<boolean> => {
|
||||||
const keyPressed = ref<boolean>(false);
|
const keyPressed = ref<boolean>(false);
|
||||||
|
|
||||||
const downHandler = (event: KeyboardEvent) => {
|
onKeyStroke(
|
||||||
if (!isInputDOMNode(event) && (event.key === keyCode || event.keyCode === keyCode)) {
|
(event) => event.key === keyCode || event.keyCode === keyCode,
|
||||||
event.preventDefault();
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
keyPressed.value = true;
|
keyPressed.value = true;
|
||||||
}
|
},
|
||||||
};
|
{ eventName: 'keypress' }
|
||||||
|
);
|
||||||
const upHandler = (event: KeyboardEvent) => {
|
onKeyStroke(
|
||||||
if (!isInputDOMNode(event) && (event.key === keyCode || event.keyCode === keyCode)) {
|
(event) => event.key === keyCode || event.keyCode === keyCode,
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
keyPressed.value = true;
|
||||||
|
},
|
||||||
|
{ eventName: 'keydown' }
|
||||||
|
);
|
||||||
|
onKeyStroke(
|
||||||
|
(event) => event.key === keyCode || event.keyCode === keyCode,
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
keyPressed.value = false;
|
keyPressed.value = false;
|
||||||
}
|
},
|
||||||
};
|
{ eventName: 'keyup' }
|
||||||
|
);
|
||||||
|
|
||||||
const resetHandler = () => (keyPressed.value = false);
|
useEventListener(window, 'blur', () => {
|
||||||
|
keyPressed.value = false;
|
||||||
const bindEvents = () => {
|
|
||||||
if (typeof keyCode !== 'undefined') {
|
|
||||||
window.addEventListener('keydown', downHandler);
|
|
||||||
window.addEventListener('keyup', upHandler);
|
|
||||||
window.addEventListener('blur', resetHandler);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const unbindEvents = () => {
|
|
||||||
window.removeEventListener('keydown', downHandler);
|
|
||||||
window.removeEventListener('keyup', upHandler);
|
|
||||||
window.removeEventListener('blur', resetHandler);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
bindEvents();
|
|
||||||
});
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
unbindEvents();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return keyPressed;
|
return keyPressed;
|
||||||
|
|||||||
@@ -5,77 +5,61 @@ import { inject } from 'vue';
|
|||||||
|
|
||||||
const DEFAULT_PADDING = 0.1;
|
const DEFAULT_PADDING = 0.1;
|
||||||
|
|
||||||
const initialZoomPanHelper: ZoomPanHelperFunctions = {
|
|
||||||
zoomIn: () => {},
|
|
||||||
zoomOut: () => {},
|
|
||||||
zoomTo: (_: number) => {},
|
|
||||||
transform: (_: FlowTransform) => {},
|
|
||||||
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
|
|
||||||
setCenter: (_: number, __: number) => {},
|
|
||||||
fitBounds: (_: Rect) => {},
|
|
||||||
project: (position: XYPosition) => position,
|
|
||||||
initialized: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
const useZoomPanHelper = (): ZoomPanHelperFunctions => {
|
||||||
const store = inject<RevueFlowStore>('store')!;
|
const store = inject<RevueFlowStore>('store')!;
|
||||||
const zoomPanHelperFunctions = () => {
|
const zoomPanHelperFunctions = () => {
|
||||||
if (store.d3Selection && store.d3Zoom) {
|
return {
|
||||||
return {
|
zoomIn: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1.2),
|
||||||
zoomIn: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1.2),
|
zoomOut: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1 / 1.2),
|
||||||
zoomOut: () => store.d3Zoom?.scaleBy(store.d3Selection as any, 1 / 1.2),
|
zoomTo: (zoomLevel: number) => store.d3Zoom?.scaleTo(store.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);
|
|
||||||
|
|
||||||
store.d3Zoom?.transform(store.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 } = store;
|
const { nodes, width, height, minZoom, maxZoom } = store;
|
||||||
|
|
||||||
if (!nodes.length) {
|
if (!nodes.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bounds = getRectOfNodes(options.includeHiddenNodes ? nodes : nodes.filter((node) => !node.isHidden));
|
const bounds = getRectOfNodes(options.includeHiddenNodes ? nodes : nodes.filter((node) => !node.isHidden));
|
||||||
const [x, y, zoom] = getTransformForBounds(
|
const [x, y, zoom] = getTransformForBounds(
|
||||||
bounds,
|
bounds,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
options.minZoom || minZoom,
|
options.minZoom || minZoom,
|
||||||
options.maxZoom || maxZoom,
|
options.maxZoom || 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);
|
||||||
|
|
||||||
store.d3Zoom?.transform(store.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 } = store;
|
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);
|
||||||
|
|
||||||
store.d3Zoom?.transform(store.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 } = store;
|
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);
|
||||||
|
|
||||||
store.d3Zoom?.transform(store.d3Selection as any, transform);
|
store.d3Zoom?.transform(store.d3Selection as any, transform);
|
||||||
},
|
},
|
||||||
project: (position: XYPosition) => {
|
project: (position: XYPosition) => {
|
||||||
const { transform, snapToGrid, snapGrid } = store;
|
const { transform, snapToGrid, snapGrid } = store;
|
||||||
return pointToRendererPoint(position, transform, snapToGrid, snapGrid);
|
return pointToRendererPoint(position, transform, snapToGrid, snapGrid);
|
||||||
},
|
},
|
||||||
initialized: true
|
initialized: true
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return initialZoomPanHelper;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return zoomPanHelperFunctions();
|
return zoomPanHelperFunctions();
|
||||||
|
|||||||
+1
-3
@@ -1,6 +1,4 @@
|
|||||||
import RevueFlow from './container/RevueFlow';
|
export { default as default } from './container/RevueFlow';
|
||||||
export default RevueFlow;
|
|
||||||
|
|
||||||
export { default as Handle } from './components/Handle';
|
export { default as Handle } from './components/Handle';
|
||||||
export { default as EdgeText } from './components/Edges/EdgeText';
|
export { default as EdgeText } from './components/Edges/EdgeText';
|
||||||
export { getBezierPath } from './components/Edges/BezierEdge';
|
export { getBezierPath } from './components/Edges/BezierEdge';
|
||||||
|
|||||||
@@ -189,15 +189,8 @@ export default function configureStore(
|
|||||||
const selectedEdges = getConnectedEdges(selectedNodes, this.edges);
|
const selectedEdges = getConnectedEdges(selectedNodes, this.edges);
|
||||||
|
|
||||||
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
|
const nextSelectedElements = [...selectedNodes, ...selectedEdges];
|
||||||
const selectedElementsChanged = !isEqual(nextSelectedElements, this.selectedElements);
|
|
||||||
const selectedElementsUpdate = selectedElementsChanged
|
|
||||||
? nextSelectedElements.length > 0
|
|
||||||
? nextSelectedElements
|
|
||||||
: []
|
|
||||||
: [];
|
|
||||||
|
|
||||||
this.userSelectionRect = nextUserSelectRect;
|
this.userSelectionRect = nextUserSelectRect;
|
||||||
this.selectedElements = selectedElementsUpdate;
|
this.selectedElements = nextSelectedElements;
|
||||||
},
|
},
|
||||||
unsetUserSelection() {
|
unsetUserSelection() {
|
||||||
const selectedNodes = this.selectedElements?.filter((node) => isNode(node) && node.__rf) as Node[];
|
const selectedNodes = this.selectedElements?.filter((node) => isNode(node) && node.__rf) as Node[];
|
||||||
|
|||||||
+90
-1
@@ -1,5 +1,5 @@
|
|||||||
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
||||||
import { DefineComponent, HTMLAttributes, PropType, VNode } from 'vue';
|
import { CSSProperties, DefineComponent, HTMLAttributes, PropType, VNode } from 'vue';
|
||||||
import { Store } from 'pinia';
|
import { Store } from 'pinia';
|
||||||
|
|
||||||
export type ElementId = string;
|
export type ElementId = string;
|
||||||
@@ -906,3 +906,92 @@ export type RevueFlowActions = {
|
|||||||
export type RevueFlowStore = Store<string, RevueFlowState, any, RevueFlowActions>;
|
export type RevueFlowStore = Store<string, RevueFlowState, any, RevueFlowActions>;
|
||||||
|
|
||||||
export type UpdateNodeInternals = (nodeId: ElementId) => void;
|
export type UpdateNodeInternals = (nodeId: ElementId) => void;
|
||||||
|
|
||||||
|
export interface RevueFlowProps extends Omit<HTMLAttributes, 'onLoad'> {
|
||||||
|
elements: Elements;
|
||||||
|
onElementClick?: (event: MouseEvent, element: Node | Edge) => void;
|
||||||
|
onElementsRemove?: (elements: Elements) => void;
|
||||||
|
onNodeDoubleClick?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseEnter?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseMove?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeMouseLeave?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeContextMenu?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeDragStart?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeDrag?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onNodeDragStop?: (event: MouseEvent, node: Node) => void;
|
||||||
|
onConnect?: (connection: Edge | Connection) => void;
|
||||||
|
onConnectStart?: OnConnectStartFunc;
|
||||||
|
onConnectStop?: OnConnectStopFunc;
|
||||||
|
onConnectEnd?: OnConnectEndFunc;
|
||||||
|
onLoad?: OnLoadFunc;
|
||||||
|
onMove?: (flowTransform?: FlowTransform) => void;
|
||||||
|
onMoveStart?: (flowTransform?: FlowTransform) => void;
|
||||||
|
onMoveEnd?: (flowTransform?: FlowTransform) => void;
|
||||||
|
onSelectionChange?: (elements: Elements | null) => void;
|
||||||
|
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void;
|
||||||
|
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void;
|
||||||
|
onPaneScroll?: (event?: WheelEvent) => void;
|
||||||
|
onPaneClick?: (event: MouseEvent) => void;
|
||||||
|
onPaneContextMenu?: (event: MouseEvent) => void;
|
||||||
|
nodeTypes?: NodeTypesType;
|
||||||
|
edgeTypes?: EdgeTypesType;
|
||||||
|
connectionMode?: ConnectionMode;
|
||||||
|
connectionLineType?: ConnectionLineType;
|
||||||
|
connectionLineStyle?: CSSProperties;
|
||||||
|
connectionLineComponent?: ConnectionLineComponent;
|
||||||
|
deleteKeyCode?: KeyCode;
|
||||||
|
selectionKeyCode?: KeyCode;
|
||||||
|
multiSelectionKeyCode?: KeyCode;
|
||||||
|
zoomActivationKeyCode?: KeyCode;
|
||||||
|
snapToGrid?: boolean;
|
||||||
|
snapGrid?: [number, number];
|
||||||
|
onlyRenderVisibleElements?: boolean;
|
||||||
|
nodesDraggable?: boolean;
|
||||||
|
nodesConnectable?: boolean;
|
||||||
|
elementsSelectable?: boolean;
|
||||||
|
selectNodesOnDrag?: boolean;
|
||||||
|
paneMoveable?: boolean;
|
||||||
|
minZoom?: number;
|
||||||
|
maxZoom?: number;
|
||||||
|
defaultZoom?: number;
|
||||||
|
defaultPosition?: [number, number];
|
||||||
|
translateExtent?: TranslateExtent;
|
||||||
|
nodeExtent?: NodeExtent;
|
||||||
|
arrowHeadColor?: string;
|
||||||
|
markerEndId?: string;
|
||||||
|
zoomOnScroll?: boolean;
|
||||||
|
zoomOnPinch?: boolean;
|
||||||
|
panOnScroll?: boolean;
|
||||||
|
panOnScrollSpeed?: number;
|
||||||
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
|
zoomOnDoubleClick?: boolean;
|
||||||
|
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||||
|
onEdgeContextMenu?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseEnter?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseMove?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeMouseLeave?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeDoubleClick?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeUpdateStart?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void;
|
||||||
|
edgeUpdaterRadius?: number;
|
||||||
|
nodeTypesId?: string;
|
||||||
|
edgeTypesId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GraphViewProps extends Omit<RevueFlowProps, 'onSelectionChange' | 'elements'> {
|
||||||
|
nodeTypes: NodeTypesType;
|
||||||
|
edgeTypes: EdgeTypesType;
|
||||||
|
selectionKeyCode: KeyCode;
|
||||||
|
deleteKeyCode: KeyCode;
|
||||||
|
multiSelectionKeyCode: KeyCode;
|
||||||
|
connectionLineType: ConnectionLineType;
|
||||||
|
snapToGrid: boolean;
|
||||||
|
snapGrid: [number, number];
|
||||||
|
onlyRenderVisibleElements: boolean;
|
||||||
|
defaultZoom: number;
|
||||||
|
defaultPosition: [number, number];
|
||||||
|
arrowHeadColor: string;
|
||||||
|
selectNodesOnDrag: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@@ -912,7 +912,7 @@
|
|||||||
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":
|
"@vueuse/core@^5.1.3", "@vueuse/core@^5.1.4":
|
||||||
version "5.1.4"
|
version "5.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.1.4.tgz#c590bd1ff5cdd3d2caa033b65ed8cb42fc12a534"
|
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-5.1.4.tgz#c590bd1ff5cdd3d2caa033b65ed8cb42fc12a534"
|
||||||
integrity sha512-iuRhSaScI1GJS4N3CFPc1GajOr6F6J1Nng1I6ocNOjLx+evss6egImx9wnuX45fxqQstnh7Vfqe3FF7+0NgoWg==
|
integrity sha512-iuRhSaScI1GJS4N3CFPc1GajOr6F6J1Nng1I6ocNOjLx+evss6egImx9wnuX45fxqQstnh7Vfqe3FF7+0NgoWg==
|
||||||
|
|||||||
Reference in New Issue
Block a user