Public
Edited
Jun 20, 2023
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
treeElm = renderTree(
nodes,
(n) => n.children,
(n, elm) => {
const { content = "" } = n;
const phrases = content
.split(/\./gim)
.map((s) => s.trim())
.filter((s) => !!s)
.map((s) => `${s}.`);
for (let phrase of phrases) {
const div = document.createElement("div");
elm.style.paddingBottom = "0.125em";
elm.appendChild(div);
div.innerText = phrase;
}
}
)
Insert cell
nodes = ({
content: `Lorem ipsum dolor sit amet.`,
children: [
{
content: `Consectetur adipiscing elit.`,
children: [
{
content: `Curabitur in dui id ipsum consectetur convallis. Nullam accumsan porttitor risus ut vestibulum. Donec vulputate, enim in posuere cursus, metus nulla viverra sapien, sed fermentum velit tortor sit amet libero.`
},
{
content: `Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.`,
children: [
{
content: `Nunc ut rutrum odio.`
},
{
content: `Aenean sollicitudin mi ut erat porta posuere.
Fusce mollis neque quis ultrices porta. Etiam in magna sed sem efficitur faucibus. `,
children: [
{
content: `Vestibulum ac ante sed magna lacinia euismod.`,
children: [
{
content: `Lorem ipsum dolor sit amet, consectetur adipiscing elit. `
},
{
content: `Integer quis orci vitae arcu lacinia malesuada. Phasellus id justo pellentesque, maximus erat suscipit, venenatis elit. Donec semper auctor magna, non viverra urna scelerisque et. `,
children: [
{
content: `Quisque pharetra augue dolor.`,
children: [{ content: `Et dapibus nisl suscipit a` }]
}
]
}
]
},
{
content: `Quisque finibus, lectus eget dictum fringilla, neque eros facilisis nunc, id auctor ligula justo vitae sapien. Nullam non quam mauris. `
}
]
},
{
content: ` Aliquam erat volutpat. Nam tortor ante, feugiat eget nisi eu, sodales aliquam felis. Phasellus id mattis erat. Vivamus eget magna at felis blandit bibendum.`
}
]
},
{
content: `Curabitur in dui id ipsum consectetur convallis. Nullam accumsan porttitor risus ut vestibulum. Donec vulputate, enim in posuere cursus, metus nulla viverra sapien, sed fermentum velit tortor sit amet libero.`
}
]
},
{
content: `Curabitur ac mi quis est aliquam finibus.`
},
{
content: `In at tincidunt tellus. `
},
{
content: `Phasellus ullamcorper ultrices gravida. In nec orci vitae nisl commodo maximus. Aenean sollicitudin mi ut erat porta posuere`
}
]
})
Insert cell
function renderTree(data, getChildren, render) {
const tree = newElement("tree");
renderTreeNodes(data, getChildren, tree);
return tree;
function renderTreeNodes(node, getChildren, parentElm) {
const treeNodeContentElm = newElement("tree-node-content", parentElm);
render(node, treeNodeContentElm);
const children = getChildren(node);
if (!children) return;
for (let child of children) {
const treeNodeElm = newElement("tree-node", parentElm);
renderTreeNodes(child, getChildren, treeNodeElm);
}
}
function newElement(className, parent) {
const div = document.createElement("div");
div.classList.add(className);
if (parent) {
parent.appendChild(div);
}
return div;
}
}
Insert cell
function getTreeCss() {
return `
.tree {
--tree-line-width: 1px;
--tree-line-color: silver;
--tree-connector-radius: 0.1em;
--tree-connector-length: 0.5em;
--tree-connector-height: 0.6em;
--tree-content-padding: 0.5em;
position: relative;
}
.tree .tree-node {
position: relative;
padding-inline-start: var(--tree-connector-length);
border-inline-start: var(--tree-line-width) solid var(--tree-line-color);
}
.tree .tree-node:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
width: var(--tree-connector-length);
height: var(--tree-connector-height);
max-height: 100%;
margin-inline-start: calc(0em - var(--tree-line-width));
border-bottom: var(--tree-line-width) solid var(--tree-line-color);
border-inline-start: var(--tree-line-width) solid var(--tree-line-color);
border-end-start-radius: var(--tree-connector-radius);
}
.tree .tree-node:last-child {
border-inline-start: var(--tree-line-width) solid transparent;
}
.tree .tree-node > .tree-node-content {
position: relative;
padding-inline-start: var(--tree-content-padding);
}
.tree .tree-node > .tree-node-content:before {
content: "";
position: absolute;
top: var(--tree-connector-height);
left: 0;
right: 0;
width: var(--tree-line-width);
height: calc(100% - var(--tree-connector-height));
border-inline-start: var(--tree-line-width) solid var(--tree-line-color);
}
.tree .tree-node > .tree-node-content:last-child:before {
border-inline-start: var(--tree-line-width) solid transparent;
}
`;
}
Insert cell
/* Tree CSS styles are in this cell */
<style>
${getTreeCss()}
</style>
Insert cell
/* Simple CSS styles are in this cell */
<style>
/* * /
.tree {
--tree-line-width: 1px;
--tree-line-color: silver;
--tree-connector-radius: 0.1em;
--tree-connector-length: 0.5em;
--tree-connector-height: 0.6em;
--tree-content-padding: 0.5em;
position: relative;
}
.tree .tree-node {
position: relative;
padding-inline-start: calc(var(--tree-content-padding) + var(--tree-connector-length));
border-inline-start: var(--tree-line-width) solid var(--tree-line-color);
}
.tree .tree-node:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
width: var(--tree-connector-length);
height: var(--tree-connector-height);
max-height: 100%;
margin-inline-start: calc(0em - var(--tree-line-width));
border-bottom: var(--tree-line-width) solid var(--tree-line-color);
border-inline-start: var(--tree-line-width) solid var(--tree-line-color);
border-end-start-radius: var(--tree-connector-radius);
}
.tree .tree-node:last-child {
border-inline-start: var(--tree-line-width) solid transparent;
}
/* */
</style>
Insert cell
treeProps = ({
direction: rtl ? "rtl" : "ltr",
"--tree-line-width": `${treeLineWidth}px`,
"--tree-line-color": treeLineColor,
"--tree-connector-radius": `${treeConnectorRadius}em`,
"--tree-connector-length": `${treeConnectorLength}em`,
"--tree-connector-height": `${treeConnectorHeight}em`,
"--tree-connector-height": `${treeConnectorHeight}em`,
"--tree-content-padding": `${treeContentPadding}em`
})
Insert cell
function applyTreeProperties(elm, props) {
for (let [prop, value] of Object.entries(props)) {
if (prop[0] === '-') {
elm.style.setProperty(prop, value);
} else {
elm.style[prop] = value;
}
}
return elm;
}
Insert cell
applyTreeProperties(treeElm, {
...treeProps,
maxHeight: "300px",
overflow: "auto"
})
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more