From 47dae8a6d4d367a1e4cc1ef7600de51dcd23dc67 Mon Sep 17 00:00:00 2001 From: DhammaCharts <100090806+DhammaCharts@users.noreply.github.com> Date: Wed, 1 Jun 2022 13:49:27 +0100 Subject: [PATCH] Improve graph display, options and ability to have a global graph on the home page, local graphs on subpage. --- assets/js/graph.js | 43 +++++++++++++++++++++++------- data/graphConfig.yaml | 33 +++++++++++++++++++++-- layouts/index.html | 2 +- layouts/partials/footerIndex.html | 28 ++++++++++++++++++++ layouts/partials/head.html | 44 +++++++++++++++++++++++++------ 5 files changed, 129 insertions(+), 21 deletions(-) create mode 100644 layouts/partials/footerIndex.html diff --git a/assets/js/graph.js b/assets/js/graph.js index c7634cf3..48248eca 100644 --- a/assets/js/graph.js +++ b/assets/js/graph.js @@ -1,4 +1,16 @@ -async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, enableZoom) { +async function drawGraph( + baseUrl, + pathColors, + depth, + enableDrag, + enableLegend, + enableZoom, + isHome, + opacityScale, + scale, + repelForce, + fontSize +) { const container = document.getElementById("graph-container") const { index, links, content } = await fetchData @@ -82,12 +94,12 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e .on("end", enableDrag ? dragended : noop) } - const height = Math.max(container.offsetHeight, 250) + const height = Math.max(container.offsetHeight, isHome ? 500 : 250) const width = container.offsetWidth const simulation = d3 .forceSimulation(data.nodes) - .force("charge", d3.forceManyBody().strength(-30)) + .force("charge", d3.forceManyBody().strength(-100 * repelForce)) .force( "link", d3 @@ -102,7 +114,7 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e .append("svg") .attr("width", width) .attr("height", height) - .attr("viewBox", [-width / 2, -height / 2, width, height]) + .attr('viewBox', [-width / 2 * 1 / scale, -height / 2 * 1 / scale, width * 1 / scale, height * 1 / scale]) if (enableLegend) { const legend = [{ Current: "var(--g-node-active)" }, { Note: "var(--g-node)" }, ...pathColors] @@ -168,7 +180,7 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e ]) const neighbourNodes = d3.selectAll(".node").filter((d) => neighbours.includes(d.id)) const currentId = d.id - window.Million.prefetch(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`)) + // window.Million.prefetch(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`)) const linkNodes = d3 .selectAll(".link") .filter((d) => d.source.id === currentId || d.target.id === currentId) @@ -179,13 +191,18 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e // highlight links linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)") + const bigFont = fontSize+0.5 + // show text for self d3.select(this.parentNode) .raise() .select("text") .transition() .duration(200) - .style("opacity", 1) + .attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity")) + .style('opacity', 1) + .style('font-size', bigFont+'em') + .attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px }) .on("mouseleave", function (_, d) { d3.selectAll(".node").transition().duration(200).attr("fill", color) @@ -197,7 +214,13 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e linkNodes.transition().duration(200).attr("stroke", "var(--g-link)") - d3.select(this.parentNode).select("text").transition().duration(200).style("opacity", 0) + 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 }) .call(drag(simulation)) @@ -208,9 +231,9 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e .attr("dy", (d) => nodeRadius(d) + 8 + "px") .attr("text-anchor", "middle") .text((d) => content[d.id]?.title || d.id.replace("-", " ")) - .style("opacity", 0) + .style('opacity', (opacityScale - 1) / 3.75) .style("pointer-events", "none") - .style("font-size", "0.4em") + .style('font-size', fontSize+'em') .raise() .call(drag(simulation)) @@ -228,7 +251,7 @@ async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, e .on("zoom", ({ transform }) => { link.attr("transform", transform) node.attr("transform", transform) - const scale = transform.k + const scale = transform.k * opacityScale; const scaledOpacity = Math.max((scale - 1) / 3.75, 0) labels.attr("transform", transform).style("opacity", scaledOpacity) }), diff --git a/data/graphConfig.yaml b/data/graphConfig.yaml index 3f8d3fb6..7f08130d 100644 --- a/data/graphConfig.yaml +++ b/data/graphConfig.yaml @@ -1,6 +1,35 @@ +# if true, a Global Graph will be shown on home page with full width, no backlink. +# A different set of Local Graphs will be shown on sub pages. +# if false, Local Graph will be default on every page as usual +enableGlobalGraph: true + +### Local Graph ### + enableLegend: false enableDrag: true enableZoom: true -depth: -1 # set to -1 to show full graph +depth: 1 # set to -1 to show full graph +scale: 1 +repelForce: 2 +centerForce: 1 +linkDistance: 1 +fontSize: 0.6 +opacityScale: 3 + +### Global Graph ### + +enableLegendGG: false +enableDragGG: true +enableZoomGG: true +depthGG: -1 # set to -1 to show full graph +scaleGG: 1.2 +repelForceGG: 1 +centerForceGG: 1 +linkDistanceGG: 1 +fontSizeGG: 0.5 +opacityScaleGG: 3 + +### Graphs ### + paths: - - /moc: "#4388cc" \ No newline at end of file + - /moc: "#4388cc" diff --git a/layouts/index.html b/layouts/index.html index 8d1ffbd4..50536142 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -19,7 +19,7 @@ {{partial "recent.html" . }} {{end}} - {{partial "footer.html" .}} + {{partial "footerIndex.html" .}} diff --git a/layouts/partials/footerIndex.html b/layouts/partials/footerIndex.html new file mode 100644 index 00000000..36c8a8ac --- /dev/null +++ b/layouts/partials/footerIndex.html @@ -0,0 +1,28 @@ + + +
+ +{{if $.Site.Data.config.enableFooter}} + {{if $.Site.Data.graphConfig.enableGlobalGraph}} +
+ +
+ {{partial "graph.html" .}} +
+ +
+ {{else}} +
+
+ +
+ {{partial "graph.html" .}} +
+ +
+ {{end}} +{{end}} + +{{partial "contact.html" .}} diff --git a/layouts/partials/head.html b/layouts/partials/head.html index f10ce145..01b8fe8a 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -62,6 +62,12 @@ })) const draw = () => { + + const siteBaseURL = new URL({{$.Site.BaseURL}}); + const pathBase = siteBaseURL.pathname; + const pathWindow = window.location.pathname; + const isHome = pathBase == pathWindow ? true : false; + // NOTE: everything within this callback will be executed for every page navigation. This is a good place to put JavaScript that loads or modifies data on the page. {{if $.Site.Data.config.enableFooter}} const container = document.getElementById("graph-container") @@ -70,14 +76,36 @@ // clear the graph in case there is anything within it container.textContent = "" - drawGraph( - {{strings.TrimRight "/" .Site.BaseURL}}, - {{$.Site.Data.graphConfig.paths}}, - {{$.Site.Data.graphConfig.depth}}, - {{$.Site.Data.graphConfig.enableDrag}}, - {{$.Site.Data.graphConfig.enableLegend}}, - {{$.Site.Data.graphConfig.enableZoom}} - ); + if (isHome && {{$.Site.Data.graphConfig.enableGlobalGraph}}) { + drawGraph( + {{strings.TrimRight "/" .Site.BaseURL}}, + {{$.Site.Data.graphConfig.paths}}, + {{$.Site.Data.graphConfig.depthGG}}, + {{$.Site.Data.graphConfig.enableDragGG}}, + {{$.Site.Data.graphConfig.enableLegendGG}}, + {{$.Site.Data.graphConfig.enableZoomGG}}, + true, + {{$.Site.Data.graphConfig.opacityScaleGG}}, + {{$.Site.Data.graphConfig.scaleGG}}, + {{$.Site.Data.graphConfig.repelForceGG}}, + {{$.Site.Data.graphConfig.fontSizeGG}} + ); + } else { + drawGraph( + {{strings.TrimRight "/" .Site.BaseURL}}, + {{$.Site.Data.graphConfig.paths}}, + {{$.Site.Data.graphConfig.depth}}, + {{$.Site.Data.graphConfig.enableDrag}}, + {{$.Site.Data.graphConfig.enableLegend}}, + {{$.Site.Data.graphConfig.enableZoom}}, + false, + {{$.Site.Data.graphConfig.opacityScale}}, + {{$.Site.Data.graphConfig.scale}}, + {{$.Site.Data.graphConfig.repelForce}}, + {{$.Site.Data.graphConfig.fontSize}} + ); + } + {{end}} {{if $.Site.Data.config.enableLinkPreview}} initPopover(