| | |
| | | async function drawGraph( |
| | | baseUrl, |
| | | pathColors, |
| | | depth, |
| | | enableDrag, |
| | | enableLegend, |
| | | enableZoom, |
| | | isHome, |
| | | opacityScale, |
| | | scale, |
| | | repelForce, |
| | | fontSize |
| | | ) { |
| | | async function drawGraph(baseUrl, isHome, pathColors, graphConfig) { |
| | | |
| | | let { |
| | | depth, |
| | | enableDrag, |
| | | enableLegend, |
| | | enableZoom, |
| | | opacityScale, |
| | | scale, |
| | | repelForce, |
| | | fontSize } = graphConfig; |
| | | |
| | | const container = document.getElementById("graph-container") |
| | | const { index, links, content } = await fetchData |
| | | |
| | |
| | | d.fy = null |
| | | } |
| | | |
| | | const noop = () => {} |
| | | const noop = () => { } |
| | | return d3 |
| | | .drag() |
| | | .on("start", enableDrag ? dragstarted : noop) |
| | |
| | | .append("svg") |
| | | .attr("width", width) |
| | | .attr("height", height) |
| | | .attr('viewBox', [-width / 2 * 1 / scale, -height / 2 * 1 / scale, width * 1 / scale, height * 1 / scale]) |
| | | .attr('viewBox', [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale]) |
| | | |
| | | if (enableLegend) { |
| | | const legend = [{ Current: "var(--g-node-active)" }, { Note: "var(--g-node)" }, ...pathColors] |
| | |
| | | const nodeRadius = (d) => { |
| | | const numOut = index.links[d.id]?.length || 0 |
| | | const numIn = index.backlinks[d.id]?.length || 0 |
| | | return 3 + (numOut + numIn) / 4 |
| | | return 2 + Math.sqrt(numOut + numIn) |
| | | } |
| | | |
| | | // draw individual nodes |
| | |
| | | .style("cursor", "pointer") |
| | | .on("click", (_, d) => { |
| | | // SPA navigation |
| | | window.Million.navigate(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`), ".singlePage") |
| | | const targ = `${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/` |
| | | window.Million.navigate(new URL(targ), ".singlePage") |
| | | plausible("Link Click", { |
| | | props: { |
| | | href: targ, |
| | | broken: false, |
| | | internal: true, |
| | | graph: true, |
| | | } |
| | | }) |
| | | }) |
| | | .on("mouseover", function (_, d) { |
| | | .on("mouseover", function(_, d) { |
| | | d3.selectAll(".node").transition().duration(100).attr("fill", "var(--g-node-inactive)") |
| | | |
| | | const neighbours = parseIdsFromLinks([ |
| | |
| | | // highlight links |
| | | linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)") |
| | | |
| | | const bigFont = fontSize+0.5 |
| | | const bigFont = fontSize * 1.5 |
| | | |
| | | // show text for self |
| | | d3.select(this.parentNode) |
| | |
| | | .duration(200) |
| | | .attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity")) |
| | | .style('opacity', 1) |
| | | .style('font-size', bigFont+'em') |
| | | .style('font-size', bigFont + 'em') |
| | | .attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px |
| | | }) |
| | | .on("mouseleave", function (_, d) { |
| | | .on("mouseleave", function(_, d) { |
| | | d3.selectAll(".node").transition().duration(200).attr("fill", color) |
| | | |
| | | const currentId = d.id |
| | |
| | | linkNodes.transition().duration(200).attr("stroke", "var(--g-link)") |
| | | |
| | | d3.select(this.parentNode) |
| | | .select("text") |
| | | .transition() |
| | | .duration(200) |
| | | .style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld")) |
| | | .style('font-size', fontSize+'em') |
| | | .attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px |
| | | .select("text") |
| | | .transition() |
| | | .duration(200) |
| | | .style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld")) |
| | | .style('font-size', fontSize + 'em') |
| | | .attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px |
| | | }) |
| | | .call(drag(simulation)) |
| | | |
| | |
| | | .attr("dx", 0) |
| | | .attr("dy", (d) => nodeRadius(d) + 8 + "px") |
| | | .attr("text-anchor", "middle") |
| | | .text((d) => content[d.id]?.title || d.id.replace("-", " ")) |
| | | .text((d) => content[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " ")) |
| | | .style('opacity', (opacityScale - 1) / 3.75) |
| | | .style("pointer-events", "none") |
| | | .style('font-size', fontSize+'em') |
| | | .style('font-size', fontSize + 'em') |
| | | .raise() |
| | | .call(drag(simulation)) |
| | | |