Koch snowflake

💾 replit:canvas Koch snowflake

⬆️ 需要: Vector, drawOnCanvas2D()

const { PI } = Math;
const { log } = console;

// degrees
function deg(x) { return PI * x / 180 }

// draw on canvas
drawOnCanvas2D('#playground', (c) => {

    // Draw a level-n Koch snowflake fractal, 
    // with lower-left corner at (x,y) and side length len. 
    function snowflake(n, x, y, len) {

        // save current transformation matrix
        // because:
        // - we're going to translate the matrix
        // - calling `leg()` will change the matrix
        c.save(); 

        c.translate(x, y);     // translate coord system to (x,y)
        c.moveTo(0, 0);        // begin a new subpath

        // draw 3 legs
        [0, -120, -120].forEach(angle => {
            c.rotate(deg(angle));
            leg(n);
        })

        // close subpath 
        c.closePath(); 

        // restore original transformation matrix before calling `snowflake()`
        c.restore(); 

        // Draw a single leg of a level-n Koch snowflake.
        // - translates coordinate system to the end of leg.
        // - easily call rotate() after drawing a leg.
        function leg(n) {

            // base case: 
            // ---------------------------------
            if (n === 0) { c.lineTo(len, 0) }    // - just a horizontal line

            // recursive case:
            // ---------------------------------
            // - draw 4 sublegs like:  ̄\/ ̄ 
            else {

                // save the current transformation matrix
                // because we are going to "shrink" the matrix now
                c.save();
                
                c.scale(1 / 3, 1 / 3);  // shrink the matrix
                
                // 2nd, 3rd, 4th sublegs
                [0, 60, -120, 60].forEach(angle => {
                    c.rotate(deg(angle)); 
                    leg(n - 1);
                })

                // restore the original transformation matrix
                c.restore();
            }

            // translate coord system to end of leg.
            c.translate(len, 0);
        }
    }

    const side = 125;               // starting side length
    const dx = 25;                  // padding between 2 snowflakes
    const P = vec(dx, side);        // starting point
    const v = vec(side + dx, 0);    // vector for translation
    
    // add snowflake subpaths from level 0 to level 4
    for(let i = 0; i < 5; i++) {
        snowflake(i, ...P.add(v.times(i)).coords, side);
    }

    // draw all snowflakes
    c.fillStyle = 'hsl(120 80% 50% / 0.3)';
    c.fill();
    c.stroke();
});

Last updated