Skip to content
Snippets Groups Projects
index.html 17.1 KiB
Newer Older
Andreas Horn's avatar
Andreas Horn committed
<!DOCTYPE html>
<html>

<head>
    <style type="text/css">
        * {
            touch-action: none;
        }

        body {
            background-color: red;
        }

        button {
            background-color: #D8D8D8;
            border: 1px solid #999999;
            border-radius: 5px;
        }

        button.selected {
            box-shadow: 0 0 2px 2px #0597f8;
        }

Andreas Horn's avatar
Andreas Horn committed
        #board {
            touch-action: none;
            box-shadow: 1px 1px 1px 0.5px rgba(0, 0, 0, 0.1);
            cursor: crosshair;
            position: absolute;
            left: 0px;
Andreas Horn's avatar
Andreas Horn committed
        }
            background-color: #ddddee;
            opacity: 0.75;
            width: 770px;
            height: 150px;
            border-radius: 8px;
            box-shadow: 0.5px 0.5px 2px #555555, inset 0px 0px 1px #555555;
            position: absolute;
            z-index: 20;
            touch-action: none;
        #ruler::before {
            position:absolute;
            background-color: #ffffff;
            background: 
            repeating-linear-gradient(180deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 43px, #777777 46px),
            repeating-linear-gradient(90deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 751px, #ffffff 751px, #ffffff 769px),
            repeating-linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 30px, #ffffff 30px, #ffffff 50px),
            repeating-linear-gradient(90deg, #222222, #222222 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 50px),
            repeating-linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 10px, #ffffff 10px, #ffffff 50px),
            repeating-linear-gradient(90deg, #222222, #222222 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 5px);
            background-position-x: 10px;
            opacity: 50%;
            width: 100%;
            height: 45px;
            content: "";
        }

        #ruler::after {
            position:absolute;
            background-color: #ffffff;
            opacity: 20%;
            width: 100%;
            height: 10px;
            bottom: 0px;
            border-top: 1px solid #555555;
            filter: blur(1px);
            content: "";
        }

        #ruler #rulerTopLeft {
            position: relative;
            top: 0px;
            left: 0px;
            width: 0px;
            height: 0px;
            background-color: blue;
        }

        #menuTop {
            position: absolute;
            top: 0px;
            left: 0px;
            margin-left: 30px;
        }

        #sidePanelLeft {
            position: absolute;
            width: 30%;
            height: 100%;
            top: 0px;
            left: -30%;
            background-color: #fafafa;
            box-shadow: #999 0px 0px 12px;
            padding: 20px;
            box-sizing: border-box;
        }

        #sidePanelLeft::after {
            content: "Notes";
            position: absolute;
            right: -25px;
            width: 25px;
            padding: 20px 0px;
            font-family: sans-serif;
            font-size: 20px;
            top: 0px;
            background-color: #fafafa;
            writing-mode: vertical-rl;
            text-orientation: mixed;
            box-shadow: #999 0px 0px 12px;
            border-top-left-radius: 10px;
            transform: rotate(180deg);
        }

        #sidePanelShadowHider {
            position: absolute;
            width: 12px;
            height: 100%;
            right: 0px;
            top: 0px;
            background-color: #fafafa;
            pointer-events: none;
            z-index: 2;
        }

        #sidePanelLeft button {
            padding: 20px;
            margin-bottom: 20px;
            min-width: 150px;
        }


/* ruler DOM object top/left */
#helper, #helper1, #helper2, #helper3, #helper4 {
    background-color: fuchsia;
    width: 10px;
    height: 10px;
    position: absolute;
    z-index: 21;
    touch-action: none;
    left: 200px;
    top: 200px;
}

#helper1, #helper2 {
    width: 150px;
    height: 150px;
    border-radius: 75px;
    opacity: 0.8;
}

/* first touch pointer */
#helper1 {
    background-color: yellow;
}

/* second touch pointer */
#helper2{
    background-color: orange;
}

/* transform origin */
#helper3{
    background-color: lime;
    border-radius: 5px;
}

