Visx is a library that lets us add graphics to our React app easily.
In this article, we’ll look at how to use it to add a dendrogram into our React app.
Install Required Packages
We have to install a few modules.
To get started, we run:
npm i @visx/gradient @visx/group @visx/hierarchy @visx/responsive @visx/shape
to install the packages.
Create the Dendrogram
We can create the dendrogram by writing:
import React, { useMemo } from "react";
import { Group } from "@visx/group";
import { Cluster, hierarchy } from "@visx/hierarchy";
import { LinkVertical } from "@visx/shape";
import { LinearGradient } from "@visx/gradient";
const citrus = "#ddf163";
const white = "#ffffff";
const green = "#79d259";
const aqua = "#37ac8c";
const merlinsbeard = "#f7f7f3";
const background = "#306c90";
const clusterData = {
name: "$",
children: [
{
name: "A",
children: [
{ name: "A1" },
{ name: "A2" },
{
name: "C",
children: [
{
name: "C1"
}
]
}
]
},
{
name: "B",
children: [{ name: "B1" }, { name: "B2" }]
},
{
name: "X",
children: [
{
name: "Z"
}
]
}
]
};
function Node({ node }) {
const isRoot = node.depth === 0;
const isParent = !!node.children;
if (isRoot) return <RootNode node={node} />;
return (
<Group top={node.y} left={node.x}>
{node.depth !== 0 && (
<circle
r={12}
fill={background}
stroke={isParent ? white : citrus}
onClick={() => {
alert(`clicked: ${JSON.stringify(node.data.name)}`);
}}
/>
)}
<text
dy=".33em"
fontSize={9}
fontFamily="Arial"
textAnchor="middle"
style={{ pointerEvents: "none" }}
fill={isParent ? white : citrus}
>
{node.data.name}
</text>
</Group>
);
}
function RootNode({ node }) {
const width = 40;
const height = 20;
const centerX = -width / 2;
const centerY = -height / 2;
return (
<Group top={node.y} left={node.x}>
<rect
width={width}
height={height}
y={centerY}
x={centerX}
fill="url('#top')"
/>
<text
dy=".33em"
fontSize={9}
fontFamily="Arial"
textAnchor="middle"
style={{ pointerEvents: "none" }}
fill={background}
>
{node.data.name}
</text>
</Group>
);
}
const defaultMargin = { top: 40, left: 0, right: 0, bottom: 40 };
function Example({ width, height, margin = defaultMargin }) {
const data = useMemo(() => hierarchy(clusterData), []);
const xMax = width - margin.left - margin.right;
const yMax = height - margin.top - margin.bottom;
return width < 10 ? null : (
<svg width={width} height={height}>
<LinearGradient id="top" from={green} to={aqua} />
<rect width={width} height={height} rx={14} fill={background} />
<Cluster root={data} size={[xMax, yMax]}>
{(cluster) => (
<Group top={margin.top} left={margin.left}>
{cluster.links().map((link, i) => (
<LinkVertical
key={`cluster-link-${i}`}
data={link}
stroke={merlinsbeard}
strokeWidth="1"
strokeOpacity={0.2}
fill="none"
/>
))}
{cluster.descendants().map((node, i) => (
<Node key={`cluster-node-${i}`} node={node} />
))}
</Group>
)}
</Cluster>
</svg>
);
}
export default function App() {
return (
<div className="App">
<Example width={500} height={300} />
</div>
);
}
We create the variables for the dendrogram at the top of the code.
The clusterData
variable has the tree data for the dendrogram.
Next, we create the Node
component to render the node of the dendrogram.
It has some text
inside the Group
component.
The root node is created with the RootBNode
component.
It’s different from Node
in that it has an extra rectangle surrounding the text.
The Example
component is where the whole tree diagram comes together.
We render the tree nodes with the render prop of the Cluster
component.
The data is set as the root
prop’s value.
In the Group
component of the render prop, we have the LinkVertical
component to add the lines to link the parent and child nodes.
We get the child nodes wit the cluster.descendants
method.
And we map them to Node
s.
Conclusion
We can add a dendrogram into our React app with the Visx library.