refactor(controls): dont import store but use actions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import ReactFlow, { ReactFlowProvider, addEdge, removeElements } from 'react-flow-renderer';
|
||||
import ReactFlow, { ReactFlowProvider, addEdge, removeElements, Controls } from 'react-flow-renderer';
|
||||
|
||||
import Sidebar from './Sidebar';
|
||||
|
||||
@@ -31,7 +31,9 @@ const ProviderFlow = () => {
|
||||
onElementClick={onElementClick}
|
||||
onConnect={onConnect}
|
||||
onElementsRemove={onElementsRemove}
|
||||
/>
|
||||
>
|
||||
<Controls />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
</ReactFlowProvider>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { fitView, zoomIn, zoomOut } from '../../utils/graph';
|
||||
import { useStoreState, useStoreActions } from '../../store/hooks';
|
||||
|
||||
import PlusIcon from '../../../assets/icons/plus.svg';
|
||||
@@ -20,6 +19,10 @@ interface ControlProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
const Controls = ({ style, showZoom = true, showFitView = true, showInteractive = true, className }: ControlProps) => {
|
||||
const setInteractive = useStoreActions((actions) => actions.setInteractive);
|
||||
const fitView = useStoreActions((actions) => actions.fitView);
|
||||
const zoomIn = useStoreActions((actions) => actions.zoomIn);
|
||||
const zoomOut = useStoreActions((actions) => actions.zoomOut);
|
||||
|
||||
const isInteractive = useStoreState((s) => s.isInteractive);
|
||||
const mapClasses = classnames('react-flow__controls', className);
|
||||
|
||||
@@ -27,16 +30,19 @@ const Controls = ({ style, showZoom = true, showFitView = true, showInteractive
|
||||
<div className={mapClasses} style={style}>
|
||||
{showZoom && (
|
||||
<>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={zoomIn}>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomin" onClick={() => zoomIn()}>
|
||||
<PlusIcon />
|
||||
</div>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomout" onClick={zoomOut}>
|
||||
<div className="react-flow__controls-button react-flow__controls-zoomout" onClick={() => zoomOut()}>
|
||||
<MinusIcon />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{showFitView && (
|
||||
<div className="react-flow__controls-button react-flow__controls-fitview" onClick={() => fitView()}>
|
||||
<div
|
||||
className="react-flow__controls-button react-flow__controls-fitview"
|
||||
onClick={() => fitView({ padding: 0.1 })}
|
||||
>
|
||||
<FitviewIcon />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { memo, ComponentType, CSSProperties } from 'react';
|
||||
import cx from 'classnames';
|
||||
|
||||
import store from '../../store';
|
||||
import { useStoreActions } from '../../store/hooks';
|
||||
import { ElementId, Edge, EdgeCompProps } from '../../types';
|
||||
|
||||
interface EdgeWrapperProps {
|
||||
@@ -38,6 +38,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
className,
|
||||
...rest
|
||||
}: EdgeWrapperProps) => {
|
||||
const setSelectedElements = useStoreActions((a) => a.setSelectedElements);
|
||||
const edgeClasses = cx('react-flow__edge', `react-flow__edge-${type}`, className, { selected, animated });
|
||||
const edgeGroupStyle: CSSProperties = {
|
||||
pointerEvents: isInteractive ? 'all' : 'none',
|
||||
@@ -47,7 +48,7 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch.setSelectedElements({ id, source, target });
|
||||
setSelectedElements({ id, source, target });
|
||||
|
||||
if (onClick) {
|
||||
onClick({ id, source, target, type });
|
||||
|
||||
+2
-10
@@ -1,5 +1,5 @@
|
||||
import { useEffect, MutableRefObject } from 'react';
|
||||
import { zoom, zoomIdentity } from 'd3-zoom';
|
||||
import { zoom } from 'd3-zoom';
|
||||
import { select, event } from 'd3-selection';
|
||||
|
||||
import { useStoreState, useStoreActions } from '../store/hooks';
|
||||
@@ -11,8 +11,6 @@ interface UseD3ZoomParams {
|
||||
}
|
||||
|
||||
export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): void => {
|
||||
const transform = useStoreState((s) => s.transform);
|
||||
const d3Selection = useStoreState((s) => s.d3Selection);
|
||||
const d3Zoom = useStoreState((s) => s.d3Zoom);
|
||||
|
||||
const initD3 = useStoreActions((actions) => actions.initD3);
|
||||
@@ -35,7 +33,7 @@ export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): voi
|
||||
d3Zoom.on('zoom', null);
|
||||
} else {
|
||||
d3Zoom.on('zoom', () => {
|
||||
if (event.sourceEvent && event.sourceEvent.target !== zoomPane.current) {
|
||||
if (!event.sourceEvent || (event.sourceEvent && event.sourceEvent.target !== zoomPane.current)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,12 +43,6 @@ export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): voi
|
||||
onMove();
|
||||
}
|
||||
});
|
||||
|
||||
if (d3Selection && d3Zoom) {
|
||||
// we need to restore the graph transform otherwise d3 zoom transform and graph transform are not synced
|
||||
const graphTransform = zoomIdentity.translate(transform[0], transform[1]).scale(transform[2]);
|
||||
d3Selection.call(d3Zoom.transform, graphTransform);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
+52
-1
@@ -1,6 +1,7 @@
|
||||
import { createStore, Action, action } from 'easy-peasy';
|
||||
import { createStore, Action, action, Thunk, thunk } from 'easy-peasy';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { Selection as D3Selection, ZoomBehavior } from 'd3';
|
||||
import { zoomIdentity } from 'd3-zoom';
|
||||
|
||||
import { getDimensions } from '../utils';
|
||||
import { getHandleBounds } from '../components/Nodes/utils';
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
HandleType,
|
||||
SetConnectionId,
|
||||
NodePosUpdate,
|
||||
FitViewParams,
|
||||
} from '../types';
|
||||
|
||||
type TransformXYK = {
|
||||
@@ -122,6 +124,11 @@ export interface StoreModel {
|
||||
setUserSelection: Action<StoreModel, XYPosition>;
|
||||
updateUserSelection: Action<StoreModel, XYPosition>;
|
||||
unsetUserSelection: Action<StoreModel>;
|
||||
|
||||
fitView: Action<StoreModel, FitViewParams>;
|
||||
zoom: Action<StoreModel, number>;
|
||||
zoomIn: Thunk<StoreModel>;
|
||||
zoomOut: Thunk<StoreModel>;
|
||||
}
|
||||
|
||||
export const storeModel: StoreModel = {
|
||||
@@ -370,6 +377,50 @@ export const storeModel: StoreModel = {
|
||||
setInteractive: action((state, isInteractive) => {
|
||||
state.isInteractive = isInteractive;
|
||||
}),
|
||||
|
||||
fitView: action((state, { padding = 0.1 }) => {
|
||||
const { nodes, width, height, d3Selection, d3Zoom } = state;
|
||||
|
||||
if (!d3Selection || !d3Zoom || !nodes.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bounds = getRectOfNodes(nodes);
|
||||
const maxBoundsSize = Math.max(bounds.width, bounds.height);
|
||||
const k = Math.min(width, height) / (maxBoundsSize + maxBoundsSize * padding);
|
||||
const boundsCenterX = bounds.x + bounds.width / 2;
|
||||
const boundsCenterY = bounds.y + bounds.height / 2;
|
||||
const transform = [width / 2 - boundsCenterX * k, height / 2 - boundsCenterY * k];
|
||||
const fittedTransform = zoomIdentity.translate(transform[0], transform[1]).scale(k);
|
||||
|
||||
d3Selection.call(d3Zoom.transform, fittedTransform);
|
||||
|
||||
state.transform = [fittedTransform.x, fittedTransform.y, fittedTransform.k];
|
||||
}),
|
||||
|
||||
zoom: action((state, amount) => {
|
||||
const { d3Zoom, d3Selection, transform } = state;
|
||||
const nextZoom = transform[2] + amount;
|
||||
|
||||
if (d3Zoom && d3Selection) {
|
||||
d3Zoom.scaleTo(d3Selection, nextZoom);
|
||||
|
||||
const graphTransform = zoomIdentity.translate(transform[0], transform[1]).scale(nextZoom);
|
||||
d3Selection.call(d3Zoom.transform, graphTransform);
|
||||
|
||||
console.log(graphTransform);
|
||||
|
||||
state.transform = [graphTransform.x, graphTransform.y, graphTransform.k];
|
||||
}
|
||||
}),
|
||||
|
||||
zoomIn: thunk((actions) => {
|
||||
actions.zoom(0.2);
|
||||
}),
|
||||
|
||||
zoomOut: thunk((actions) => {
|
||||
actions.zoom(-0.2);
|
||||
}),
|
||||
};
|
||||
|
||||
const store = createStore(storeModel);
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ export interface WrapNodeProps {
|
||||
}
|
||||
|
||||
export type FitViewParams = {
|
||||
padding: number;
|
||||
padding?: number;
|
||||
};
|
||||
export type FitViewFunc = (fitViewOptions: FitViewParams) => void;
|
||||
export type ProjectFunc = (position: XYPosition) => XYPosition;
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ export const getConnectedEdges = (nodes: Node[], edges: Edge[]): Edge[] => {
|
||||
});
|
||||
};
|
||||
|
||||
export const fitView = ({ padding }: FitViewParams = { padding: 0.1 }): void => {
|
||||
export const fitView = ({ padding = 0.1 }: FitViewParams = { padding: 0.1 }): void => {
|
||||
const { nodes, width, height, d3Selection, d3Zoom } = store.getState();
|
||||
|
||||
if (!d3Selection || !d3Zoom || !nodes.length) {
|
||||
|
||||
Reference in New Issue
Block a user