Public
Edited
Apr 9
21 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
transitMorph = {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, 1100, 850])
.style("font", "10px sans-serif");

svg.call(appendDefs);

const linesGroup = svg.append("g").attr("id", "lines");
const stopsGroup = svg.append("g").attr("id", "stops");
// const stopLinesGroup = svg.append("g").attr("id", "stopLines");

var nextLines = geographicLines;
var currentLines = schematicLines;

var nextLabels = geographicLabels;
var currentLabels = schematicLabels;

// var nextStopLines = geographicStopLines2;
// var currentStopLines = schematicStopLines;

while (true) {
const t = svg.transition().duration(duration);

stopsGroup
.selectAll("text")
.data(currentLabels, (d) => d.halte)
.join(
(enter) =>
enter
.append("text")
.attr("transform", (d) => d.transform)
.attr("fill", "black")
.attr("font-size", 8.5)
.text((d) => d.halte)
.attr("stroke", "white")
.attr("paint-order", "stroke")
.attr("stroke-linejoin", "round")
.attr("stroke-width", 2),
(update) =>
update.call((update) =>
update.transition(t).attrTween("transform", function (d) {
var previous = d3.select(this).attr("transform");
var current = d.transform;
return d3.interpolateTransformSvg(previous, current);
})
)
);

linesGroup
.selectAll("path")
.data(currentLines, (d) => d.lijn)
.join(
(enter) =>
enter
.append("path")
.attr("fill", "none")
.attr("stroke-linejoin", "round")
.attr("stroke", (d) => d.stroke)
.attr("stroke-width", 5)
.attr("d", (d) => d.d)
// .attr("marker-mid", "url(#dot)") // for debugging path interpolation
.attr("marker-end", (d) => `url(#marker-${d.lijn})`)
.attr("marker-start", (d) => `url(#marker-${d.lijn})`)
.append("title")
.text((d) => d.lijn),
(update) =>
update.call((update) =>
update.transition(t).attrTween("d", function (d) {
var previous = d3.select(this).attr("d");
var current = d.d;
return d3.interpolatePath(previous, current);
})
)
);

// markersGroup
// .selectAll("path")
// .data(currentMarkers, (d) => d.id)
// .join(
// (enter) =>
// enter
// .append("path")
// .attr("fill", "none")
// .attr("d", (d) => d.d)
// .attr("id", (d) => d.id)
// .attr("stroke-width", 6)
// .attr("stroke", (d) => d.stroke),
// (update) =>
// update.call((update) =>
// update
// .transition(t)
// .attrTween("d", function (d) {
// var previous = d3.select(this).attr("d");
// var current = d.d;
// return d3.interpolatePath(previous, current);
// })
// )
// );

yield Promises.delay(duration + pause, svg.node());

[nextLabels, currentLabels] = [currentLabels, nextLabels];
[nextLines, currentLines] = [currentLines, nextLines];
// [nextStopLines, currentStopLines] = [currentStopLines, nextStopLines];
}
}
Insert cell
Insert cell
Insert cell
Insert cell
appendDefs = (svg) =>
svg
.append("defs")
.selectAll("marker")
.data(schematicLines)
.join((enter) => {
const marker = enter
.append("marker")
.attr("overflow", "visible")
.attr("markerWidth", markerWidth)
.attr("markerHeight", markerWidth)
.attr("orient", 0)
.attr("id", (d) => `marker-${d.lijn}`)
.attr("viewBox", `0 0 ${markerWidth * 2} ${markerWidth * 2}`)
.attr("refY", markerWidth / 2);

// marker
// .append("line")
// .attr("stroke", (d) => d.stroke)
// .attr("x", 0)
// .attr("y1", 0)
// .attr("x2", markerWidth)
// .attr("y2", 0)
// .attr("stroke-width", 4)
// .attr("fill-rule", "evenodd");

// For debugging path interpolation
// const marker2 = enter
// .append("marker")
// .attr("overflow", "visible")
// .attr("markerWidth", 8)
// .attr("markerHeight", 8)
// .attr("orient", 0)
// .attr("id", "dot")
// // .attr("viewBox", `0 0 ${markerWidth * 2} ${markerWidth * 2}`)
// .attr("refY", 4)
// .attr("refX", 4);

// marker2
// .append("circle")
// .attr("cx", 4)
// .attr("cy", 4)
// .attr("r", 0.2)
// .attr("fill", "black");

marker
.append("rect")
.attr("fill", "white")
.attr("stroke", (d) => d.stroke)
.attr("width", markerWidth)
.attr("height", markerWidth)
.attr("rx", 2);

marker
.append("text")
.attr("x", markerWidth / 2)
.attr("y", markerWidth / 2)
.attr("dominant-baseline", "middle")
.attr("text-anchor", "middle")
.attr("font-size", 6)
.attr("fill", "black")
.text((d) => d.lijn);
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// schematicMarkerNames = schematicMarkers
// .filter((d) => Boolean(d.id))
// .map((d) => d.id.replaceAll("-", " "))
Insert cell
// geographicMarkers2 = schematicMarkerNames
// .map((d) => geographicLabels.find((e) => d.slice(0, -2) === e.halte))
// .filter(Boolean)
// .map((d) => {
// const { halte, transform, stroke } = d;
// const { translateX, translateY } = parseSvg(transform);

// return {
// stroke,
// id: halte.replaceAll(" ", "-"),
// d: `M${translateX.toFixed(2)} ${translateY.toFixed(2)}v20`
// };
// })
Insert cell
// geographicMarkers = uniqueStops.map((d) => ({
// d: `M${projection([+d.longitude, +d.latitude]).map((d) => d.toFixed(2))}v10`,
// id: `${d.name.replaceAll(" ", "-")}-${d.desc.replace("Metrolijn ", "")}`
// }))
Insert cell
// uniqueStops
// .map((d) =>
// d.desc
// .replaceAll("Metrolijn ", "")
// .split("/")
// .map((e) => `${d.name.replaceAll(" ", "-")}-${e}`)
// )
// .flat()
Insert cell
// schematicMarkerElements = Array.from(
// schematicSvg.querySelector("#markers").querySelectorAll("path")
// )
Insert cell
// schematicMarkers = schematicMarkerElements
// .map((d) => ({
// d: d.getAttribute("d"),
// id: d.getAttribute("id"),
// stroke: d.getAttribute("stroke")
// }))
// .filter((d) => Boolean(d.id))
// .map((d) => ({ ...d, id: d.id.slice(0, -2) }))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// pathStrings = Array.from(schematicSvg.querySelector("#lines").children)
// .map((child) => child.getAttribute("d"))
// .map(snap.path.toAbsolute)
// .map((d) =>
// d.map(([command, ...coords]) => `${command}${coords.join(",")}`).join(" ")
// )[3]
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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { freelanceBanner } from "@julesblm/freelance-banner"
Insert cell
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