/** * Generate list of integers from 10 to 2000 in increments of 10 */ function generateIntegers(start: number, end: number, step: number): number[] { const integers: number[] = []; for (let i = start; i <= end; i += step) { integers.push(i); } return integers; } /** * Precomputed list of integers (10, 20, 30, ..., 2000) */ export const INTEGERS = generateIntegers(10, 2000, 10); /** * Get the index of an integer in the precomputed list, or -1 if not found */ export function getIntegerIndex(integer: number): number { return INTEGERS.indexOf(integer); } /** * Get the integer at a specific index in the precomputed list */ export function getIntegerAtIndex(index: number): number | undefined { return INTEGERS[index]; } /** * Get the next integer in the precomputed list */ export function getNextInteger(currentInteger: number): number { const index = getIntegerIndex(currentInteger); if (index === -1 || index === INTEGERS.length - 1) { return currentInteger; // Stay at current if not found or at end } return INTEGERS[index + 1]; } /** * Get the previous integer in the precomputed list */ export function getPreviousInteger(currentInteger: number): number { const index = getIntegerIndex(currentInteger); if (index === -1 || index === 0) { return currentInteger; // Stay at current if not found or at start } return INTEGERS[index - 1]; } /** * Calculate the best initial integer based on viewport dimensions * The grid size will be n × n pixels * * @param maxInteger - Maximum allowed integer (default 2000) * @returns The largest integer that will fit in the viewport without scrolling */ export function getInitialIntegerForViewport(maxInteger: number = 2000): number { // MUI's 'md' breakpoint is 900px const isMobile = window.innerWidth < 900; let availableWidth: number; let availableHeight: number; if (isMobile) { // Mobile layout: controls at top, full width available // Account for left/right padding (~20px total on mobile) availableWidth = window.innerWidth - 20; // Account for controls section at top (approximately 400-450px) and padding // Being conservative with 500px to ensure it fits availableHeight = window.innerHeight - 500; } else { // Desktop layout: sidebar on left // Account for sidebar (300px) and padding/margins (~50px total) availableWidth = window.innerWidth - 350; // Account for top/bottom padding (~50px total) availableHeight = window.innerHeight - 50; } // Use the smaller dimension to ensure it fits both ways const availableSize = Math.min(availableWidth, availableHeight); // Find the largest integer where n fits in the available space // Round down to nearest multiple of 10 const targetInteger = Math.floor(availableSize / 10) * 10; // Find the largest integer in our list that doesn't exceed the target or max const maxAllowedInteger = Math.min(targetInteger, maxInteger); // Find the largest integer in our list that doesn't exceed the max for (let i = INTEGERS.length - 1; i >= 0; i--) { if (INTEGERS[i] <= maxAllowedInteger) { return INTEGERS[i]; } } // Fallback to smallest integer if viewport is too small return INTEGERS[0]; }