chart = function ({ data } = {}) {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", width / 6);
const path = d3.geoPath().projection(projection);
const topg = svg.append("g").attr("class", "topg");
const circleR = 10;
let currentCircle = null;
const extractId = (i) => {
let id = i;
const si = "" + i;
if (si.includes("_")) {
id = +i.split("_")[1];
}
return id;
};
topg
.selectAll("path")
.data(countries.features)
.enter()
.append("path")
.attr("d", path);
const circleData = [
...data.map(({ id, from }) => ({ id: `from_${id}`, coordinates: from })),
...data.map(({ id, to }) => ({ id: `to_${id}`, coordinates: to }))
];
const circle = topg
.selectAll("circle")
.data(circleData, (d) => d.id)
.enter()
.append("circle")
.attr("cx", (d) => projection(d.coordinates)[0])
.attr("cy", (d) => projection(d.coordinates)[1])
.attr("r", circleR)
.style("fill", "grey")
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut);
svg.on("mouseover", () => {
svg.node().value = currentCircle;
svg.node().dispatchEvent(new CustomEvent("input"));
});
function connIdToCoor(cId) {
const f = (srcOrTo) => data.locations.filter(({ id }) => id === srcOrTo)[0];
const [src, to] = cId.split("_");
const srcConn = f(src);
const toConn = f(to);
return [srcConn.coordinates, toConn.coordinates];
}
function onMouseOver(_, d) {
const selId = d.id;
d3.selectAll("circle").style("fill", (d) =>
extractId(d.id) === extractId(selId) ? "tomato" : "grey"
);
d3.selectAll("line").attr("stroke", (d) => {
if (!d) return;
return extractId(d.id) === extractId(selId) ? "tomato" : "grey";
});
currentCircle = d;
}
function onMouseOut(_, d) {
d3.selectAll("circle").style("fill", "grey");
d3.selectAll("line").attr("stroke", "grey");
currentCircle = null;
}
const line = topg
.selectAll("line")
.data(data, (d) => d.id)
.enter()
.append("line")
.attr("x1", (d) => projection(d.from)[0])
.attr("y1", (d) => projection(d.from)[1])
.attr("x2", (d) => projection(d.to)[0])
.attr("y2", (d) => projection(d.to)[1])
.attr("stroke", "grey")
.attr("stroke-width", 2)
.attr("opacity", 0.5)
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut);
const zoom = d3
.zoom()
.scaleExtent([1, 20])
.on("zoom", function ({ transform }) {
topg.attr("transform", transform);
topg.selectAll("circle").attr("r", circleR / transform.k);
});
svg.call(zoom);
return svg.node();
}