Public
Edited
Aug 16, 2023
2 forks
Insert cell
Insert cell
chart = {

// Specify the chart’s dimensions.
const width = 928;
const height = width;

// Create the color scale.
const colorOverUnder = d3.scaleOrdinal()
.domain(["Over", "Under"])
.range(["navy", "#c91459"])

const colorCategory = d3.scaleOrdinal()
.domain(["Mindset", "Personal Thriving", "Inspiring Leadership", "Outcomes"])
.range(["#FFC72B", "#FF5E2B", "#37B4FF", "#49B5AE"])

// Compute the layout.
const pack = data => d3.pack()
.size([width, height])
.padding(3)
(d3.hierarchy(data)
.sum(d => d.value)
.sort((a, b) => b.value - a.value));
const root = pack(data);

// Create the SVG container.
const svg = d3.create("svg")
.attr("viewBox", `-${width / 2} -${height / 2} ${width} ${height}`)
.attr("width", width)
.attr("height", height)
.attr("style", `max-width: 100%; height: auto; display: block; margin: 0 -14px; cursor: pointer;`);

// Append the nodes.
const node = svg.append("g")
.selectAll("circle")
.data(root.descendants().slice(1))
.join("circle")
.attr("fake", d => console.log(d.cat))
.attr("fill", d => d.data.cat ? 'white' : colorOverUnder(d.data.overunder))
.attr('opacity', 1)
.attr('stroke', d => d.data.cat ? colorCategory(d.data.cat) : 'white')
.attr('stroke-width', 5)
.attr("pointer-events", d => !d.children ? "none" : null)
.on("click", (event, d) => focus !== d && (zoom(event, d), event.stopPropagation()));
// Append the text labels.
const label = svg.append("g")
.style("font", "20px sans-serif")
.attr("pointer-events", "none")
.attr("text-anchor", "middle")
.selectAll("text")
.data(root.descendants())
.join("text")
.style("fill-opacity", d => d.parent === root ? 0 : 1)
.style("display", d => d.parent === root ? "inline" : "none")
.text(d => d.data.name);

// Create the zoom behavior and zoom immediately in to the initial focus node.
svg.on("click", (event) => zoom(event, root));
let focus = root;
let view;
zoomTo([focus.x, focus.y, focus.r * 2]);

function zoomTo(v) {
const k = width / v[2];

view = v;

label.attr("transform", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);
node.attr("transform", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`);
node.attr("r", d => d.r * k);
}

function zoom(event, d) {
const focus0 = focus;

focus = d;

const transition = svg.transition()
.duration(event.altKey ? 7500 : 750)
.tween("zoom", d => {
const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]);
return t => zoomTo(i(t));
});

label
.filter(function(d) { return d.parent === focus || this.style.display === "inline"; })
.transition(transition)
.style("fill-opacity", d => d.parent === focus ? 1 : 0)
.on("start", function(d) { if (d.parent === focus) this.style.display = "inline"; })
.on("end", function(d) { if (d.parent !== focus) this.style.display = "none"; });
}

return svg.node();
}
Insert cell
data = ({
name: "Whole Person Model",
cat: "none",
children: [
{ name: "Mindset",
cat: "Mindset",
children: [
{ name: "Self-Efficacy", value: 2.8464286, overunder: 'Under'},
{ name: "Growth Mindset", value: 3.6053571, overunder: 'Over'},
{ name: "Self-Awareness", value: 8.6553571, overunder: 'Under'},
] },
{ name: "Personal Thriving", cat: "Personal Thriving", children: [
{ name: "Social Thriving", cat: "Personal Thriving", children: [
{ name: "Social Connection", value: 2.8178571, overunder: 'Under'},
{ name: "Authenticity", value: 4.6017857, overunder: 'Over'},
{ name: "Empathy", value: 5.9150268, overunder: 'Over'},
] },
{ name: "Emotional Thriving",
cat: "Personal Thriving",
children: [
{ name: "Self-Compassion", value: 2.8473214, overunder: 'Under'},
{ name: "Emotional Regulation", value: 2.463392, overunder: 'Under'},
] },
{ name: "Cognitive Thriving",
cat: "Personal Thriving",
children: [
{ name: "Cognitive Agility", value: 1.4508929, overunder: 'Under'},
{ name: "Focus", value: 10.6250000, overunder: 'Under'},
{ name: "Strategic Planning", value: 6.6321429, overunder: 'Under'},
] },
{ name: "Physical Thriving", cat: "Personal Thriving", children: [
{ name: "Physical Activity", value: 1.5607143, overunder: 'Under'},
{ name: "Nutrition", value: 2.2133929, overunder: 'Over'},
{ name: "Rest", value: 5.5258929, overunder: 'Under'},
] },
] },
{ name: "Inspiring Leadership", cat: "Inspiring Leadership", children: [
{ name: "Motivating Others", cat: "Inspiring Leadership", children: [
{ name: "Empowerment", value: 4.5080501, overunder: 'Over'},
{ name: "Recognition", value: 1.9901610, overunder: 'Over'},
] },
{ name: "Guiding Others", cat: "Inspiring Leadership", children: [
{ name: "Alignment", value: 0.5625000, overunder: 'Over'},
{ name: "Coaching", value: 2.1788909, overunder: 'Under'},
{ name: "Problem Solving", value: 0.6339286, overunder: 'Under'},
] },
{ name: "Including Others", cat: "Inspiring Leadership", children: [
{ name: "Encouraging Participation", value: 3.8640429, overunder: 'Over'},
{ name: "Relationship Building", value: 1.4491071, overunder: 'Over'},
] },
] },
{ name: "Outcomes", cat: "Outcomes", children: [
{ name: "Engagement", value: 5.0751342, overunder: 'Over'},
{ name: "Work-Life Balance", value: 5.6681574, overunder: 'Under'},
{ name: "Resilience", value: 5.0974955, overunder: 'Under'},
] },
]
})
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