Merge pull request #2906 from wbkd/feat/custom-minimap-nodes

feat: add prop to render custom node inside minimap
This commit is contained in:
Moritz Klack
2023-03-13 13:10:02 +01:00
committed by GitHub
6 changed files with 108 additions and 19 deletions

View File

@@ -0,0 +1,5 @@
---
'@reactflow/minimap': minor
---
feat: add nodeComponent prop for passing custom component

View File

@@ -5,6 +5,7 @@ import Basic from '../examples/Basic';
import Backgrounds from '../examples/Backgrounds';
import ControlledUncontrolled from '../examples/ControlledUncontrolled';
import CustomConnectionLine from '../examples/CustomConnectionLine';
import CustomMiniMapNode from '../examples/CustomMiniMapNode';
import CustomNode from '../examples/CustomNode';
import DefaultNodes from '../examples/DefaultNodes';
import DragHandle from '../examples/DragHandle';
@@ -77,6 +78,11 @@ const routes: IRoute[] = [
path: '/custom-connectionline',
component: CustomConnectionLine,
},
{
name: 'Custom Minimap Node',
path: '/custom-minimap-node',
component: CustomMiniMapNode,
},
{
name: 'Custom Node',
path: '/custom-node',

View File

@@ -0,0 +1,74 @@
import { MouseEvent, CSSProperties, useCallback } from 'react';
import ReactFlow, {
addEdge,
Background,
BackgroundVariant,
Connection,
Controls,
Edge,
MiniMap,
MiniMapNodeProps,
Node,
ReactFlowInstance,
useEdgesState,
useNodesState,
} from 'reactflow';
const onInit = (reactFlowInstance: ReactFlowInstance) => console.log('flow loaded:', reactFlowInstance);
const onNodeClick = (_: MouseEvent, node: Node) => console.log('click', node);
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node);
const buttonStyle: CSSProperties = {
position: 'absolute',
left: 10,
top: 10,
zIndex: 4,
};
const CustomMiniMapNode = ({ x, y, width, height, color }: MiniMapNodeProps) => (
<circle cx={x} cy={y} r={Math.max(width, height) / 2} fill={color} />
);
const CustomMiniMapNodeFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const onConnect = useCallback((params: Connection | Edge) => setEdges((els) => addEdge(params, els)), [setEdges]);
const addRandomNode = () => {
const nodeId = (nodes.length + 1).toString();
const newNode: Node = {
id: nodeId,
data: { label: `Node: ${nodeId}` },
position: {
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
},
};
setNodes((nds) => nds.concat(newNode));
};
return (
<ReactFlow
nodes={nodes}
edges={edges}
onInit={onInit}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onNodeClick={onNodeClick}
onConnect={(p) => onConnect(p)}
onNodeDragStop={onNodeDragStop}
onlyRenderVisibleElements={false}
>
<Controls />
<Background variant={BackgroundVariant.Lines} />
<MiniMap nodeComponent={CustomMiniMapNode} />
<button type="button" onClick={addRandomNode} style={buttonStyle}>
add node
</button>
</ReactFlow>
);
};
export default CustomMiniMapNodeFlow;

View File

@@ -55,6 +55,9 @@ function MiniMap({
nodeClassName = '',
nodeBorderRadius = 5,
nodeStrokeWidth = 2,
// We need to rename the prop to be `CapitalCase` so that JSX will render it as
// a component properly.
nodeComponent: NodeComponent = MiniMapNode,
maskColor = 'rgb(240, 240, 240, 0.6)',
maskStrokeColor = 'none',
maskStrokeWidth = 1,
@@ -181,7 +184,7 @@ function MiniMap({
const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
return (
<MiniMapNode
<NodeComponent
key={node.id}
x={x}
y={y}

View File

@@ -1,23 +1,7 @@
import { memo } from 'react';
import type { CSSProperties, MouseEvent } from 'react';
import type { MiniMapNodeProps } from './types';
import cc from 'classcat';
interface MiniMapNodeProps {
id: string;
x: number;
y: number;
width: number;
height: number;
borderRadius: number;
className: string;
color: string;
shapeRendering: string;
strokeColor: string;
strokeWidth: number;
style?: CSSProperties;
onClick?: (event: MouseEvent, id: string) => void;
}
const MiniMapNode = ({
id,
x,

View File

@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { HTMLAttributes, MouseEvent } from 'react';
import type { ComponentType, CSSProperties, HTMLAttributes, MouseEvent } from 'react';
import type { Node, PanelPosition, XYPosition } from '@reactflow/core';
export type GetMiniMapNodeAttribute<NodeData = any> = (node: Node<NodeData>) => string;
@@ -10,6 +10,7 @@ export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, '
nodeClassName?: string | GetMiniMapNodeAttribute<NodeData>;
nodeBorderRadius?: number;
nodeStrokeWidth?: number;
nodeComponent?: ComponentType<MiniMapNodeProps>;
maskColor?: string;
maskStrokeColor?: string;
maskStrokeWidth?: number;
@@ -20,3 +21,19 @@ export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, '
zoomable?: boolean;
ariaLabel?: string | null;
};
export interface MiniMapNodeProps {
id: string;
x: number;
y: number;
width: number;
height: number;
borderRadius: number;
className: string;
color: string;
shapeRendering: string;
strokeColor: string;
strokeWidth: number;
style?: CSSProperties;
onClick?: (event: MouseEvent, id: string) => void;
}