<!doctype html>
<html>
    <head>
        <title>8seg dimension planning</title>
<style>
canvas {
}

body {
    margin-left: auto;
    margin-right: auto;
    width: min-content;
}

#form {
    max-width: 1000px;
    margin-left: auto;
    margin-right: auto;
    display: grid;
    grid-template-columns: max-content auto;
}

#form > label {
    text-align: right;
    padding-right: 0.5em;
}

#form > input[type="number"] {
    max-width: 5em;
}

#form > input {
    justify-self: start;
}

</style>
    </head>
    <body>
        <canvas id="viz" width="1800px" height="500px">
        </canvas>
        <div id="form">
            <label for="text">Text</label><input type="text" id="text" value="Sphinx of black quartz/judge my vow"/>
            <label for="digit_width">Digit width</label><input type="number" id="digit_width" step="0.01" value="1.0">
            <label for="digit_height">Digit height</label><input type="number" id="digit_height" step="0.01" value="1.6">
            <label for="digit_space">Digit spacing</label><input type="number" id="digit_space" step="0.01" value="0.4">
            <label for="digit_num">Number of digits</label><input type="number" id="digit_num" value="36">
            <label for="leds_per_m">LEDs per meter</label><input type="number" id="leds_per_m" value="10">
            <label for="individual_leds">Render individual LEDs</label><input type="checkbox" id="individual_leds">
            <label for="line_width">Visualization line width</label><input type="number" id="line_width", value=0.05>
        </div>
<script>

    const seg_map = {
        " ": 0x00,
        "a": 0x2e,
        "b": 0xd6,
        "c": 0xd0,
        "d": 0xc5,
        "e": 0x59,
        "f": 0x98,
        "g": 0xd4,
        "h": 0x8c,
        "i": 0x5c,
        "j": 0x78,
        "k": 0x8e,
        "l": 0xc0,
        "m": 0xa3,
        "n": 0xa5,
        "o": 0xf0,
        "p": 0x93,
        "q": 0xf4,
        "r": 0x9e,
        "s": 0x55,
        "t": 0xc8,
        "u": 0xe0,
        "v": 0x8a,
        "w": 0xac,
        "x": 0x0f,
        "y": 0x0b,
        "z": 0x5a,
        "0": 0x13,
        "1": 0x20,
        "2": 0x16,
        "3": 0x56,
        "4": 0x23,
        "5": 0x1c,
        "6": 0x4e,
        "7": 0x1a,
        "8": 0x5f,
        "9": 0x33,
        "/": 0x0a,
        "\\": 0x05,
    };

    function map_digit(codepoint) {
        if (!seg_map.hasOwnProperty(codepoint)) {
            return seg_map[" "];
        }

        return seg_map[codepoint];
    }

    function do_line(ctx, x1, y1, x2, y2, scale) {
        if (document.querySelector("#individual_leds").checked) {
            const leds_per_m = parseFloat(document.querySelector("#leds_per_m").value);
            const dist = Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
            const num_leds = dist * leds_per_m;
            const d_off = (num_leds % 1.0) / 2;
            for (var i=0; i<num_leds; i++) {
                const frac_d = ((d_off + i)/leds_per_m);
                const x = x1*scale + (x2-x1)*scale*frac_d/dist;
                const y = y1*scale + (y2-y1)*scale*frac_d/dist;
                ctx.moveTo(x-0.5, y-0.5);
                ctx.lineTo(x+0.5, y+0.5);
            }
        } else {
            ctx.moveTo(x1*scale, y1*scale);
            ctx.lineTo(x2*scale, y2*scale);
        }
    }

    function draw_digit(ctx, x, y, w, h, seg, scale) {
        for (var i=0; i<2; i++) {
            if (i == 0) {
                ctx.strokeStyle = '#e00000';
            } else {
                ctx.strokeStyle = '#404040';
                seg = ~seg;
            }
            ctx.beginPath();
            if (seg & 0x80) {
                do_line(ctx, x, y, x, y+h, scale);
            }
            if (seg & 0x40) {
                do_line(ctx, x, y+h, x+w, y+h, scale);
            }
            if (seg & 0x20) {
                do_line(ctx, x+w, y+h, x+w, y, scale);
            }
            if (seg & 0x10) {
                do_line(ctx, x+w, y, x, y, scale);
            }
            if (seg & 0x01) {
                do_line(ctx, x+w/2, y+h/2, x, y, scale);
            }
            if (seg & 0x02) {
                do_line(ctx, x+w/2, y+h/2, x+w, y, scale);
            }
            if (seg & 0x08) {
                do_line(ctx, x+w/2, y+h/2, x, y+h, scale);
            }
            if (seg & 0x04) {
                do_line(ctx, x+w/2, y+h/2, x+w, y+h, scale);
            }
            ctx.stroke();
        }
    }

    function update() {
        const canvas = document.querySelector("#viz");
        const ctx = canvas.getContext("2d");
        ctx.fillStyle = '#202020';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        const digit_num = parseFloat(document.querySelector("#digit_num").value);
        const digit_width = parseFloat(document.querySelector("#digit_width").value);
        const digit_height = parseFloat(document.querySelector("#digit_height").value);
        const digit_space = parseFloat(document.querySelector("#digit_space").value);
        const line_width = parseFloat(document.querySelector("#line_width").value);
        const text = document.querySelector("#text").value.toLowerCase();

        const segs = [];
        for (var codepoint of text) {
            segs.push(map_digit(codepoint));
        }

        for (var i=0; i<digit_num; i++) {
            segs.push(map_digit(" "));
        }

        const total_w = digit_num * digit_width + (digit_num - 1) * digit_space;
        const total_h = digit_height;

        const fill_factor = 0.8;
        const scale = canvas.width * fill_factor / total_w;

        var x = (canvas.width/scale - total_w) / 2;
        var y = (canvas.height/scale - total_h) / 2;

        ctx.lineWidth = scale*line_width*digit_width;

        for (var i=0; i<digit_num; i++) {
            draw_digit(ctx, x, y, digit_width, digit_height, segs[i], scale);
            x += digit_width + digit_space;
        }
    }

    function handle_change(evt) {
        update();
    }

    document.querySelector("#digit_width").addEventListener('change', handle_change);
    document.querySelector("#digit_height").addEventListener('change', handle_change);
    document.querySelector("#digit_space").addEventListener('change', handle_change);
    document.querySelector("#digit_num").addEventListener('change', handle_change);
    document.querySelector("#line_width").addEventListener('change', handle_change);
    document.querySelector("#leds_per_m").addEventListener('change', handle_change);
    document.querySelector("#individual_leds").addEventListener('change', handle_change);
    document.querySelector("#text").addEventListener('input', handle_change);

    update();
</script>
    </body>
</html>