megenginelite-sys 1.8.2

A safe megenginelite wrapper in Rust
Documentation
<html>

<title>Visualizer</title>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
</head>
<script>
    window.onload = () => {
        var board = document.getElementById('board');
        var fileInput = document.getElementById('fileInput');
        var desc = document.getElementById('desc');
        var hRange = document.getElementById('hRange');
        var vRange = document.getElementById('vRange');
        var lastColor = undefined;
        var lastElem = undefined;
        var scale = 1;
        var svg = undefined;
        var svgWidth = undefined;
        var svgHeight = undefined;
        var resetBtn = document.getElementById('resetBtn');
        var relocBtn = document.getElementById('relocBtn');

        var loadDesc = (svgElem) => {
            var mgeType = svgElem.attributes['tag:type'];
            if (mgeType === undefined) {
                return;
            }

            var elemList = [];
            for (attrName of svgElem.getAttributeNames()) {
                var prefix = 'tag:';
                if (!attrName.startsWith(prefix)) {
                    continue;
                }
                var elem = '<p>' + attrName.substr(prefix.length) + ': ' + svgElem.attributes[attrName].value + '</p>'
                elemList.push(elem);
            }
            desc.innerHTML = elemList.join('');
        };

        var selectElem = svgElem => {
            loadDesc(svgElem);
            lastColor = svgElem.attributes['fill'].value;
            lastElem = svgElem;
            svgElem.attributes['fill'].value = 'green';
        };

        var unselectLast = svgElem => {
            if (lastElem) {
                lastElem.attributes['fill'].value = lastColor;
            }
            lastElem = undefined;
            lastColor = undefined;
        };

        var recLoadSVG = svgElem => {
            if (svgElem.children === undefined) {
                return;
            }
            svgElem.onmousedown = e => {
                var mgeType = svgElem.attributes['tag:type'];
                if (mgeType === undefined) {
                    return;
                }

                unselectLast();
                selectElem(svgElem);

                e.stopPropagation();
            };
            for (child of svgElem.children) {
                recLoadSVG(child);
            }
        }
        var scaleBoard = (x, y) => {
            var transform = 'scale(' + x + ',' + y + ')';
            svg.setAttribute('transform', transform);
            board.style['width'] = svgWidth * x;
            board.style['height'] = svgHeight * y;
        }
        var autoScaleBoard = () => {
            var hRangeValue = Math.sqrt(Number(hRange.value) / 10);
            var vRangeValue = Math.sqrt(Number(vRange.value) / 10);
            scaleBoard(Number(hRangeValue), Number(vRangeValue));
        }
        var zoomBoard = dScale => {
            scale *= dScale;
            scaleBoard(scale, scale);
        };

        var reset = () => {
            if (!svgHeight || !svgWidth) {
                return;
            }
            var vScale = window.screen.availHeight / svgHeight;
            var hScale = window.screen.availWidth / svgWidth;
            var minScale = Math.min(hScale, vScale);
            zoomBoard(minScale / scale);
            window.scrollTo({
                top: 0,
                left: 0,
            });
        };

        var loadSVG = () => {
            var file = fileInput.files[0];
            var reader = new FileReader();
            reader.readAsText(file, "UTF-8");
            reader.onload = e => {
                board.innerHTML = '<p style="margin: 0;">' + e.target.result + '</p>';
                svg = board.children[0].children[0];
                svgWidth = svg.attributes['width'].value;
                svgHeight = svg.attributes['height'].value;
                for (child of board.children) {
                    recLoadSVG(child);

                    var svgInfo = child.attributes['svg:info'];
                    if (svgInfo !== undefined) {
                        var elemList = [];
                        for (attrName of child.getAttributeNames()) {
                            var prefix = 'svg:';
                            if (!attrName.startsWith(prefix)) {
                                continue;
                            }
                            var elem = '<p>' + attrName.substr(prefix.length) + ': ' + child.attributes[attrName].value + '</p>'
                            elemList.push(elem);
                        }
                        info.innerHTML = elemList.join('');
                    }
                }
                setTimeout(reset, 1);
            };
        }
        window.addEventListener('wheel', e => {
            if (e.ctrlKey) {
                e.preventDefault();
                e.stopPropagation();
                var factor = 1;
                if (e.deltaY < 0) {
                    factor = 1.1;
                } else if (e.deltaY > 0) {
                    factor = 1 / 1.1;
                }
                zoomBoard(factor);
                var newPageX = e.pageX * factor;
                var newPageY = e.pageY * factor;
                x = newPageX - e.x;
                y = newPageY - e.y;
                window.scrollTo({
                    top: y,
                    left: x,
                });
            } else if (e.altKey) {

            }
        }, { 'passive': false });
        fileInput.onchange = loadSVG;
        resetBtn.onclick = reset;
        relocBtn.onclick = () => {
            if (!lastElem) {
                return;
            }
            y = scale * lastElem.attributes['y'].value;
            x = scale * lastElem.attributes['x'].value;
            window.scrollTo({
                top: y - window.screen.availHeight/2,
                left: x - window.screen.availWidth/2,
                behavior: 'smooth',
            });
        };
    };
</script>

<body>
    <p id="board"
        style="white-space: nowrap; display: flex; justify-content: center; align-content: center; align-items: center; margin: 0; left: 0;">
    </p>
    <div style="display: flex; position: fixed; top: 0; left: 0; right: 0; background-color: white; flex-grow: 2;">
        <input type='file' id='fileInput'></input>
        <div style="flex-grow: 1;"></div>
        <button id='resetBtn'>reset</button>
        <button id='relocBtn'>reloc</button>
    </div>
    <p id="desc" style="position: fixed; bottom: 0; background-color: white;">desc</p>
    <p id="info" style="position: fixed;top: 0; right: 0; background-color: white;">info</p>
</body>

</html>