@webwriter/flowchart
Version:
Create programming flowcharts with interactive tasks. Use standardized Elements such as loops and Branchings.
119 lines (95 loc) • 4.43 kB
text/typescript
import { GraphNode } from "../../definitions/GraphNode";
// Entfernt die alten Verbindungsinformationen innerhalb der Knoten
export function removeOldConnection(fromNode: GraphNode, toNode: GraphNode) {
// Entferne die Verbindungsinformation vom Startknoten
if (fromNode.connections) {
fromNode.connections = fromNode.connections.filter(
(connection) => connection.connectedToId !== toNode.id
);
}
// Entferne die Verbindungsinformation vom Zielknoten
if (toNode.connections) {
toNode.connections = toNode.connections.filter(
(connection) => connection.connectedToId !== fromNode.id
);
}
}
export function snapNodePosition(ctx: CanvasRenderingContext2D, draggedNode: GraphNode, graphNodes: GraphNode[], threshold: number): void {
const draggedNodeSize = measureTextSize(ctx, draggedNode.text);
for (const node of graphNodes) {
if (node.id === draggedNode.id) {
continue;
}
const nodeSize = measureTextSize(ctx, node.text);
const xDifference = Math.abs((draggedNode.x + draggedNodeSize.width / 2) - (node.x + nodeSize.width / 2));
const yDifference = Math.abs((draggedNode.y + draggedNodeSize.height / 2) - (node.y + nodeSize.height / 2));
if (xDifference <= threshold) {
draggedNode.x = node.x + nodeSize.width / 2 - draggedNodeSize.width / 2;
}
if (yDifference <= threshold) {
draggedNode.y = node.y + nodeSize.height / 2 - draggedNodeSize.height / 2;
}
}
}
export const isWithinCircle = (x: number, y: number, circleX: number, circleY: number, radius: number):
boolean => Math.sqrt(Math.pow(x - circleX, 2) + Math.pow(y - circleY, 2)) <= radius;
// Bestimmt die Maße des Knotens anhand der Textgrößen
export function measureTextSize(ctx: CanvasRenderingContext2D, text: string): { width: number; height: number } {
const metrics = ctx.measureText(text);
const width = metrics.width + 60;
// Extrahiere die Schriftgröße aus der Font-Eigenschaft des Canvas-Kontexts
const fontSizeMatch = ctx.font.match(/\d+px/);
const fontSize = fontSizeMatch ? parseInt(fontSizeMatch[0], 10) : 16;
// Berechne die Höhe basierend auf der Schriftgröße
const height = fontSize + 30;
if (text === '') {
return { width: 30, height: 30 };
}
return { width, height };
}
export function isNodeInRectangle(ctx: CanvasRenderingContext2D, node: GraphNode, rect: { x: number, y: number, width: number, height: number }): boolean {
const rectStartX = rect.width >= 0 ? rect.x : rect.x + rect.width;
const rectStartY = rect.height >= 0 ? rect.y : rect.y + rect.height;
const rectEndX = rect.width >= 0 ? rect.x + rect.width : rect.x;
const rectEndY = rect.height >= 0 ? rect.y + rect.height : rect.y;
// Berechne die Mitte des Knotens
const nodeCenterX = node.x + (measureTextSize(ctx, node.text).width / 2);
const nodeCenterY = node.y + (measureTextSize(ctx, node.text).height / 2);
return nodeCenterX >= rectStartX && nodeCenterY >= rectStartY && nodeCenterX <= rectEndX && nodeCenterY <= rectEndY;
}
export function findLastGraphNode(ctx: CanvasRenderingContext2D, graphNodes: GraphNode[], x: number, y: number) {
const d = 5; // Toleranzbereich
return findLast(graphNodes, (element) =>
x >= element.x - d &&
x <= element.x + measureTextSize(ctx, element.text).width + d &&
y >= element.y - d &&
y <= element.y + measureTextSize(ctx, element.text).height + d
);
}
export function findGraphNodeLastIndex(ctx: CanvasRenderingContext2D, graphNodes: GraphNode[], x: number, y: number) {
const d = 5; // Toleranzbereich
return findLastIndex(graphNodes, (element) =>
x >= element.x - d &&
x <= element.x + measureTextSize(ctx, element.text).width + d &&
y >= element.y - d &&
y <= element.y + measureTextSize(ctx, element.text).height + d
);
}
function findLast<T>(arr: T[], predicate: (element: T) => boolean): T | undefined {
for (let i = arr.length - 1; i >= 0; i--) {
const element = arr[i];
if (predicate(element)) {
return element;
}
}
return undefined;
}
export function findLastIndex<T>(arr: T[], predicate: (element: T) => boolean): number {
for (let i = arr.length - 1; i >= 0; i--) {
const element = arr[i];
if (predicate(element)) {
return i;
}
}
return -1;
}