Files
xyflow/src/container/EdgeRenderer/MarkerDefinitions.tsx
T

118 lines
2.8 KiB
TypeScript

import React, { useMemo } from 'react';
import { useStore } from '../../store';
import { EdgeMarker, ArrowHeadType, ReactFlowState } from '../../types';
import { getMarkerId } from '../../utils/graph';
interface MarkerProps extends EdgeMarker {
id: string;
}
interface MarkerDefinitionsProps {
defaultColor: string;
}
type SymbolProps = Omit<MarkerProps, 'id' | 'type'>;
const ArrowSymbol = ({ color = 'none', strokeWidth = 1 }: SymbolProps) => {
return (
<polyline
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
fill="none"
points="-5,-4 0,0 -5,4"
/>
);
};
const ArrowClosedSymbol = ({ color = 'none', strokeWidth = 1 }: SymbolProps) => {
return (
<polyline
stroke={color}
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={strokeWidth}
fill={color}
points="-5,-4 0,0 -5,4 -5,-4"
/>
);
};
const markerSymbols = {
[ArrowHeadType.Arrow]: ArrowSymbol,
[ArrowHeadType.ArrowClosed]: ArrowClosedSymbol,
};
const Marker = ({
id,
type,
color,
width = 12.5,
height = 12.5,
units = 'strokeWidth',
strokeWidth,
orient = 'auto',
}: MarkerProps) => {
const Symbol = markerSymbols[type];
return (
<marker
className="react-flow__arrowhead"
id={id}
markerUnits={units}
markerWidth={`${width}`}
markerHeight={`${height}`}
viewBox="-10 -10 20 20"
orient={orient}
refX="0"
refY="0"
>
<Symbol color={color} strokeWidth={strokeWidth} />
</marker>
);
};
const edgesSelector = (s: ReactFlowState) => s.edges;
const MarkerDefinitions = ({ defaultColor }: MarkerDefinitionsProps) => {
const edges = useStore(edgesSelector);
const markers = useMemo(() => {
const ids: string[] = [];
return edges.reduce<MarkerProps[]>((markers, edge) => {
[edge.markerStart, edge.markerEnd].forEach((marker) => {
if (marker && typeof marker === 'object') {
const markerId = getMarkerId(marker);
if (!ids.includes(markerId)) {
markers.push({ id: markerId, color: marker.color || defaultColor, ...marker });
ids.push(markerId);
}
}
});
return markers.sort((a, b) => a.id.localeCompare(b.id));
}, []);
}, [edges, defaultColor]);
return (
<defs>
{markers.map((marker: MarkerProps) => (
<Marker
id={marker.id}
key={marker.id}
type={marker.type}
color={marker.color}
width={marker.width}
height={marker.height}
units={marker.units}
strokeWidth={marker.strokeWidth}
orient={marker.orient}
/>
))}
</defs>
);
};
MarkerDefinitions.displayName = 'MarkerDefinitions';
export default MarkerDefinitions;