linked list visualisations
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
'use client';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { LinkedListState, LinkedListPointerState } from '@/lib/visualizations/types';
|
||||
import { LinkedListNode } from '../primitives/linked-list-node';
|
||||
import { LinkedListPointer } from '../primitives/linked-list-pointer';
|
||||
|
||||
interface LinkedListViewProps {
|
||||
list: LinkedListState;
|
||||
pointers: LinkedListPointerState[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const NODE_WIDTH = 40; // w-10 = 40px
|
||||
const ARROW_WIDTH = 22; // 16px line + 6px arrow head
|
||||
|
||||
export function LinkedListView({
|
||||
list,
|
||||
pointers,
|
||||
className,
|
||||
}: LinkedListViewProps) {
|
||||
// Calculate total width for proper pointer alignment
|
||||
const totalWidth = list.nodes.length * NODE_WIDTH + (list.nodes.length - 1) * ARROW_WIDTH;
|
||||
|
||||
// Group pointers by nodeIndex to calculate offsets for overlapping pointers
|
||||
const pointersByIndex = pointers.reduce((acc, pointer) => {
|
||||
const idx = pointer.nodeIndex;
|
||||
if (!acc[idx]) acc[idx] = [];
|
||||
acc[idx].push(pointer);
|
||||
return acc;
|
||||
}, {} as Record<number, LinkedListPointerState[]>);
|
||||
|
||||
// Calculate horizontal offset for each pointer
|
||||
const getPointerOffset = (pointer: LinkedListPointerState): number => {
|
||||
const pointersAtIndex = pointersByIndex[pointer.nodeIndex] || [];
|
||||
if (pointersAtIndex.length <= 1) return 0;
|
||||
|
||||
const pointerIdx = pointersAtIndex.findIndex(p => p.id === pointer.id);
|
||||
const totalPointers = pointersAtIndex.length;
|
||||
const spacing = 28; // px between overlapping pointers
|
||||
// Center the group: offset from center based on position
|
||||
return (pointerIdx - (totalPointers - 1) / 2) * spacing;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col items-center', className)}>
|
||||
{list.label && (
|
||||
<span className="mb-2 text-sm font-medium text-foreground-muted">
|
||||
{list.label}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div className="relative" style={{ width: totalWidth }}>
|
||||
{/* Pointers row */}
|
||||
<div className="relative mb-1 h-8">
|
||||
{pointers.map((pointer) => (
|
||||
<LinkedListPointer
|
||||
key={pointer.id}
|
||||
pointer={pointer}
|
||||
nodeWidth={NODE_WIDTH}
|
||||
arrowWidth={ARROW_WIDTH}
|
||||
horizontalOffset={getPointerOffset(pointer)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Linked list nodes */}
|
||||
<div className="flex items-center">
|
||||
{list.nodes.map((node, index) => (
|
||||
<LinkedListNode
|
||||
key={node.id}
|
||||
node={node}
|
||||
isLast={index === list.nodes.length - 1}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user