Skip to content

Commit

Permalink
can now add edges
Browse files Browse the repository at this point in the history
  • Loading branch information
jfkonecn committed Dec 21, 2023
1 parent 6d3bb04 commit bf39476
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 164 deletions.
1 change: 1 addition & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function App() {
},
],
gridSquareSize: 25,
edges: [],
},
});

Expand Down
207 changes: 44 additions & 163 deletions src/canvas/Canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import {
import { DrawMode, Grid, Node } from "../types";
import {
UseCursorRtn,
UseTranslatePositionRtn,
useCursor,
useDocumentKeyDown,
useResizeObserver,
useScale,
useTranslatePosition,
} from "../using-utils";
import { draw } from "./draw-utils";

// https://www.jgibson.id.au/blog/responsive-canvas/
// https://jsfiddle.net/u5ogmh9a/
Expand Down Expand Up @@ -83,6 +83,44 @@ export default function Canvas({
});
}
}
} else if (drawMode.typename === "addEdge") {
let selectedNode: Node | undefined;
for (const node of grid.nodes) {
const intersects = nodeIntersectsWithLasso(cursor, cursor, node);
if (intersects) {
selectedNode = node;
}
}
const phase = drawMode.phase;
if (drawMode.phase.typename === "idle" && selectedNode) {
onDrawModeChange({
typename: "addEdge",
phase: { typename: "adding", startUuid: selectedNode.uuid },
});
} else if (phase.typename === "adding" && selectedNode) {
const canvas = canvasRef.current;
const startNode = grid.nodes.find((x) =>
phase.startUuid.includes(x.uuid),
);
if (canvas && startNode) {
grid.edges.push({
startUuid: startNode.uuid,
endUuid: selectedNode.uuid,
uuid: crypto.randomUUID(),
});

onGridChange(grid);
onDrawModeChange({
typename: "addEdge",
phase: { typename: "idle" },
});
}
} else {
onDrawModeChange({
typename: "addEdge",
phase: { typename: "idle" },
});
}
} else if (
drawMode.typename === "select" &&
drawMode.phase.typename !== "movingNode"
Expand Down Expand Up @@ -181,6 +219,11 @@ export default function Canvas({
typename: "addNode",
phase: { typename: "idle" },
});
} else if (e.key === "Escape" && drawMode.typename === "addEdge") {
onDrawModeChange({
typename: "addEdge",
phase: { typename: "idle" },
});
} else if (e.key === "Delete" && drawMode.typename === "select") {
const phase = drawMode.phase;
if (phase.typename === "selected") {
Expand Down Expand Up @@ -226,19 +269,6 @@ export default function Canvas({
);
}

type CanvasState = {
canvas: HTMLCanvasElement;
grid: Grid;
scale: number;
translate: UseTranslatePositionRtn;
cursor: { x: number; y: number };
drawMode: DrawMode;
};

type ContextState = Omit<CanvasState, "canvas"> & {
ctx: CanvasRenderingContext2D;
};

function nodeIntersectsWithLasso(
cursor: UseCursorRtn,
lassoStart: { x: number; y: number },
Expand All @@ -258,152 +288,3 @@ function nodeIntersectsWithLasso(
const intersects = distanceSquared <= node.radius * node.radius;
return intersects;
}

function draw({
canvas,
grid,
scale,
translate,
cursor,
drawMode,
}: CanvasState) {
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio * scale;
const cssWidth = Math.round(canvas.clientWidth / scale);
const cssHeight = Math.round(canvas.clientHeight / scale);
const pxWidth = Math.round(dpr * cssWidth);
const pxHeight = Math.round(dpr * cssHeight);
canvas.width = pxWidth;
canvas.height = pxHeight;
if (ctx) {
ctx.translate(translate.translateX, translate.translateY);
ctx.scale(dpr, dpr);
const contextState: ContextState = {
ctx,
grid,
scale,
translate,
cursor,
drawMode,
};
drawGrid(contextState);
drawNodes(contextState);
drawCursor(contextState);
}
}

function drawCursor({
ctx,
grid,
cursor: { x, y },
scale,
drawMode,
}: ContextState) {
ctx.strokeStyle = "blue";
ctx.fillStyle = "black";
const fontSize = 1 / scale + 1;
ctx.font = `${fontSize}rem Arial`;
ctx.lineWidth = grid.gridSquareSize / 5;
const textOffset = grid.gridSquareSize / 2;
ctx.fillText(
`${x.toFixed(2)}, ${y.toFixed(2)}`,
x + textOffset,
y - textOffset,
);
const crossHairSize = grid.gridSquareSize * 5;
ctx.beginPath();
ctx.moveTo(x - crossHairSize, y);
ctx.lineTo(x + crossHairSize, y);
ctx.moveTo(x, y - crossHairSize);
ctx.lineTo(x, y + crossHairSize);
ctx.stroke();
if (drawMode.typename === "select" && drawMode.phase.typename === "lasso") {
ctx.strokeStyle = "red";
ctx.beginPath();
ctx.moveTo(drawMode.phase.start.x, drawMode.phase.start.y);
ctx.lineTo(x, drawMode.phase.start.y);
ctx.lineTo(x, y);
ctx.lineTo(drawMode.phase.start.x, y);
ctx.lineTo(drawMode.phase.start.x, drawMode.phase.start.y);
ctx.stroke();
} else if (
drawMode.typename === "addNode" &&
drawMode.phase.typename === "adding"
) {
ctx.strokeStyle = "green";
const deltaX = x - drawMode.phase.start.x;
const deltaY = y - drawMode.phase.start.y;
const radius = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
ctx.beginPath();
ctx.arc(
drawMode.phase.start.x,
drawMode.phase.start.y,
radius,
0,
2 * Math.PI,
);
ctx.stroke();
}
}

function drawNodes({ grid, ctx, drawMode }: ContextState) {
const selectedUuids =
drawMode.typename === "select" && drawMode.phase.typename === "selected"
? drawMode.phase.uuids
: drawMode.typename === "select" &&
drawMode.phase.typename === "movingNode"
? drawMode.phase.startNodes.map((x) => x.uuid)
: [];
for (const node of grid.nodes) {
if (selectedUuids.includes(node.uuid)) {
ctx.strokeStyle = "red";
ctx.lineWidth = grid.gridSquareSize / 5;
ctx.setLineDash([grid.gridSquareSize / 5, grid.gridSquareSize / 5]);
ctx.beginPath();
ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI);
ctx.stroke();
} else {
ctx.strokeStyle = "black";
ctx.fillStyle = "white";
ctx.setLineDash([]);
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
}
ctx.setLineDash([]);
}

function drawGrid({ grid, ctx }: ContextState) {
ctx.lineWidth = 1;
let iteration = 0;
const maxLength = 2000;
for (let i = -maxLength; i <= maxLength; i += grid.gridSquareSize) {
if (iteration % 5 === 0) {
ctx.strokeStyle = "black";
} else {
ctx.strokeStyle = "grey";
}
ctx.beginPath();
iteration++;
ctx.moveTo(i, -maxLength);
ctx.lineTo(i, maxLength);
ctx.stroke();
}

iteration = 0;
for (let i = -maxLength; i <= maxLength; i += grid.gridSquareSize) {
if (iteration % 5 === 0) {
ctx.strokeStyle = "black";
} else {
ctx.strokeStyle = "grey";
}
iteration++;
ctx.beginPath();
ctx.moveTo(-maxLength, i);
ctx.lineTo(maxLength, i);
ctx.stroke();
}
}
Loading

0 comments on commit bf39476

Please sign in to comment.