Skip to content

Commit

Permalink
Use dagre instead of Graphology
Browse files Browse the repository at this point in the history
  • Loading branch information
stereobooster committed Oct 20, 2024
1 parent ed21fa7 commit 40248b0
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 150 deletions.
3 changes: 1 addition & 2 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
"@beoe/rehype-gnuplot": "workspace:*",
"@beoe/rehype-graphviz": "workspace:*",
"@beoe/rehype-vizdom": "workspace:*",
"@dagrejs/graphlib": "^2.2.4",
"astro": "4.16.2",
"graphology": "^0.25.4",
"graphology-traversal": "^0.3.1",
"sharp": "^0.33.5",
"typescript": "^5.6.3",
"vite-plugin-qrcode": "^0.2.3"
Expand Down
20 changes: 9 additions & 11 deletions packages/demo/src/components/vizdom.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { MultiGraph } from "graphology";
import { bfsFromNode } from "graphology-traversal";
import { json } from "@dagrejs/graphlib";

// highlight nodes and edges in graphviz on hover
// highlight nodes and edges in vizdom on hover
document.querySelectorAll(".vizdom").forEach((container) => {
const data = container.getAttribute("data-graph")
? JSON.parse(container.getAttribute("data-graph")!)
: null;

if (data) {
const graph = new MultiGraph();
graph.import(data);

const graph = json.read(data);
let current: string | null = null;
container.addEventListener("mouseover", (e) => {
// @ts-expect-error
const node = e.target?.closest(".node");
if (node) {
const id = node.getAttribute("id");
const id = node.getAttribute("id").replace("node-", "");
if (current == id) return;
container
.querySelectorAll(".node")
.forEach((node) => node.classList.remove("active"));
container
.querySelectorAll(".edge")
.forEach((node) => node.classList.remove("active"));
bfsFromNode(graph, id, (node, _attr, _depth) => {
container.querySelector(`#${node}`)?.classList.add("active");
graph.outEdges(node).forEach((edge) => {
container.querySelector(`#${edge}`)?.classList.add("active");

[id, ...(graph.successors(id) || [])].forEach((node) => {
container.querySelector(`#node-${node}`)?.classList.add("active");
graph.outEdges(node)?.forEach(({ name }) => {
container.querySelector(`#edge-${name}`)?.classList.add("active");
});
});
current = id;
Expand Down
10 changes: 6 additions & 4 deletions packages/rehype-vizdom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,15 @@ You can add dark mode with something like this:
- [ ] another script: to select several nodes and draw path between them
- [ ] documentation about "animation" script
- note about animation for reverse edges
- [ ] lightweight alternative to graphology
- https://www.npmjs.com/package/graph-data-structure
- https://www.npmjs.com/package/@dagrejs/graphlib
- https://www.npmjs.com/search?q=graph-theory
- [ ] search text in graph
- See [text-search](https://github.com/stereobooster/facets/blob/main/notes/text-search.md#candidates)

## Notes

- Doesn't support some unicode chars, like `label="∅"`
- Client-side JS library
- graphology is about 70kb uncompressed
- `@dagrejs/graphlib` is about 12kb
- [graph-data-structure](https://www.npmjs.com/package/graph-data-structure) is about 4kb (but it doesn't support ids for edges)
- [DirectedGraph](https://data-structure-typed-docs.vercel.app/classes/DirectedGraph.html) is about 40kb
- [Other options](https://www.npmjs.com/search?q=graph-theory)
57 changes: 38 additions & 19 deletions packages/rehype-vizdom/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,47 @@ export async function dotToSvg(code: string) {
const positioned = directedGraph.layout();
const obj = positioned.to_json().to_obj();
// JSON in Graphology format
// const graph = {
// attributes: { name: "g" },
// options: { allowSelfLoops: true, multi: true, type: "directed" },
// nodes: obj.nodes.map((node) => ({
// key: `node-${node.unique_id}`,
// // attributes: {
// // label: node.label,
// // x: node.x,
// // y: node.y,
// // width: node.width,
// // height: node.width,
// // // url: node.url,
// // },
// })),
// edges: obj.edges.map((edge) => ({
// key: `edge-${edge.unique_id}`,
// source: `node-${edge.source}`,
// target: `node-${edge.target}`,
// // attributes: {
// // label: edge.label,
// // // url: edge.url,
// // },
// })),
// };

// JSON in Dagre format
const graph = {
attributes: { name: "g" },
options: { allowSelfLoops: true, multi: true, type: "directed" },
options: {
directed: true,
multigraph: true,
compound: false,
},
nodes: obj.nodes.map((node) => ({
key: `node-${node.unique_id}`,
// attributes: {
// label: node.label,
// x: node.x,
// y: node.y,
// width: node.width,
// height: node.width,
// // url: node.url,
// },
v: node.unique_id,
// value: {},
})),
edges: obj.edges.map((edge) => ({
key: `edge-${edge.unique_id}`,
source: `node-${edge.source}`,
target: `node-${edge.target}`,
// attributes: {
// label: edge.label,
// // url: edge.url,
// },
v: edge.source,
w: edge.target,
name: edge.unique_id,
// value: {},
})),
};
const svg = await positioned.to_svg().to_string();
Expand All @@ -56,7 +75,7 @@ export type RehypeVizdomConfig = {
cache?: MapLike;
class?: string;
svgo?: SvgoConfig | boolean;
// if true adds data-graph to each figure with JSON in Graphology format
// if true adds data-graph to each figure with JSON representation of graph
dataGraph?: boolean;
};

Expand Down
126 changes: 12 additions & 114 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 40248b0

Please sign in to comment.