refactor: NodeRenderer (#51)
* refactor: NodeRenderer * fix getNodesInside partially param * add `skipInvisible` prop * refactor(noderenderer): rename skipInvisble to onlyRenderVisibleNodes closes #40
This commit is contained in:
Vendored
+130
-1153
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+130
-1153
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-1
@@ -20,6 +20,7 @@ export interface GraphViewProps {
|
||||
backgroundType: GridType;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [number, number];
|
||||
onlyRenderVisibleNodes: boolean;
|
||||
}
|
||||
declare const GraphView: React.MemoExoticComponent<({ nodeTypes, edgeTypes, onMove, onLoad, onElementClick, onNodeDragStop, connectionLineType, connectionLineStyle, selectionKeyCode, onElementsRemove, deleteKeyCode, elements, showBackground, backgroundGap, backgroundColor, backgroundType, onConnect, snapToGrid, snapGrid, }: GraphViewProps) => JSX.Element>;
|
||||
declare const GraphView: React.MemoExoticComponent<({ nodeTypes, edgeTypes, onMove, onLoad, onElementClick, onNodeDragStop, connectionLineType, connectionLineStyle, selectionKeyCode, onElementsRemove, deleteKeyCode, elements, showBackground, backgroundGap, backgroundColor, backgroundType, onConnect, snapToGrid, snapGrid, onlyRenderVisibleNodes }: GraphViewProps) => JSX.Element>;
|
||||
export default GraphView;
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
onElementClick: () => void;
|
||||
onNodeDragStop: () => void;
|
||||
onlyRenderVisibleNodes?: boolean;
|
||||
}
|
||||
declare const NodeRenderer: React.MemoExoticComponent<(props: NodeRendererProps) => JSX.Element>;
|
||||
declare const NodeRenderer: React.MemoExoticComponent<({ onlyRenderVisibleNodes, ...props }: NodeRendererProps) => JSX.Element>;
|
||||
export default NodeRenderer;
|
||||
|
||||
Vendored
+4
-2
@@ -20,10 +20,11 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
backgroundColor: string;
|
||||
backgroundType: GridType;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [16, 16];
|
||||
snapGrid: [number, number];
|
||||
onlyRenderVisibleNodes: boolean;
|
||||
}
|
||||
declare const ReactFlow: {
|
||||
({ style, onElementClick, elements, children, nodeTypes, edgeTypes, onLoad, onMove, onElementsRemove, onConnect, onNodeDragStop, connectionLineType, connectionLineStyle, deleteKeyCode, selectionKeyCode, showBackground, backgroundGap, backgroundType, backgroundColor, snapToGrid, snapGrid, }: ReactFlowProps): JSX.Element;
|
||||
({ style, onElementClick, elements, children, nodeTypes, edgeTypes, onLoad, onMove, onElementsRemove, onConnect, onNodeDragStop, connectionLineType, connectionLineStyle, deleteKeyCode, selectionKeyCode, showBackground, backgroundGap, backgroundType, backgroundColor, snapToGrid, snapGrid, onlyRenderVisibleNodes }: ReactFlowProps): JSX.Element;
|
||||
displayName: string;
|
||||
defaultProps: {
|
||||
onElementClick: () => void;
|
||||
@@ -52,6 +53,7 @@ declare const ReactFlow: {
|
||||
backgroundType: GridType;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: number[];
|
||||
onlyRenderVisibleNodes: boolean;
|
||||
};
|
||||
};
|
||||
export default ReactFlow;
|
||||
|
||||
Vendored
+6
-1
@@ -2,7 +2,12 @@ import { CSSProperties, SVGAttributes } from 'react';
|
||||
export declare type ElementId = string;
|
||||
export declare type Elements = Array<Node | Edge>;
|
||||
export declare type Transform = [number, number, number];
|
||||
export declare type Position = 'left' | 'top' | 'right' | 'bottom';
|
||||
export declare enum Position {
|
||||
Left = "left",
|
||||
Top = "top",
|
||||
Right = "right",
|
||||
Bottom = "bottom"
|
||||
}
|
||||
export declare type XYPosition = {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
Vendored
+1
-1
@@ -7,7 +7,7 @@ export declare const addEdge: (edgeParams: Edge, elements: (Node | Edge)[]) => (
|
||||
export declare const parseElement: (element: Node | Edge, transform: [number, number, number], snapToGrid: boolean, snapGrid: [number, number]) => Node | Edge;
|
||||
export declare const getBoundsofRects: (rect1: Rect, rect2: Rect) => Rect;
|
||||
export declare const getRectOfNodes: (nodes: Node[]) => Rect;
|
||||
export declare const graphPosToZoomedPos: (pos: XYPosition, transform: [number, number, number]) => XYPosition;
|
||||
export declare const graphPosToZoomedPos: ({ x, y }: XYPosition, [tx, ty, tScale]: [number, number, number]) => XYPosition;
|
||||
export declare const getNodesInside: (nodes: Node[], rect: Rect, [tx, ty, tScale]?: [number, number, number], partially?: boolean) => Node[];
|
||||
export declare const getConnectedEdges: (nodes: Node[], edges: Edge[]) => Edge[];
|
||||
export declare const fitView: ({ padding }?: FitViewParams) => void;
|
||||
|
||||
@@ -40,6 +40,7 @@ export interface GraphViewProps {
|
||||
backgroundType: GridType;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [number, number];
|
||||
onlyRenderVisibleNodes: boolean
|
||||
}
|
||||
|
||||
const GraphView = memo(
|
||||
@@ -63,6 +64,7 @@ const GraphView = memo(
|
||||
onConnect,
|
||||
snapToGrid,
|
||||
snapGrid,
|
||||
onlyRenderVisibleNodes
|
||||
}: GraphViewProps) => {
|
||||
const zoomPane = useRef<HTMLDivElement>(null);
|
||||
const rendererNode = useRef<HTMLDivElement>(null);
|
||||
@@ -136,6 +138,7 @@ const GraphView = memo(
|
||||
nodeTypes={nodeTypes}
|
||||
onElementClick={onElementClick}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
|
||||
/>
|
||||
<EdgeRenderer
|
||||
width={state.width}
|
||||
|
||||
@@ -1,45 +1,24 @@
|
||||
import React, { memo, ComponentType } from 'react';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
import { isNode } from '../../utils/graph';
|
||||
import {
|
||||
Node,
|
||||
Transform,
|
||||
NodeTypesType,
|
||||
NodeComponentProps,
|
||||
} from '../../types';
|
||||
import { getNodesInside } from '../../utils/graph';
|
||||
import { Node, Transform, NodeTypesType, NodeComponentProps, Elements } from '../../types';
|
||||
|
||||
interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
onElementClick: () => void;
|
||||
onNodeDragStop: () => void;
|
||||
onlyRenderVisibleNodes?: boolean;
|
||||
}
|
||||
|
||||
interface NodeRendererState {
|
||||
nodes: Node[];
|
||||
transform: Transform;
|
||||
selectedElements: any;
|
||||
}
|
||||
|
||||
function renderNode(
|
||||
node: Node,
|
||||
props: NodeRendererProps,
|
||||
state: NodeRendererState
|
||||
) {
|
||||
function renderNode(node: Node, props: NodeRendererProps, transform: Transform, selectedElements: Elements) {
|
||||
const nodeType = node.type || 'default';
|
||||
|
||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<NodeComponentProps>;
|
||||
if (!props.nodeTypes[nodeType]) {
|
||||
console.warn(
|
||||
`No node type found for type "${nodeType}". Using fallback type "default".`
|
||||
);
|
||||
console.warn(`No node type found for type "${nodeType}". Using fallback type "default".`);
|
||||
}
|
||||
|
||||
const NodeComponent = (props.nodeTypes[nodeType] ||
|
||||
props.nodeTypes.default) as ComponentType<NodeComponentProps>;
|
||||
const selected = state.selectedElements
|
||||
.filter(isNode)
|
||||
.map((e: Node) => e.id)
|
||||
.includes(node.id);
|
||||
const isSelected = selectedElements.some(({ id }) => id === node.id);
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
@@ -51,28 +30,26 @@ function renderNode(
|
||||
yPos={node.__rg.position.y}
|
||||
onClick={props.onElementClick}
|
||||
onNodeDragStop={props.onNodeDragStop}
|
||||
transform={state.transform}
|
||||
selected={selected}
|
||||
transform={transform}
|
||||
selected={isSelected}
|
||||
style={node.style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const NodeRenderer = memo((props: NodeRendererProps) => {
|
||||
const state: NodeRendererState = useStoreState(s => ({
|
||||
nodes: s.nodes,
|
||||
transform: s.transform,
|
||||
selectedElements: s.selectedElements,
|
||||
}));
|
||||
const NodeRenderer = memo(({ onlyRenderVisibleNodes = true, ...props }: NodeRendererProps) => {
|
||||
const { nodes, transform, selectedElements, width, height } = useStoreState(s => s);
|
||||
|
||||
const { transform, nodes } = state;
|
||||
const [tx, ty, tScale] = transform;
|
||||
const transformStyle = {
|
||||
transform: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`,
|
||||
transform: `translate(${tx}px,${ty}px) scale(${tScale})`,
|
||||
};
|
||||
|
||||
const renderNodes = onlyRenderVisibleNodes ? getNodesInside(nodes, { x: 0, y: 0, width, height }, transform, true) : nodes;
|
||||
|
||||
return (
|
||||
<div className="react-flow__nodes" style={transformStyle}>
|
||||
{nodes.map(node => renderNode(node, props, state))}
|
||||
{renderNodes.map(node => renderNode(node, props, transform, selectedElements))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,7 +48,8 @@ export interface ReactFlowProps
|
||||
backgroundColor: string;
|
||||
backgroundType: GridType;
|
||||
snapToGrid: boolean;
|
||||
snapGrid: [16, 16];
|
||||
snapGrid: [number, number];
|
||||
onlyRenderVisibleNodes: boolean
|
||||
}
|
||||
|
||||
const ReactFlow = ({
|
||||
@@ -73,6 +74,7 @@ const ReactFlow = ({
|
||||
backgroundColor,
|
||||
snapToGrid,
|
||||
snapGrid,
|
||||
onlyRenderVisibleNodes
|
||||
}: ReactFlowProps) => {
|
||||
const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []);
|
||||
const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []);
|
||||
@@ -100,6 +102,7 @@ const ReactFlow = ({
|
||||
backgroundType={backgroundType}
|
||||
snapToGrid={snapToGrid}
|
||||
snapGrid={snapGrid}
|
||||
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
|
||||
/>
|
||||
{children}
|
||||
</StoreProvider>
|
||||
@@ -136,6 +139,7 @@ ReactFlow.defaultProps = {
|
||||
backgroundType: GridType.Dots,
|
||||
snapToGrid: false,
|
||||
snapGrid: [16, 16],
|
||||
onlyRenderVisibleNodes: true
|
||||
};
|
||||
|
||||
export default ReactFlow;
|
||||
|
||||
+2
-2
@@ -157,10 +157,10 @@ export const getNodesInside = (
|
||||
const overlappingArea =
|
||||
(Math.max(rBox.x, nBox.x) - Math.min(rBox.x2, nBox.x2)) * (Math.max(rBox.y, nBox.y) - Math.min(rBox.y2, nBox.y2));
|
||||
if (partially) {
|
||||
return overlappingArea > 0;
|
||||
return overlappingArea >= 0;
|
||||
}
|
||||
const area = width * height;
|
||||
return overlappingArea === area;
|
||||
return overlappingArea >= area;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user