/ concept-collection / gcd-visualizer
concept-collection / gcd-visualizer
gcd-visualizer / src / utils / integerUtils.ts
103 lines · 3.2 KBBlameHistoryRaw
1/**
2 * Generate list of integers from 10 to 2000 in increments of 10
3 */
4function generateIntegers(start: number, end: number, step: number): number[] {
5 const integers: number[] = [];
6 for (let i = start; i <= end; i += step) {
7 integers.push(i);
8 }
9 return integers;
12/**
13 * Precomputed list of integers (10, 20, 30, ..., 2000)
14 */
15export const INTEGERS = generateIntegers(10, 2000, 10);
17/**
18 * Get the index of an integer in the precomputed list, or -1 if not found
19 */
20export function getIntegerIndex(integer: number): number {
21 return INTEGERS.indexOf(integer);
24/**
25 * Get the integer at a specific index in the precomputed list
26 */
27export function getIntegerAtIndex(index: number): number | undefined {
28 return INTEGERS[index];
31/**
32 * Get the next integer in the precomputed list
33 */
34export function getNextInteger(currentInteger: number): number {
35 const index = getIntegerIndex(currentInteger);
36 if (index === -1 || index === INTEGERS.length - 1) {
37 return currentInteger; // Stay at current if not found or at end
38 }
39 return INTEGERS[index + 1];
42/**
43 * Get the previous integer in the precomputed list
44 */
45export function getPreviousInteger(currentInteger: number): number {
46 const index = getIntegerIndex(currentInteger);
47 if (index === -1 || index === 0) {
48 return currentInteger; // Stay at current if not found or at start
49 }
50 return INTEGERS[index - 1];
53/**
54 * Calculate the best initial integer based on viewport dimensions
55 * The grid size will be n × n pixels
56 *
57 * @param maxInteger - Maximum allowed integer (default 2000)
58 * @returns The largest integer that will fit in the viewport without scrolling
59 */
60export function getInitialIntegerForViewport(maxInteger: number = 2000): number {
61 // MUI's 'md' breakpoint is 900px
62 const isMobile = window.innerWidth < 900;
64 let availableWidth: number;
65 let availableHeight: number;
67 if (isMobile) {
68 // Mobile layout: controls at top, full width available
69 // Account for left/right padding (~20px total on mobile)
70 availableWidth = window.innerWidth - 20;
72 // Account for controls section at top (approximately 400-450px) and padding
73 // Being conservative with 500px to ensure it fits
74 availableHeight = window.innerHeight - 500;
75 } else {
76 // Desktop layout: sidebar on left
77 // Account for sidebar (300px) and padding/margins (~50px total)
78 availableWidth = window.innerWidth - 350;
80 // Account for top/bottom padding (~50px total)
81 availableHeight = window.innerHeight - 50;
82 }
84 // Use the smaller dimension to ensure it fits both ways
85 const availableSize = Math.min(availableWidth, availableHeight);
87 // Find the largest integer where n fits in the available space
88 // Round down to nearest multiple of 10
89 const targetInteger = Math.floor(availableSize / 10) * 10;
91 // Find the largest integer in our list that doesn't exceed the target or max
92 const maxAllowedInteger = Math.min(targetInteger, maxInteger);
94 // Find the largest integer in our list that doesn't exceed the max
95 for (let i = INTEGERS.length - 1; i >= 0; i--) {
96 if (INTEGERS[i] <= maxAllowedInteger) {
97 return INTEGERS[i];
98 }
99 }
101 // Fallback to smallest integer if viewport is too small
102 return INTEGERS[0];