Force - Customer Force Layout 2
Circular Force Layout with Track Constraints
Demonstrates an advanced custom force layout that constrains nodes to move along concentric circular tracks while applying force-directed physics for hierarchical radial organization.
Circular Force Layout with Track Constraints
Functional Overview
This example demonstrates an advanced custom force layout that constrains nodes to move along concentric circular tracks while still applying force-directed physics. Nodes are organized into hierarchical layers (circular tracks) with the root at the center, creating an organized radial layout.
Implementation of Key Features
Circular Track Constraints
The custom layout enforces that nodes move only along their assigned circular orbit:
- Track Assignment: Each node has a
limitCircularproperty specifying which circular track it belongs to - Track Radii: Configurable array of diameters for each circular layer
- Position Calculation: The
getOvalPoint()function calculates positions on circular paths using angle and radius
const [circularSet, setCircularSet] = useState<number[]>([200, 550, 800, 1020, 1260]);
const updateLayoutCircleSet = async (myLayout: MyForceLayout) => {
myLayout.setLevelCircleSet(circularSet.map(v => v / 2 - 60));
};
Hierarchical Node Organization
Nodes use custom properties for organization:
- myLevel: Style classification (root, level1-4)
- myColor: Color scheme for different branches
- limitCircular: Which circular track the node should occupy
- force_weight: Resistance to movement (heavier nodes move less)
{ id: 'a', text: '', color: '#cccccc', force_weight: 10000,
disablePointEvent: true, disableDrag: true,
data: { myColor: 'root-color', myLevel: 'my-root', limitCircular: 0 } }
Fixed Position Nodes
Level 1 nodes are fixed at specific positions on the innermost track:
- Use
fixed: trueto prevent force layout from moving them - Manually set x, y coordinates using polar coordinates
- Configure
expandHolderPositionfor collapse button placement
leve1NodeForSystem.fixed = true;
let nodePoint = getOvalPoint(rootNodeJson.x, rootNodeJson.y, circularSet[0] / 2, 90);
leve1NodeForSystem.x = nodePoint.x;
leve1NodeForSystem.y = nodePoint.y;
leve1NodeForSystem.expandHolderPosition = 'right';
Custom Node Styling with Slots
Use RGSlotOnNode to render different node styles based on level:
- Root node displays an image
- Other levels show colored text nodes
<RGSlotOnNode>
{({ node }) => {
return node.data?.myLevel === 'my-root' ? (
<div className={`my-node ${node.data.myColor} ${node.data.myLevel}`}>
<div className="node-content">
<img src={node.data.img} alt="" />
</div>
</div>
) : (
<div className={`my-node ${node.data?.myColor} ${node.data?.myLevel}`}>
<div className="node-content">
<div className="my-node-text">{node.text}</div>
</div>
</div>
);
}}
</RGSlotOnNode>
Visual Circular Tracks
Concentric circles are rendered as absolute positioned div elements with CSS variables for dynamic sizing:
<div style={{ position: 'absolute', left: `${circularSet[4] * -0.5}px`, top: `${circularSet[4] * -0.5}px` }}>
<div className="c-circle" style={{ '--circle-size': `${circularSet[4]}px` }}>
<div className="circle-title">Close In-Laws</div>
{/* Nested circles */}
</div>
</div>
Dashed Line Styles
Lines are configured with custom dash patterns and arrows disabled:
graphJsonData.lines.forEach(line => {
line.dashType = 2;
line.showEndArrow = false;
});
Creative Use Cases
- Family Tree Visualization: Display generational relationships in concentric circles
- Organization Charts: Show departments and teams in radial layers
- Network Topology: Visualize network layers with center as core infrastructure
- Solar System Models: Display celestial bodies in orbital tracks
- Skill Radars: Show skills or competencies organized by category rings