about summary refs log tree commit diff stats
path: root/html/simple-shape/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'html/simple-shape/index.html')
-rw-r--r--html/simple-shape/index.html352
1 files changed, 214 insertions, 138 deletions
diff --git a/html/simple-shape/index.html b/html/simple-shape/index.html
index 75b1f6b..4e4fa49 100644
--- a/html/simple-shape/index.html
+++ b/html/simple-shape/index.html
@@ -55,33 +55,137 @@
     </div>
     <script>
         /**
+         * Configuration object for application-wide settings
+         * Centralizes magic numbers and configuration values
+         * @constant {Object}
+         */
+        const CONFIG = {
+            canvas: {
+                dpi: 300,
+                width: 8.5 * 300, // 8.5in at 300dpi
+                height: 11 * 300, // 11in at 300dpi
+            },
+            grid: {
+                rows: 4,
+                columns: 5,
+                topMargin: 100,
+                bottomMargin: 300,
+                patternSize: 400,
+                gutterRatio: 0.1, // 10% of pattern size
+                patternRatio: 0.8  // 80% of space for pattern
+            },
+            style: {
+                strokeWidth: 4,
+                strokeColor: '#000'
+            }
+        };
+
+        /**
          * Canvas Setup and Configuration
          * This section initializes a high-resolution canvas optimized for both screen display and printing.
-         * The dimensions are calculated based on standard US Letter size (8.5x11 inches) at 300 DPI.
          */
         const canvas = document.getElementById('canvas');
         const ctx = canvas.getContext('2d');
         
-        canvas.width = 2550;  // 8.5in * 300dpi
-        canvas.height = 3300; // 11in * 300dpi
+        canvas.width = CONFIG.canvas.width;
+        canvas.height = CONFIG.canvas.height;
 
         /**
-         * Utility Functions
-         * A collection of pure functions for randomization, following the functional programming paradigm.
-         * These provide a consistent interface for generating random values across the application.
+         * Utility Functions Module
+         * Pure functions for common operations
+         * @namespace Utils
          */
-        const random = (min, max) => Math.random() * (max - min) + min;
-        const randomInt = (min, max) => Math.floor(random(min, max));
-        const randomChoice = arr => arr[Math.floor(Math.random() * arr.length)];
+        const Utils = {
+            /**
+             * Generates a random number within a range
+             * @param {number} min - Minimum value
+             * @param {number} max - Maximum value
+             * @returns {number}
+             */
+            random: (min, max) => Math.random() * (max - min) + min,
+            
+            /**
+             * Generates a random integer within a range
+             * @param {number} min - Minimum value
+             * @param {number} max - Maximum value
+             * @returns {number}
+             */
+            randomInt: (min, max) => Math.floor(Utils.random(min, max)),
+            
+            /**
+             * Randomly selects an item from an array
+             * @param {Array} arr - Source array
+             * @returns {*}
+             */
+            randomChoice: arr => arr[Math.floor(Math.random() * arr.length)],
+            
+            /**
+             * Fisher-Yates shuffle implementation
+             * @param {Array} arr - Array to shuffle
+             * @returns {Array} New shuffled array
+             */
+            shuffle: arr => [...arr].sort(() => Math.random() - 0.5),
+            
+            /**
+             * Creates a range array of numbers
+             * @param {number} start - Start value
+             * @param {number} end - End value
+             * @returns {Array<number>}
+             */
+            range: (start, end) => Array.from(
+                { length: end - start }, 
+                (_, i) => start + i
+            )
+        };
+
+        /**
+         * Drawing Context Manager
+         * Handles canvas context state management using functional composition
+         * @namespace ContextManager
+         */
+        const ContextManager = {
+            /**
+             * Executes a drawing operation with saved context state
+             * @param {Function} drawFn - Drawing function to execute
+             * @returns {Function}
+             */
+            withContext: drawFn => (...args) => {
+                ctx.save();
+                drawFn(...args);
+                ctx.restore();
+            },
+
+            /**
+             * Applies a translation transformation
+             * @param {number} x - X translation
+             * @param {number} y - Y translation
+             * @returns {Function}
+             */
+            withTranslation: (x, y) => drawFn => (...args) => {
+                ctx.translate(x, y);
+                drawFn(...args);
+            },
+
+            /**
+             * Applies a rotation transformation around a point
+             * @param {number} angle - Rotation angle in radians
+             * @param {number} x - Center X coordinate
+             * @param {number} y - Center Y coordinate
+             * @returns {Function}
+             */
+            withRotation: (angle, x, y) => drawFn => (...args) => {
+                ctx.translate(x, y);
+                ctx.rotate(angle);
+                ctx.translate(-x, -y);
+                drawFn(...args);
+            }
+        };
 
         /**
          * Shape Factory Pattern
-         * Implements the Factory pattern to create basic geometric shapes.
-         * Each factory method is a pure function that takes position and size parameters.
-         * The factory uses method chaining with the Canvas API for drawing operations.
-         * @namespace
+         * @namespace Shapes
          */
