Public
Edited
Apr 21, 2024
Insert cell
Insert cell
<div>
<style>
#narrativeTextBox {position: absolute; width: 300px; top: 30px; left: 520px; font-size: 14px;}
a {color: blue; font-weight: bold;}
a:hover {cursor: pointer; color: orange;}
</style>
<svg width="500" height="300" viewBox="0 0 500 300"></svg>
<div id="narrativeTextBox">
<h3>Dynamic Narrative</h3>
<p>Use narrative text right on the page as an interface to both explain and direct reading of the visual by moving around from <a id="region1">region1</a> to <a id="region2">region2</a> to <a id="region3">region3</a> and <a id="fullview">back to all</a> or whatever you might need to explain things. This can be a very effective way of using dynamics, including <a id="highlight">highlighting</a> and turning things <a id="turnOn">on</a> and <a id="turnOff">off</a> as a part of the directed navigation for story-telling and exploratory data.</p>
</div>
</div>
Insert cell
svgContainer = d3.select(container).select("svg")
Insert cell
circles = svgContainer.selectAll("circle")
.data(d3.range(10))
.join("circle")
.attr("cx", () => 50 + Math.random() * 400)
.attr("cy", () => 50 + Math.random() * 200)
.attr("r", 20)
.style("fill", d => d3.schemeCategory10[d])
Insert cell
{
// attach dynamic instructions to the text markers
//
d3.select("#region1").on("click", () => zoomToRegion([[10,5],[100,100]]));
d3.select("#region2").on("click", () => zoomToRegion([[200,50],[350,150]]));
d3.select("#region3").on("click", () => zoomToRegion([[50,150],[150,300]]));
d3.select("#fullview").on("click", () => zoomToRegion([[0,0],[svgContainer.attr("width"),svgContainer.attr("height")]]));

d3.select("#highlight").on("click", highlight);
d3.select("#turnOff").on("click", dimAll);
d3.select("#turnOn").on("click", showAll);
}
Insert cell
zoomToRegion = (coords) => {
//[[x0, y0], [x1, y1]] // [[left,bottom],[right,top]]
let minX = d3.min([coords[0][0],coords[1][0]]);
let minY = d3.min([coords[0][1],coords[1][1]]);
let maxX = d3.max([coords[0][0],coords[1][0]]);
let maxY = d3.max([coords[0][1],coords[1][1]]);
let viewBox = minX + " " + minY + " " + maxX + " " + maxY;
svgContainer.transition().duration(1000).attr("viewBox", viewBox);
}
Insert cell
Insert cell
dimAll = () => {
circles.style("opacity",0.1);
}
Insert cell
showAll = () => {
circles.style("opacity", "");
}
Insert cell
highlight = () => {
dimAll();
circles.filter(d => d > Math.random()*10).style("opacity","");
}
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