Published
Edited
May 9, 2021
Insert cell
Insert cell
Insert cell
//import {letters} from "@sjengle/english-alphabet-dataset"
Insert cell
//letters
Insert cell
//letters[0]
Insert cell
TrailData= d3.csvParse(await FileAttachment("Mormon Trail Points and Info.csv").text(), d3.autoType)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
vis = {
// wait until this cell is visible
await visibility();
const svg = d3.select(DOM.svg(width, height));
svg.style("border", "1px solid #bbbbbb");
// data layer to keep circles
const g = svg.append("g").attr("id", "circles");
g.selectAll("circle")
.data(TrailData)
.enter()
.append("circle")
.attr("cx", d => x(d.Longitude))
.attr("cy", d => y(d.Latitude))
.attr("r", r)
.style("fill", d => color(d.type));
// annotation layer to keep labels on top of data
svg.append("g").attr("id", "annotation");
return svg.node();
}
Insert cell
Insert cell
Insert cell
circles = d3.select(vis).select("g#circles").selectAll("circle");
Insert cell
annotations = d3.select(vis).select("g#annotation");
Insert cell
Insert cell
highlight = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>highlight: none</code>`;
// event.namespace allows us to add multiple functions for one event
// only needed in examples like this where some events trigger multiple functions
circles.on("mouseover.highlight", function(d) {
d3.select(this)
.raise() // bring to front
.style("stroke", "red")
.style("stroke-width", 2);
// show what we interacted with
d3.select(status).text("highlight: " + d.letter);
});

circles.on("mouseout.highlight", function(d) {
d3.select(this).style("stroke", null);
d3.select(status).text("highlight: none");
});
return status;
}
Insert cell
Insert cell
//hover1 = {
//const svg = d3.select(vis);
// used to test out interactivity in this cell
//const status = html`<code>hover: none</code>`;

//circles.on("mouseover.hover1", function(d) {
//let me = d3.select(this);
//annotations.insert("text")
//.attr("id", "label")
//.attr("x", me.attr("cx"))
//.attr("y", me.attr("cy"))
//.attr("dy", r + 14)
//.attr("text-anchor", "middle")
//.text(d.codeword);

// show what we interacted with
//d3.select(status).text("hover: " + d.letter);
// });

//circles.on("mouseout.hover1", function(d) {
//annotations.select("text#label").remove();
//d3.select(status).text("hover: none");
//});
//return status;
//}
Insert cell
Insert cell
hover2 = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>hover: none</code>`;

circles.on("mouseover.hover2", function(d) {
let me = d3.select(this);
let div = d3.select("body").append("div");
div.attr("id", "details");
div.attr("class", "tooltip");
let rows = div.append("table")
.selectAll("tr")
.data(Object.keys(d))
.enter()
.append("tr");
rows.append("th").text(key => key);
rows.append("td").text(key => d[key]);
// show what we interacted with
d3.select(status).text("hover: " + d.letter);
});

circles.on("mousemove.hover2", function(d) {
let div = d3.select("div#details");
// get height of tooltip
let bbox = div.node().getBoundingClientRect();
div.style("left", d3.event.clientX + "px")
div.style("top", (d3.event.clientY - bbox.height) + "px");
});
circles.on("mouseout.hover2", function(d) {
d3.selectAll("div#details").remove();
d3.select(status).text("hover: none");
});
return status;
}
Insert cell
Insert cell
brush1 = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>brush: none</code>`;
circles.on("mouseover.brush1", function(d) {
circles.filter(e => (d.type !== e.type)).transition().style("fill", "#bbbbbb");
// show what we interacted with
d3.select(status).text("brush: " + d.type);
});
circles.on("mouseout.brush1", function(d) {
circles.transition().style("fill", d => color(d.type));
d3.select(status).text("brush: none");
});
return status;
}
Insert cell
Insert cell
brush2 = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>brush: none</code>`;
let brush = d3.brush()
.on("start.brush2 brush.brush2 end.brush2", brushed);
function brushed() {
if (d3.event.selection) {
const [[x0, y0], [x1, y1]] = d3.event.selection;
// show what we interacted with
d3.select(status).text("brush: " + d3.event.selection);
circles.classed("dim", function(d) {
let cx = +d3.select(this).attr("cx");
let cy = +d3.select(this).attr("cy");
return !(x0 <= cx && cx < x1 &&
y0 <= cy && cy < y1);
});
}
else {
d3.select(status).text("brush: none");
circles.classed("dim", false);
}
}
// place brush BEHIND points so we still get pointer events
svg.insert("g", ":first-child").attr("class", "brush").call(brush);
return status;
}
Insert cell
Insert cell
drag = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>drag: none</code>`;
let drag = d3.drag();
drag.on("start.drag", function(d) {
d3.select(this).raise(); // places circle above others
// show what we interacted with
d3.select(status).text("drag: " + d.letter);
});
drag.on("drag.drag", function(d) {
d3.select(this)
.attr("cx", d3.event.x)
.attr("cy", d3.event.y);
});
drag.on("end.drag", function(d) {
d3.select(status).text("drag: none");
});
circles.call(drag);
return status;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
html`
<style>
circle {
stroke: white;
stroke-width: 2px;
}

text, .tooltip {
font-family: sans-serif;
font-size: 10pt;
}

.dim {
fill-opacity: 0.3;
}

.tooltip {
position: absolute;
width: auto;
height: auto;
padding: 8px;
background: #ddd;
pointer-events: none;
border: 1px solid #eee;
border-radius: 10px;
}
</style>
`
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