# Koch snowflake

{% tabs %}
{% tab title="💾 程式" %}
![Koch snowflake (from level 0 \~ 4)](https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2F3xFnXMTNqLVlCUKFduex%2FKoch%20snowflake.png?alt=media\&token=847dcc73-eaa3-4554-9522-c7806a81c405)

<img src="https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2F2AaMtY0q5KOFKOVKS5Fl%2Ffile.drawing.svg?alt=media&#x26;token=ec644f28-a3d8-4a28-a914-cd3b0abe6954" alt="subleg: base case (left), recursive base (right)" class="gitbook-drawing">

:floppy\_disk: replit：[canvas Koch snowflake](https://replit.com/@pegasusroe/canvas-Koch-snowflake#script.js)

⬆️ 需要： [vector](../../../../appendix/custom/class/vector "mention"), [drawoncanvas2d](../../+ext/drawoncanvas2d "mention")

```javascript
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();
});
```
{% endtab %}

{% tab title="📗 參考" %}
* [ ] JavaScript: The Definitive Guide (15.8 Graphics in a \<canvas>)
{% endtab %}

{% tab title="👥 相關" %}
* [recursion](../../../../appendix/algorithms/recursion "mention")
* [fractal](../../examples/fractal "mention")
{% endtab %}
{% endtabs %}