/* ruler "top/left" */
#helper4{
    background-color: red;
    border-radius: 5px;
}

Andreas Horn's avatar
Andreas Horn committed
    </style>

    <script type="application/javascript" src="js/lib.js"></script>
    <script type="application/javascript" src="js/Vector.js"></script>
Andreas Horn's avatar
Andreas Horn committed
    <script type="application/javascript" src="js/main.js"></script>
    <script type="application/javascript" src="js/Board.js"></script>
    <script type="application/javascript" src="js/Pen.js"></script>
    <script type="application/javascript" src="js/PointerManager.js"></script>
    <script type="application/javascript" src="js/Ruler.js"></script>
Andreas Horn's avatar
Andreas Horn committed

    <script type="application/javascript">
        let redrawAllTimeout;
Andreas Horn's avatar
Andreas Horn committed
        function init() {
            Board.init("board");
            Ruler.init(document.getElementById("ruler"));
Andreas Horn's avatar
Andreas Horn committed

            setColor("#000000");
            setLineWidth("8");

Andreas Horn's avatar
Andreas Horn committed
            // Attach event listener
            var pointerDown = function (e) {
                //console.log("down");
                clearTimeout(redrawAllTimeout);
                    if (!Pen.erase) {
                        // start new free hand stroke
                        Board.strokeData.push([]);
                        // check if we must follow the ruler
                        Board.collectStrokeInfo(e, Pen);
                    } else {

                    }
                    gestureStartPoint[e.pointerId] = e;
Andreas Horn's avatar
Andreas Horn committed
                }
            }

            var pointerMove = function (e) {
                if (e.pointerType == "pen") {
                    if (!Pen.erase) {
                        Board.collectStrokeInfo(e, Pen);
                    } else {
                        Board.eraseLine(e, Pen);
                    }
                } else if (e.pointerType == "touch") {
                    detectGesture(e);
Andreas Horn's avatar
Andreas Horn committed
                }
            }
            var pointerCancel = function (e) {
                //console.log("cancel");

                if (e.pointerType == "pen") {
                    if (!Pen.erase) {
                        Board.drawLastCurve();
                        clearTimeout(redrawAllTimeout);
                        redrawAllTimeout = setTimeout(_ => Board.redrawAll(), 1000);
                    }
                } else if (e.pointerType == "touch") {
                    if (gestureStartPoint[e.pointerId]) {
                        delete gestureStartPoint[e.pointerId];
                    }
                PointerManager.unregisterPointer(e);
Andreas Horn's avatar
Andreas Horn committed
            }
            var pointerSwipeInFromLeft = function (e) {
                var swipeDistance = Math.abs(e.detail.x - e.detail.startX);
                
                var width = sidePanelLeft.offsetWidth;

                var offsetX = e.detail.x;
                var offsetXSidePanel = -width + offsetX;
                                
                if (offsetXSidePanel >= 0 || swipeDistance > 100) {
                }
                
                sidePanelLeft.style.transition = "";
                sidePanelLeft.style.left = offsetXSidePanel + "px";
                document.getElementById("menuTop").style.transition = "";
                document.getElementById("menuTop").style.left = offsetX + "px";
            }

            var pointerSwipeOutToLeft = function (e) {
            }

            var pointerSwipeLeft = function (e) {
                if (e.detail.target == sidePanelLeft) {
                    var swipeDistance = Math.abs(e.detail.x - e.detail.startX);
                    if (swipeDistance > 100) {   
            var hideSidePanelLeft = function () {
                sidePanelLeft.style.transition = "left 0.5s";
                sidePanelLeft.style.left = -sidePanelLeft.offsetWidth + "px";
                document.getElementById("menuTop").style.transition = "left 0.5s";
                document.getElementById("menuTop").style.left = "0px";
                sidePanelLeft.dataset.visible = false;
            }

            var showSidePanelLeft = function () {
                sidePanelLeft.style.transition = "";
                sidePanelLeft.style.left = "0px";
                document.getElementById("menuTop").style.transition = "";
                document.getElementById("menuTop").style.left = sidePanelLeft.offsetWidth + "px";
                sidePanelLeft.dataset.visible = true;
            }

            var sidePanelLeftOnClick = function () {
                if (sidePanelLeft.dataset.visible == "false") {
                    showSidePanelLeft();
                }
            }

            Board.canvas.addEventListener("pointerdown", pointerDown);
            Board.canvas.addEventListener("pointermove", pointerMove);
            Board.canvas.addEventListener("pointerup", pointerCancel);
            Board.canvas.addEventListener("pointerleave", pointerCancel);
Andreas Horn's avatar
Andreas Horn committed

            sidePanelLeft = document.getElementById("sidePanelLeft");
            noteList = document.getElementById("noteList");

            updateNoteList();

            sidePanelLeft.addEventListener("pointerdown", pointerDown);
            sidePanelLeft.addEventListener("pointermove", pointerMove);
            sidePanelLeft.addEventListener("pointerup", pointerCancel);
            sidePanelLeft.addEventListener("pointerleave", pointerCancel);
            sidePanelLeft.addEventListener("pointerdown", sidePanelLeftOnClick);


            document.addEventListener("swipeInFromLeft", pointerSwipeInFromLeft);
            document.addEventListener("swipeOutToLeft", pointerSwipeOutToLeft);
            document.addEventListener("swipeLeft", pointerSwipeLeft);

            setInterval(_ => Board.drawLastCurve(), 30);
Andreas Horn's avatar
Andreas Horn committed

        function updateNoteList() {
            noteList.innerHTML = "";
            for (var key of Object.keys(localStorage)) {
                if (key.startsWith("strokeData/")) {
                    var noteName = key.replace(/^strokeData\//, "");
                    var btn = newElement("button", {}, noteName);
                    ((noteName) => btn.addEventListener("click", _ => Board.load(noteName)))(noteName);
                    noteList.appendChild(btn);
                    noteList.appendChild(newElement("br"));
                }
            }
        }

        var sidePanelLeft;
        var noteList;

        var gestureStartPoint = [];

        function detectGesture(ev) {
            if (gestureStartPoint[ev.pointerId]) {
                var gsp = gestureStartPoint[ev.pointerId];
                
                if (gsp.started == "swipeInFromLeft" || (gsp.clientX < ev.clientX && gsp.clientX < 10)) {
                    gsp.started = "swipeInFromLeft";

                    var swipeInFromLeft = new CustomEvent("swipeInFromLeft", {
                        detail: {
                            target: ev.target,
                            pointerId: ev.pointerId,
                            startX: gsp.clientX,
                            startY: gsp.clientY,
                            x: ev.clientX,
                            y: ev.clientY
                        }
                    });

                    document.dispatchEvent(swipeInFromLeft);
                }

                if (gsp.clientX > ev.clientX && ev.clientX < 10) {
                    var swipeOutToLeft = new CustomEvent("swipeOutToLeft", {
                        detail: {
                            target: ev.target,
                            pointerId: ev.pointerId,
                            startX: gsp.clientX,
                            startY: gsp.clientY,
                            x: ev.clientX,
                            y: ev.clientY
                        }
                    });

                    document.dispatchEvent(swipeOutToLeft);
                }

                if (gsp.clientX > ev.clientX) {
                    var swipeLeft = new CustomEvent("swipeLeft", {
                        detail: {
                            target: ev.target,
                            pointerId: ev.pointerId,
                            startX: gsp.clientX,
                            startY: gsp.clientY,
                            x: ev.clientX,
                            y: ev.clientY
                        }
                    });

                    document.dispatchEvent(swipeLeft);
                }
            }
        }

        // sets the color when a color button was pressed
        function setColor(btn) {
            Pen.colors.fg = (btn.dataset) ? btn.dataset.color : btn;
            Pen.erase = Pen.colors.fg.startsWith("erase");
            document.querySelectorAll("button[data-color]").forEach(b => b.classList.remove("selected"));
            document.querySelector("button[data-color='" + Pen.colors.fg + "']").classList.add("selected");
        }

        // sets the line with when a line with button was pressed
        function setLineWidth(btn) {
            Pen.lineWidth = (btn.dataset) ? btn.dataset.lineWidth : btn;
            document.querySelectorAll("button[data-line-width]").forEach(b => b.classList.remove("selected"));
            document.querySelector("button[data-line-width='" + Pen.lineWidth + "']").classList.add("selected");
        }
        function toggleRuler(btn) {
            if (Ruler.visible) {
                Ruler.hide();
                btn.classList.remove("selected");
            } else {
                Ruler.show();
                btn.classList.add("selected");
            }
        }

        function btnLoad() {
            var noteName = prompt("Please enter the name of the note to load:");

            if (noteName != "") {
                Board.load(noteName);
            } else {
                alert("Could not find note, loading the lastest saved note!");
                Board.load(Board.latestNote);
            }
        }
Andreas Horn's avatar
Andreas Horn committed
    </script>
</head>

<body onload="init();">
    <canvas touch-action="none" id="board" width="640" height="640" style="width:320px; height:320px;">
        Opps, you cannot play draw N guess with this browser!
    </canvas>
    <div id="menuTop">
        <button style="position:absolute; top:20px; left: 20px; width: 80px; height: 35px;" onclick="Board.save();">save</button>
        <button style="position:absolute; top:65px; left: 20px; width: 80px; height: 35px;" onclick="btnLoad();">load</button>
        <button style="position:absolute; top:20px; left: 120px; width: 80px; height: 80px;" onclick="Board.clear();">clear</button>
        
        <button data-color="#000000" style="position:absolute; top:20px; left: 220px; width: 35px; height: 35px; background-color: black; color: white" onclick="setColor(this);"> </button>
        <button data-color="#FF0000" style="position:absolute; top:20px; left: 265px; width: 35px; height: 35px; background-color: red;" onclick="setColor(this);"> </button>
        <button data-color="#4169E1" style="position:absolute; top:65px; left: 220px; width: 35px; height: 35px; background-color: royalblue;" onclick="setColor(this);"> </button>
        <button data-color="#32CD32" style="position:absolute; top:65px; left: 265px; width: 35px; height: 35px; background-color: limegreen;" onclick="setColor(this);"> </button>

        <button data-color="eraseLine" style="position:absolute; top:20px; left: 320px; width: 80px; height: 35px;" onclick="setColor(this);">erase line</button>
        <button data-color="erase" style="position:absolute; top:65px; left: 320px; width: 80px; height: 35px;" onclick="setColor(this);">erase</button>

        <button data-line-width="4" style="position:absolute; top:20px; left: 420px; width: 35px; height: 35px;" onclick="setLineWidth(this);">4</button>
        <button data-line-width="8" style="position:absolute; top:20px; left: 465px; width: 35px; height: 35px;" onclick="setLineWidth(this);">8</button>
        <button data-line-width="16" style="position:absolute; top:65px; left: 420px; width: 35px; height: 35px;" onclick="setLineWidth(this);">16</button>
        <button data-line-width="24" style="position:absolute; top:65px; left: 465px; width: 35px; height: 35px;" onclick="setLineWidth(this);">24</button>
    
        <button style="position:absolute; top:20px; left: 520px; width: 80px; height: 35px;" onclick="toggleRuler(this);">Ruler</button>
    </div>
    <div id="ruler">
        <div id="rulerTopLeft">top left</div>
        <div id="rulerValues"></div>
    </div>
        <div id="sidePanelShadowHider"></div>
        Notes: <br>
        <br>
        <div id="noteList">

        </div>
    </div>

    <div id="helper"></div>
    <div id="helper1"></div>
    <div id="helper2"></div>
    <div id="helper3"></div>
    <div id="helper4"></div>
Andreas Horn's avatar
Andreas Horn committed
</body>

</html>