-        const shapes = {
+        const Shapes = {
             /**
              * Creates a circle with optional fill
              * @param {number} x - Center X coordinate
@@ -121,20 +225,34 @@
 
         /**
          * Pattern Generator System
-         * Implements the Strategy pattern for pattern generation.
-         * Uses higher-order functions to create composable pattern generators.
-         * Each pattern is a pure function that can be transformed and combined.
-         * 
-         * @function generatePattern
-         * @returns {Function} A pattern generation function that takes x, y, and size parameters
+         * @namespace Patterns
          */
-        const generatePattern = () => {
+        const Patterns = {
+            /**
+             * Creates a pattern generator with transformation capabilities
+             * @param {Function} patternFn - Base pattern drawing function
+             * @returns {Function} Enhanced pattern generator
+             */
+            createGenerator: patternFn => {
+                return ContextManager.withContext((x, y, size) => {
+                    const rotation = Math.PI/2 * Utils.randomInt(0, 4);
+                    if (rotation > 0) {
+                        ContextManager.withRotation(
+                            rotation,
+                            x + size/2,
+                            y + size/2
+                        )(patternFn)(x, y, size);
+                    } else {
+                        patternFn(x, y, size);
+                    }
+                });
+            },
+
             /**
-             * Collection of pattern strategies
-             * Each strategy is a pure function implementing a specific pattern algorithm
+             * Collection of base pattern implementations
              * @type {Array<Function>}
              */
-            const types = [
+            types: [
                 /**
                  * Grid-based pattern strategy
                  * Demonstrates use of nested loops for regular grid generation
@@ -147,7 +265,7 @@
                     for(let i = 0; i < 3; i++) {
                         for(let j = 0; j < 3; j++) {
                             if((i + j) % 2 === 0) { // Checkerboard pattern
-                                shapes.circle(
+                                Shapes.circle(
                                     x + spacing/2 + i * spacing,
                                     y + spacing/2 + j * spacing,
                                     spacing/2
@@ -162,7 +280,7 @@
                     for(let i = 3; i > 0; i--) {
                         const offset = (3 - i) * size/6;
                         const squareSize = size - offset * 2;
-                        shapes.square(x + offset, y + offset, squareSize);
+                        Shapes.square(x + offset, y + offset, squareSize);
                     }
                 },
 
@@ -172,14 +290,14 @@
                     const radius = size/4;
                     
                     // Center circle
-                    shapes.circle(x + center, y + center, size/6);
+                    Shapes.circle(x + center, y + center, size/6);
                     
                     // Petals
                     for(let i = 0; i < 6; i++) {
                         const angle = (i / 6) * Math.PI * 2;
                         const petalX = x + center + Math.cos(angle) * radius;
                         const petalY = y + center + Math.sin(angle) * radius;
-                        shapes.circle(petalX, petalY, size/6);
+                        Shapes.circle(petalX, petalY, size/6);
                     }
                 },
 
@@ -187,7 +305,7 @@
                 (x, y, size) => {
                     const triSize = size/3;
                     for(let i = 0; i < 3; i++) {
-                        shapes.triangle(
+                        Shapes.triangle(
                             x + i * triSize,
                             y + (i % 2) * triSize/2,
                             triSize
@@ -200,7 +318,7 @@
                     const gridSize = size/2;
                     for(let i = 0; i < 2; i++) {
                         for(let j = 0; j < 2; j++) {
-                            shapes.square(
+                            Shapes.square(
                                 x + i * gridSize + size/8,
                                 y + j * gridSize + size/8,
                                 gridSize * 0.75
@@ -215,13 +333,13 @@
                     for(let i = 0; i < 2; i++) {
                         for(let j = 0; j < 2; j++) {
                             if((i + j) % 2 === 0) {
-                                shapes.circle(
+                                Shapes.circle(
                                     x + spacing/2 + i * spacing,
                                     y + spacing/2 + j * spacing,
                                     spacing/3
                                 );
                             } else {
-                                shapes.square(
+                                Shapes.square(
                                     x + i * spacing + spacing/6,
                                     y + j * spacing + spacing/6,
                                     spacing * 2/3
@@ -235,11 +353,11 @@
                 (x, y, size) => {
                     const center = size/2;
                     // Horizontal and vertical lines
-                    shapes.line(x, y + center, x + size, y + center);
-                    shapes.line(x + center, y, x + center, y + size);
+                    Shapes.line(x, y + center, x + size, y + center);
+                    Shapes.line(x + center, y, x + center, y + size);
                     // Diagonal lines
-                    shapes.line(x, y, x + size, y + size);
-                    shapes.line(x + size, y, x, y + size);
+                    Shapes.line(x, y, x + size, y + size);
+                    Shapes.line(x + size, y, x, y + size);
                 },
 
                 // Nested arcs
@@ -278,7 +396,7 @@
                 (x, y, size) => {
                     const center = size/2;
                     for(let i = 1; i <= 3; i++) {
-                        shapes.circle(
+                        Shapes.circle(
                             x + center,
                             y + center,
                             size,
@@ -330,118 +448,76 @@
                         ctx.stroke();
                     }
                 }
-            ];
-
-            /**
-             * Pattern Generator Factory
-             * Creates a new pattern generator with transformation capabilities
-             * Implements the Decorator pattern for adding rotation behavior
-             * @returns {Function} A function that generates a specific pattern with transformations
-             */
-            return (x, y, size) => {
-                ctx.save();
-                ctx.translate(x, y);
-                
-                // Rotation decorator
-                const rotation = Math.PI/2 * randomInt(0, 4);
-                if(rotation > 0) {
-                    ctx.translate(size/2, size/2);
-                    ctx.rotate(rotation);
-                    ctx.translate(-size/2, -size/2);
-                }
-                
-                randomChoice(types)(0, 0, size);
-                ctx.restore();
-            };
+            ]
         };
 
         /**
-         * Pattern Collection
-         * Creates a pool of pattern generators using the Factory pattern
-         * Limits the number of patterns to ensure visual coherence through repetition
-         * @type {Array<Function>}
-         */
-        const patterns = Array(10).fill(null).map(generatePattern);
-
-        /**
          * Layout System
-         * Implements a responsive grid layout system with gutters and margins
-         * Uses the Composite pattern to build complex layouts from simple components
+         * Handles grid layout and composition
+         * @namespace Layout
          */
+        const Layout = {
+            /**
+             * Calculates layout metrics for the grid
+             * @returns {Object} Layout calculations
+             */
+            calculateMetrics: () => {
+                const availableHeight = CONFIG.canvas.height - 
+                    (CONFIG.grid.topMargin + CONFIG.grid.bottomMargin);
+                
+                const totalPatternHeight = CONFIG.grid.rows * CONFIG.grid.patternSize;
+                const totalGapHeight = availableHeight - totalPatternHeight;
+                const rowGap = totalGapHeight / (CONFIG.grid.rows - 1);
+                
+                const totalWidth = CONFIG.grid.patternSize * CONFIG.grid.columns;
+                const xOffset = (CONFIG.canvas.width - totalWidth) / 2;
+                
+                return { rowGap, xOffset };
+            },
 
-        /**
-         * Fisher-Yates shuffle implementation
-         * Used for randomizing pattern order while maintaining uniform distribution
-         * @param {Array} arr - Array to shuffle
-         * @returns {Array} New shuffled array
-         */
-        const shuffle = arr => [...arr].sort(() => Math.random() - 0.5);
+            /**
+             * Draws a row of patterns
+             */
+            drawRow: (xOffset, y, size) => {
+                const gutter = size * CONFIG.grid.gutterRatio;
+                const patternSize = size * CONFIG.grid.patternRatio;
+                
+                const patterns = Utils.shuffle(patternGenerators);
+                Utils.range(0, CONFIG.grid.columns).forEach(i => {
+                    const xPos = xOffset + i * size + gutter;
+                    const yPos = y + gutter;
+                    patterns[i](xPos, yPos, patternSize);
+                });
+            },
 
-        /**
-         * Row Composition Function
-         * Implements the Composite pattern for building rows of patterns
-         * Handles spacing and layout calculations for individual patterns
-         * @param {number} xOffset - Starting X position for the row
-         * @param {number} y - Y position for the row
-         * @param {number} size - Size of each pattern cell
-         */
-        const drawPatternRow = (xOffset, y, size) => {
-            const gutter = size * 0.1; // 10% of pattern size for gutter
-            const patternWithGutter = size * 0.8; // 80% of space for actual pattern
-            
-            const shuffledPatterns = shuffle(patterns);
-            for(let i = 0; i < 5; i++) {
-                const xPos = xOffset + i * size + gutter;
-                const yPos = y + gutter;
-                shuffledPatterns[i](xPos, yPos, patternWithGutter);
+            /**
+             * Draws the complete grid
+             */
+            drawGrid: () => {
+                ctx.clearRect(0, 0, CONFIG.canvas.width, CONFIG.canvas.height);
+                
+                ctx.strokeStyle = CONFIG.style.strokeColor;
+                ctx.lineWidth = CONFIG.style.strokeWidth;
+                
+                const { rowGap, xOffset } = Layout.calculateMetrics();
+                
+                Utils.range(0, CONFIG.grid.rows).forEach(i => {
+                    const y = CONFIG.grid.topMargin + 
+                        i * (CONFIG.grid.patternSize + rowGap);
+                    Layout.drawRow(xOffset, y, CONFIG.grid.patternSize);
+                });
             }
         };
 
-        /**
-         * Grid Layout Manager
-         * Implements the Facade pattern to simplify complex layout operations
-         * Handles margin calculations, row spacing, and overall composition
-         * Uses asymmetric margins for better visual balance
-         */
-        const drawGrid = () => {
-            ctx.clearRect(0, 0, canvas.width, canvas.height);
-            
-            ctx.strokeStyle = '#000';
-            ctx.lineWidth = 4;
-            
-            const patternSize = 400;
-            const numRows = 4;
-            const topMargin = 100;     // Reduced from 300
-            const bottomMargin = 300;  // Keep original bottom margin
-            
-            // Calculate available space with asymmetric margins
-            const availableHeight = canvas.height - (topMargin + bottomMargin);
-            
-            // Calculate row spacing with increased gaps
-            const totalPatternHeight = numRows * patternSize;
-            const totalGapHeight = availableHeight - totalPatternHeight;
-            const rowGap = totalGapHeight / (numRows - 1);
-            
-            // Calculate horizontal centering
-            const totalWidth = patternSize * 5;
-            const xOffset = (canvas.width - totalWidth) / 2;
-            
-            // Draw each row
-            for(let i = 0; i < numRows; i++) {
-                const y = topMargin + i * (patternSize + rowGap);
-                drawPatternRow(xOffset, y, patternSize);
-            }
-        };
+        // Generate pattern instances
+        const patternGenerators = Utils.range(0, 10)
+            .map(() => Patterns.createGenerator(
+                Utils.randomChoice(Patterns.types)
+            ));
 
-        // Initialize the system
-        drawGrid();
-        
-        /**
-         * Event Handler
-         * Implements the Observer pattern for user interaction
-         * Regenerates the entire pattern grid on demand
-         */
-        canvas.addEventListener('click', drawGrid);
+        // Initialize and set up interaction
+        Layout.drawGrid();
+        canvas.addEventListener('click', Layout.drawGrid);
     </script>
 </body>
 </html>
\ No newline at end of file