UNPKG

@webwriter/flowchart

Version:

Create programming flowcharts with interactive tasks. Use standardized Elements such as loops and Branchings.

116 lines (103 loc) 4.11 kB
import { GraphNode } from '../../definitions/GraphNode'; import { Arrow } from '../../definitions/Arrow'; import { findLastGraphNode } from '../helper/utilities'; import { findArrow } from '../helper/arrowHelper'; import { findLastIndex } from '../helper/utilities'; export function handleSequenceSelection( ctx: CanvasRenderingContext2D, selectedSequence: { id: string; order: number; type: string; }[], graphNodes: GraphNode[], arrows: Arrow[], x: number, y: number ) { const clickedNode = findLastGraphNode(ctx, graphNodes, x, y); const clickedArrow = findArrow(arrows, x, y); let clickedItem: GraphNode | Arrow; let sequenceType: string; if (clickedNode) { clickedItem = clickedNode; sequenceType = 'node'; } else if (clickedArrow) { clickedItem = clickedArrow; sequenceType = 'arrow'; } if (clickedItem) { selectedSequence.push({ id: clickedItem.id, order: selectedSequence.length + 1, type: sequenceType, }); return; const existingIndex = findLastIndex( selectedSequence, (item) => item.id === clickedItem.id && item.type === sequenceType ); const lastIndex = selectedSequence.length - 1; const lastItemType = lastIndex >= 0 ? selectedSequence[lastIndex].type : null; const lastItemId = lastIndex >= 0 ? selectedSequence[lastIndex].id : null; if (selectedSequence.length === 0 || (lastItemType !== sequenceType && existingIndex !== -1)) { selectedSequence.push({ id: clickedItem.id, order: selectedSequence.length + 1, type: sequenceType, }); } else if (existingIndex === lastIndex) { selectedSequence.pop(); } else { let lastItem: GraphNode | Arrow; if (lastItemType === 'node') { lastItem = graphNodes.find((node) => node.id === lastItemId); } else { lastItem = arrows.find((arrow) => arrow.id === lastItemId); } if (sequenceType === 'node' && isArrow(lastItem)) { const clickedNode = clickedItem as GraphNode; const connectedNode = findConnectedNode(lastItem, clickedNode, graphNodes); if (connectedNode || existingIndex !== -1) { selectedSequence.push({ id: clickedItem.id, order: selectedSequence.length + 1, type: sequenceType, }); } } else if (sequenceType === 'arrow' && isGraphNode(lastItem)) { const clickedArrow = clickedItem as Arrow; const connectedArrow = findConnectedArrow(lastItem, clickedArrow, arrows); if (connectedArrow || existingIndex !== -1) { selectedSequence.push({ id: clickedItem.id, order: selectedSequence.length + 1, type: sequenceType, }); } } } } } function findConnectedArrow(node: GraphNode, clickedArrow: Arrow, arrows: Arrow[]): Arrow | null { for (const arrow of arrows) { if (arrow.from.id === node.id && arrow.id === clickedArrow.id) { return arrow; } } return null; } function findConnectedNode(arrow: Arrow, clickedNode: GraphNode, graphNodes: GraphNode[]): GraphNode | null { for (const node of graphNodes) { if (arrow.to.id === node.id && clickedNode.id === node.id) { return node; } } return null; } function isGraphNode(obj: GraphNode | Arrow): obj is GraphNode { return (obj as GraphNode).node !== undefined; } function isArrow(obj: GraphNode | Arrow): obj is Arrow { return (obj as Arrow).from !== undefined; }