Search code examples
javascripthtmlhtml5-canvas

Canvas deletes it's self after resizing HTML5/JavaScript


I made canvas that you can draw on it. And it's also responsive to screen size. But if I resize the browser even with one pixel... Canvas clears it's self. Is there any way to prevent this? Fot the heads up, in my code you'll see code that prevents user from scrolling while he/she is on canvas(drawing). You'll also see code for mobile devices(to make possible for mobile users to draw on canvas). But "scroll prevent" isn't working on IOS devices for some reason.

#pen {
    background-color: rgba(0, 0, 0, .2);
}

#paper {
    display: grid;
    column-count: 1;
}

#canvasORG {
    width: 97.5vw;
    height: 90vh;
    cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>✍️</text></svg>") 5 27, auto;
}

#colors {
    padding-top: 5px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: row;
}

#black {
    width: 30px;
    height: 30px;
    background: black;
}

#black:hover {
    background: rgba(0, 0, 0, .1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en">

<head>
    <link rel="shortcut icon" type="image/icon" href="images/IYN_logo.png" />
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <script src="script.js"></script>
</head>

<body>

        <div id="paper">
            <div id="canvasORG">
                <canvas id="canvas" style="background-color: white; border:2px solid;"></canvas>
            </div>
            <div id="colors">
                &emsp;
                <div id="black" onclick="color(this)"></div>&nbsp;
                &emsp;
                <button id="pen" style="height: 50px; font-size: 25px; padding-bottom: 5px;">✍🏻</button>
            </div>
        </div>

        <script>
            const points = [];
            const canvas = document.getElementById("canvas");
            const mouse = { x: 0, y: 0, button: false }
            const ctx = canvas.getContext("2d");
            canvas.addEventListener("mousemove", mouseEvents);
            canvas.addEventListener("mousedown", mouseEvents);
            canvas.addEventListener("mouseup", mouseEvents);
            var x = "black",
                y = 5 * 4;
            const canvasORG = document.getElementById("canvasORG");

            (function () {
                window.addEventListener("resize", resizeCanvas, false);
                canvas.width = canvasORG.clientWidth;
                canvas.height = canvasORG.clientHeight;

                function resizeCanvas() {
                    canvas.width = canvasORG.clientWidth;
                    canvas.height = canvasORG.clientHeight;
                    //DRAW ALL
                    //ctx.fillStyle = 'white';
                    //ctx.fillRect(0, 0, canvas.width, canvas.height)
                }
                resizeCanvas();
            })();

            function mouseEvents(e) {
                mouse.x = e.pageX - 1;
                mouse.y = e.pageY - 1;
                const lb = mouse.button;
                mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
                if (mouse.button) {
                    if (!lb) { points.length = 0 }
                    points.push({ x: mouse.x, y: mouse.y });
                    drawPoints();
                }
            }

            function drawPoints() {
                $(this).scrollTop(0);
                ctx.strokeStyle = x;
                ctx.lineWidth = y;
                ctx.lineCap = "round";
                ctx.lineJoin = "round";
                ctx.beginPath();
                if (mode == "pen") {
                    ctx.globalCompositeOperation = "source-over";
                    for (const p of points) { ctx.lineTo(p.x, p.y); }
                    ctx.stroke();
                } else {
                    ctx.globalCompositeOperation = "destination-out";
                    ctx.arc(mouse.x, mouse.y, 8, 0, Math.PI * 2, false);
                    ctx.stroke();
                    ctx.fill();
                }
            }

            function color(obj) {
                switch (obj.id) {
                    case "black":
                        x = "black";
                        break;
                }
            }

            canvas.addEventListener("touchstart", function (e) {
                mousePos = getTouchPos(canvas, e);
                var touch = e.touches[0];
                var mouseEvent = new MouseEvent("mousedown", {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            }, false);
            canvas.addEventListener("touchend", function (e) {
                var mouseEvent = new MouseEvent("mouseup", {});
                canvas.dispatchEvent(mouseEvent);
            }, false);
            canvas.addEventListener("touchmove", function (e) {
                var touch = e.touches[0];
                var mouseEvent = new MouseEvent("mousemove", {
                    clientX: touch.clientX,
                    clientY: touch.clientY
                });
                canvas.dispatchEvent(mouseEvent);
            }, false);

            // Get the position of a touch relative to the canvas
            function getTouchPos(canvasDom, touchEvent) {
                var rect = canvasDom.getBoundingClientRect();
                return {
                    x: touchEvent.touches[0].clientX - rect.left,
                    y: touchEvent.touches[0].clientY - rect.top
                };
            }

            document.getElementById("canvas").onwheel = function (event) {
                event.preventDefault();
            };

            document.getElementById("canvas").onmousewheel = function (event) {
                event.preventDefault();
            };

            canvas.addEventListener("touchstart", function (event) { event.preventDefault() })
            canvas.addEventListener("touchmove", function (event) { event.preventDefault() })
            canvas.addEventListener("touchend", function (event) { event.preventDefault() })
            canvas.addEventListener("touchcancel", function (event) { event.preventDefault() })

            var mode = "pen";
            $("#pen").click(function () {
                mode = "pen";
            });
            $("#eraser").click(function () {
                mode = "eraser"
            });
        </script>
</body>

</html>


Solution

  • I would change the resize handler to redraw the image after the change:

    const temp = ctx.getImageData(0, 0, canvas.width, canvas.height);
    canvas.width = canvasORG.clientWidth;
    canvas.height = canvasORG.clientHeight;
    ctx.putImageData(temp, 0, 0);
    

    The problem with this is that if the resize is smaller than the drawing, then the portion that is now off the canvas is destroyed.

    #pen {
        background-color: rgba(0, 0, 0, .2);
    }
    
    #paper {
        display: grid;
        column-count: 1;
    }
    
    #canvasORG {
        width: 97.5vw;
        height: 90vh;
        cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>✍️</text></svg>") 5 27, auto;
    }
    
    #colors {
        padding-top: 5px;
        display: flex;
        flex-wrap: wrap;
        flex-direction: row;
    }
    
    #black {
        width: 30px;
        height: 30px;
        background: black;
    }
    
    #black:hover {
        background: rgba(0, 0, 0, .1);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <link rel="shortcut icon" type="image/icon" href="images/IYN_logo.png" />
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="styles.css">
        <script src="script.js"></script>
    </head>
    
    <body>
    
            <div id="paper">
                <div id="canvasORG">
                    <canvas id="canvas" style="background-color: white; border:2px solid;"></canvas>
                </div>
                <div id="colors">
                    &emsp;
                    <div id="black" onclick="color(this)"></div>&nbsp;
                    &emsp;
                    <button id="pen" style="height: 50px; font-size: 25px; padding-bottom: 5px;">✍🏻</button>
                </div>
            </div>
    
            <script>
                const points = [];
                const canvas = document.getElementById("canvas");
                const mouse = { x: 0, y: 0, button: false }
                const ctx = canvas.getContext("2d");
                canvas.addEventListener("mousemove", mouseEvents);
                canvas.addEventListener("mousedown", mouseEvents);
                canvas.addEventListener("mouseup", mouseEvents);
                var x = "black",
                    y = 5 * 4;
                const canvasORG = document.getElementById("canvasORG");
    
                (function () {
                    window.addEventListener("resize", resizeCanvas, false);
                    canvas.width = canvasORG.clientWidth;
                    canvas.height = canvasORG.clientHeight;
    
                    function resizeCanvas() {
                        const temp = ctx.getImageData(0, 0, canvas.width, canvas.height);
                        canvas.width = canvasORG.clientWidth;
                        canvas.height = canvasORG.clientHeight;
                        ctx.putImageData(temp, 0, 0);
                    }
                    resizeCanvas();
                })();
    
                function mouseEvents(e) {
                    mouse.x = e.pageX - 1;
                    mouse.y = e.pageY - 1;
                    const lb = mouse.button;
                    mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
                    if (mouse.button) {
                        if (!lb) { points.length = 0 }
                        points.push({ x: mouse.x, y: mouse.y });
                        drawPoints();
                    }
                }
    
                function drawPoints() {
                    $(this).scrollTop(0);
                    ctx.strokeStyle = x;
                    ctx.lineWidth = y;
                    ctx.lineCap = "round";
                    ctx.lineJoin = "round";
                    ctx.beginPath();
                    if (mode == "pen") {
                        ctx.globalCompositeOperation = "source-over";
                        for (const p of points) { ctx.lineTo(p.x, p.y); }
                        ctx.stroke();
                    } else {
                        ctx.globalCompositeOperation = "destination-out";
                        ctx.arc(mouse.x, mouse.y, 8, 0, Math.PI * 2, false);
                        ctx.stroke();
                        ctx.fill();
                    }
                }
    
                function color(obj) {
                    switch (obj.id) {
                        case "black":
                            x = "black";
                            break;
                    }
                }
    
                canvas.addEventListener("touchstart", function (e) {
                    mousePos = getTouchPos(canvas, e);
                    var touch = e.touches[0];
                    var mouseEvent = new MouseEvent("mousedown", {
                        clientX: touch.clientX,
                        clientY: touch.clientY
                    });
                    canvas.dispatchEvent(mouseEvent);
                }, false);
                canvas.addEventListener("touchend", function (e) {
                    var mouseEvent = new MouseEvent("mouseup", {});
                    canvas.dispatchEvent(mouseEvent);
                }, false);
                canvas.addEventListener("touchmove", function (e) {
                    var touch = e.touches[0];
                    var mouseEvent = new MouseEvent("mousemove", {
                        clientX: touch.clientX,
                        clientY: touch.clientY
                    });
                    canvas.dispatchEvent(mouseEvent);
                }, false);
    
                // Get the position of a touch relative to the canvas
                function getTouchPos(canvasDom, touchEvent) {
                    var rect = canvasDom.getBoundingClientRect();
                    return {
                        x: touchEvent.touches[0].clientX - rect.left,
                        y: touchEvent.touches[0].clientY - rect.top
                    };
                }
    
                document.getElementById("canvas").onwheel = function (event) {
                    event.preventDefault();
                };
    
                document.getElementById("canvas").onmousewheel = function (event) {
                    event.preventDefault();
                };
    
                canvas.addEventListener("touchstart", function (event) { event.preventDefault() })
                canvas.addEventListener("touchmove", function (event) { event.preventDefault() })
                canvas.addEventListener("touchend", function (event) { event.preventDefault() })
                canvas.addEventListener("touchcancel", function (event) { event.preventDefault() })
    
                var mode = "pen";
                $("#pen").click(function () {
                    mode = "pen";
                });
                $("#eraser").click(function () {
                    mode = "eraser"
                });
            </script>
    </body>
    
    </html>