From cec3662c748ff6abbe8570632e9287085a2a51fc Mon Sep 17 00:00:00 2001 From: Aaron Pham <29749331+aarnphm@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:09:20 -0500 Subject: [PATCH] feat(graph): focusOnHover (#954) by default, globalGraph will enable focusOnHover, similar to Obsidian. --------- Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> --- quartz/components/Graph.tsx | 3 +++ quartz/components/scripts/graph.inline.ts | 27 ++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/quartz/components/Graph.tsx b/quartz/components/Graph.tsx index 40ab43a2d..f7ebcc9a2 100644 --- a/quartz/components/Graph.tsx +++ b/quartz/components/Graph.tsx @@ -17,6 +17,7 @@ export interface D3Config { opacityScale: number removeTags: string[] showTags: boolean + focusOnHover?: boolean } interface GraphOptions { @@ -37,6 +38,7 @@ const defaultOptions: GraphOptions = { opacityScale: 1, showTags: true, removeTags: [], + focusOnHover: false, }, globalGraph: { drag: true, @@ -50,6 +52,7 @@ const defaultOptions: GraphOptions = { opacityScale: 1, showTags: true, removeTags: [], + focusOnHover: true, }, } diff --git a/quartz/components/scripts/graph.inline.ts b/quartz/components/scripts/graph.inline.ts index c991e163e..1c9bb5d64 100644 --- a/quartz/components/scripts/graph.inline.ts +++ b/quartz/components/scripts/graph.inline.ts @@ -44,6 +44,7 @@ async function renderGraph(container: string, fullSlug: FullSlug) { opacityScale, removeTags, showTags, + focusOnHover, } = JSON.parse(graph.dataset["cfg"]!) const data: Map = new Map( @@ -189,6 +190,8 @@ async function renderGraph(container: string, fullSlug: FullSlug) { return 2 + Math.sqrt(numLinks) } + let connectedNodes: SimpleSlug[] = [] + // draw individual nodes const node = graphNode .append("circle") @@ -202,17 +205,25 @@ async function renderGraph(container: string, fullSlug: FullSlug) { window.spaNavigate(new URL(targ, window.location.toString())) }) .on("mouseover", function (_, d) { - const neighbours: SimpleSlug[] = data.get(slug)?.links ?? [] - const neighbourNodes = d3 - .selectAll(".node") - .filter((d) => neighbours.includes(d.id)) const currentId = d.id const linkNodes = d3 .selectAll(".link") .filter((d: any) => d.source.id === currentId || d.target.id === currentId) - // highlight neighbour nodes - neighbourNodes.transition().duration(200).attr("fill", color) + if (focusOnHover) { + // fade out non-neighbour nodes + connectedNodes = linkNodes.data().flatMap((d: any) => [d.source.id, d.target.id]) + + d3.selectAll(".link") + .transition() + .duration(200) + .style("opacity", 0.2) + d3.selectAll(".node") + .filter((d) => !connectedNodes.includes(d.id)) + .transition() + .duration(200) + .style("opacity", 0.2) + } // highlight links linkNodes.transition().duration(200).attr("stroke", "var(--gray)").attr("stroke-width", 1) @@ -231,6 +242,10 @@ async function renderGraph(container: string, fullSlug: FullSlug) { .style("font-size", bigFont + "em") }) .on("mouseleave", function (_, d) { + if (focusOnHover) { + d3.selectAll(".link").transition().duration(200).style("opacity", 1) + d3.selectAll(".node").transition().duration(200).style("opacity", 1) + } const currentId = d.id const linkNodes = d3 .selectAll(".link")