diff --git a/dev/GraphBrowser.tsx b/dev/GraphBrowser.tsx index 410292d..deb617b 100644 --- a/dev/GraphBrowser.tsx +++ b/dev/GraphBrowser.tsx @@ -1,23 +1,68 @@ import "./GraphBrowser.css"; import { type Component, createSignal, onMount } from "solid-js"; -import { createGraph, type Edge, type Graph, type Node } from "#/lib/Graph.ts"; -import type { Vector } from "#/lib/Vector.ts"; +import { + drawEdge, + drawNode, + type Graph, + type Node, + type PositionPartial, +} from "#/lib/Graph.ts"; +import { createVector, type Vector } from "#/lib/Vector.ts"; + +function drawGraph( + graph: Graph, + ctx: CanvasRenderingContext2D, +): void { + for (const [node, neighbours] of graph.entries()) { + drawNode(node, ctx); + for (const neighbour of neighbours) { + drawEdge([node, neighbour], ctx); + } + } +} + +function placeNodes(graph: Graph): void { + const visited: Array> = []; + const currentPosition = createVector(); + const radius = 24; + + for (const [node, neighbours] of graph.entries()) { + if (visited.includes(node)) { + continue; + } + visited.push(node); + + node.position.x = currentPosition.x; + node.position.y = currentPosition.y; + + neighbours.forEach((neighbour, index) => { + const fraction = (index + 1) / neighbours.length; + const rad = Math.PI * 2 * fraction; + neighbour.position.x = currentPosition.x + radius * Math.cos(rad); + neighbour.position.y = currentPosition.y + radius * Math.sin(rad); + visited.push(neighbour); + }); + + currentPosition.y += radius * 2; + } +} export const GraphBrowser: Component<{ graph: Graph<{ position: Vector; label: string }>; }> = (props) => { let canvasRef!: HTMLCanvasElement; - const [width, setWidth] = createSignal(100); - const [height, setHeight] = createSignal(100); + const [width, setWidth] = createSignal(300); + const [height, setHeight] = createSignal(300); onMount(() => { const ctx: CanvasRenderingContext2D = canvasRef.getContext("2d", { alpha: false, })!; + ctx.translate(width() / 2, height() / 2); - setWidth(canvasRef.parentElement!.offsetWidth); - setHeight(width()); + placeNodes(props.graph); + drawGraph(props.graph, ctx); }); return ( diff --git a/dev/main.tsx b/dev/main.tsx index a90e492..65d636d 100644 --- a/dev/main.tsx +++ b/dev/main.tsx @@ -39,11 +39,16 @@ const nodes: Array = [ { position: createVector(), label: "foo" }, { position: createVector(), label: "bar" }, { position: createVector(), label: "lol" }, + { position: createVector(), label: "hai" }, + { position: createVector(), label: "sea" }, + { position: createVector(), label: "vot" }, ]; const edges: Array> = [ [nodes[0], nodes[1]], - [nodes[1], nodes[2]], + [nodes[0], nodes[2]], + [nodes[0], nodes[3]], + [nodes[4], nodes[5]], ]; const graph = createGraph(nodes, edges); diff --git a/lib/Graph.ts b/lib/Graph.ts index 924c519..6846539 100644 --- a/lib/Graph.ts +++ b/lib/Graph.ts @@ -4,14 +4,14 @@ export type Node = T; export type Edge = [Node, Node]; export type Graph = Map, Array>>; -type PositionPartial = { +export type PositionPartial = { position: Vector; }; export function drawNode( node: Node, ctx: CanvasRenderingContext2D, - color: string, + color: string = "#fff", ): void { ctx.lineWidth = 2; ctx.strokeStyle = color; @@ -41,7 +41,7 @@ export function getNodeByPosition( export function drawEdge( edge: Edge, ctx: CanvasRenderingContext2D, - color: string, + color: string = "#fff", ): void { ctx.lineWidth = 2; ctx.strokeStyle = color; @@ -85,11 +85,9 @@ export function createGraph( export function originDFS(origin: Node, graph: Graph): Array> { const visited: Array> = [origin]; - if (!graph.has(origin)) { return visited; } - innerDFS(origin, graph, visited); return visited;