feat(graph): enable radial mode (#1738)
| | |
| | | opacityScale: 1, // how quickly do we fade out the labels when zooming out? |
| | | removeTags: [], // what tags to remove from the graph |
| | | showTags: true, // whether to show tags in the graph |
| | | enableRadial: false, // whether to constrain the graph, similar to Obsidian |
| | | }, |
| | | globalGraph: { |
| | | drag: true, |
| | |
| | | opacityScale: 1, |
| | | removeTags: [], // what tags to remove from the graph |
| | | showTags: true, // whether to show tags in the graph |
| | | enableRadial: true, // whether to constrain the graph, similar to Obsidian |
| | | }, |
| | | }) |
| | | ``` |
| | |
| | | removeTags: string[] |
| | | showTags: boolean |
| | | focusOnHover?: boolean |
| | | enableRadial?: boolean |
| | | } |
| | | |
| | | interface GraphOptions { |
| | |
| | | showTags: true, |
| | | removeTags: [], |
| | | focusOnHover: false, |
| | | enableRadial: false, |
| | | }, |
| | | globalGraph: { |
| | | drag: true, |
| | |
| | | showTags: true, |
| | | removeTags: [], |
| | | focusOnHover: true, |
| | | enableRadial: true, |
| | | }, |
| | | } |
| | | |
| | | export default ((opts?: GraphOptions) => { |
| | | export default ((opts?: Partial<GraphOptions>) => { |
| | | const Graph: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { |
| | | const localGraph = { ...defaultOptions.localGraph, ...opts?.localGraph } |
| | | const globalGraph = { ...defaultOptions.globalGraph, ...opts?.globalGraph } |
| | |
| | | forceCenter, |
| | | forceLink, |
| | | forceCollide, |
| | | forceRadial, |
| | | zoomIdentity, |
| | | select, |
| | | drag, |
| | |
| | | removeTags, |
| | | showTags, |
| | | focusOnHover, |
| | | enableRadial, |
| | | } = JSON.parse(graph.dataset["cfg"]!) as D3Config |
| | | |
| | | const data: Map<SimpleSlug, ContentDetails> = new Map( |
| | |
| | | })), |
| | | } |
| | | |
| | | const width = graph.offsetWidth |
| | | const height = Math.max(graph.offsetHeight, 250) |
| | | |
| | | // we virtualize the simulation and use pixi to actually render it |
| | | // Calculate the radius of the container circle |
| | | const radius = Math.min(width, height) / 2 - 40 // 40px padding |
| | | const simulation: Simulation<NodeData, LinkData> = forceSimulation<NodeData>(graphData.nodes) |
| | | .force("charge", forceManyBody().strength(-100 * repelForce)) |
| | | .force("center", forceCenter().strength(centerForce)) |
| | | .force("link", forceLink(graphData.links).distance(linkDistance)) |
| | | .force("collide", forceCollide<NodeData>((n) => nodeRadius(n)).iterations(3)) |
| | | |
| | | const width = graph.offsetWidth |
| | | const height = Math.max(graph.offsetHeight, 250) |
| | | if (enableRadial) |
| | | simulation.force("radial", forceRadial(radius * 0.8, width / 2, height / 2).strength(0.3)) |
| | | |
| | | // precompute style prop strings as pixi doesn't support css variables |
| | | const cssVars = [ |