diff --git a/assets/js/graph.js b/assets/js/graph.js index c7634cf3e..174d4946d 100644 --- a/assets/js/graph.js +++ b/assets/js/graph.js @@ -1,4 +1,15 @@ -async function drawGraph(baseUrl, pathColors, depth, enableDrag, enableLegend, enableZoom) { +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 @@ -82,12 +93,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 +113,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] @@ -179,13 +190,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*1.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 +213,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 +230,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 +250,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/config.toml b/config.toml index 5efa9f346..803ef1ecb 100644 --- a/config.toml +++ b/config.toml @@ -30,4 +30,4 @@ enableGitInfo = true tabWidth = 4 [frontmatter] lastmod = ["lastmod", ":git", "date", "publishDate"] - publishDate = ["publishDate", "date"] \ No newline at end of file + publishDate = ["publishDate", "date"] diff --git a/data/graphConfig.yaml b/data/graphConfig.yaml index 3f8d3fb6b..a6f916acb 100644 --- a/data/graphConfig.yaml +++ b/data/graphConfig.yaml @@ -1,6 +1,37 @@ -enableLegend: false -enableDrag: true -enableZoom: true -depth: -1 # set to -1 to show full graph +# 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: false + +### Local Graph ### + +localGraph: + enableLegend: false + enableDrag: true + enableZoom: true + depth: 1 # set to -1 to show full graph + scale: 1.2 + repelForce: 2 + centerForce: 1 + linkDistance: 1 + fontSize: 0.6 + opacityScale: 3 + +### Global Graph ### + +globalGraph: + enableLegend: false + enableDrag: true + enableZoom: true + depth: -1 # set to -1 to show full graph + scale: 1.4 + repelForce: 1 + centerForce: 1 + linkDistance: 1 + fontSize: 0.5 + opacityScale: 3 + +### For all graphs ### + paths: - - /moc: "#4388cc" \ No newline at end of file + - /moc: "#4388cc" diff --git a/layouts/index.html b/layouts/index.html index 8d1ffbd4f..505361420 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 000000000..5f190446a --- /dev/null +++ b/layouts/partials/footerIndex.html @@ -0,0 +1,24 @@ +{{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 3b50340e1..b3ad28d8c 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -57,8 +57,14 @@ content, })) - const render = () => { + const render = () => { // 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, adds event listeners, etc. If you are only dealing with basic DOM replacement, use the init function + + const siteBaseURL = new URL({{$.Site.BaseURL}}); + const pathBase = siteBaseURL.pathname; + const pathWindow = window.location.pathname; + const isHome = pathBase == pathWindow; + {{if $.Site.Data.config.enableFooter}} const container = document.getElementById("graph-container") // retry if the graph is not ready @@ -66,14 +72,14 @@ // clear the graph in case there is anything within it container.textContent = "" + const drawGlobal = isHome && {{$.Site.Data.graphConfig.enableGlobalGraph}}; 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}} - ); + {{strings.TrimRight "/" .Site.BaseURL}}, + drawGlobal, + {{$.Site.Data.graphConfig.paths}}, + drawGlobal ? {{$.Site.Data.graphConfig.globalGraph}} : {{$.Site.Data.graphConfig.localGraph}} + ); + {{end}} {{if $.Site.Data.config.enableLinkPreview}}