feat(graph): focusOnHover (#954)
by default, globalGraph will enable focusOnHover, similar to Obsidian. --------- Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com>
This commit is contained in:
		@@ -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,
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,7 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
 | 
			
		||||
    opacityScale,
 | 
			
		||||
    removeTags,
 | 
			
		||||
    showTags,
 | 
			
		||||
    focusOnHover,
 | 
			
		||||
  } = JSON.parse(graph.dataset["cfg"]!)
 | 
			
		||||
 | 
			
		||||
  const data: Map<SimpleSlug, ContentDetails> = 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<HTMLElement, NodeData>(".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<HTMLElement, NodeData>(".link")
 | 
			
		||||
          .transition()
 | 
			
		||||
          .duration(200)
 | 
			
		||||
          .style("opacity", 0.2)
 | 
			
		||||
        d3.selectAll<HTMLElement, NodeData>(".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<HTMLElement, NodeData>(".link").transition().duration(200).style("opacity", 1)
 | 
			
		||||
        d3.selectAll<HTMLElement, NodeData>(".node").transition().duration(200).style("opacity", 1)
 | 
			
		||||
      }
 | 
			
		||||
      const currentId = d.id
 | 
			
		||||
      const linkNodes = d3
 | 
			
		||||
        .selectAll(".link")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user