-2

I am trying to implement a paint bucket tool with undo and redo functionality. The issue is that undo and redo are working properly the first time, but when I do undo redo multiple times, the code fails. Can anyone help me figure the issue out? This is my complete code. You can just copy paste and it will work at your end.

<!DOCTYPE html>
<html>
    <head>
        <title>Painitng</title>
        <style>
            body {
                width: 100%;
                height: auto;
                text-align: center;
            }
            .colorpick {
                widh: 100%;
                height: atuo;
            }
            .pick {
                display: inline-block;
                width: 30px;
                height: 30px;
                margin: 5px;
                cursor: pointer;
            }
            canvas {
                border: 2px solid silver;
            }
        </style>
    </head>
    <body>
        <button id="zoomin">Zoom In</button>
        <button id="zoomout">Zoom Out</button>
        <button onclick="undo()">Undo</button>
        <button onclick="redo()">Redo</button>
        <div id="canvasDiv"></div>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script> 
        <script type="text/javascript">
            var colorYellow = {
                r: 255,
                g: 207,
                b: 51
            };
            var context;
            var canvasWidth = 500;
            var canvasHeight = 500;
            var myColor = colorYellow;
            var curColor = myColor;
            var outlineImage = new Image();
            var backgroundImage = new Image();
            var drawingAreaX = 0;
            var drawingAreaY = 0;
            var drawingAreaWidth = 500;
            var drawingAreaHeight = 500;
            var colorLayerData;
            var outlineLayerData;
            var totalLoadResources = 2;
            var curLoadResNum = 0;
            var undoarr = new Array();
            var redoarr = new Array();
            var uc = 0;
            var rc = 0;

            // Clears the canvas.
            function clearCanvas() {
                context.clearRect(0, 0, context.canvas.width, context.canvas.height);
            }

            function undo() {
                if (undoarr.length <= 0)
                    return;

                if (uc==0) {
                    redoarr.push(undoarr.pop());
                    uc = 1;
                }
                var a = undoarr.pop();
                colorLayerData = a;
                redoarr.push(a);
                clearCanvas();
                context.putImageData(a, 0, 0);
                context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
                context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
                console.log(undoarr);
            }

            function redo() {
                if (redoarr.length <= 0)
                    return;
                if (rc==0) {
                    undoarr.push(redoarr.pop());
                    rc = 1;
                }
                var a = redoarr.pop();
                colorLayerData = a;
                undoarr.push(a);
                clearCanvas();
                context.putImageData(a, 0, 0);
                context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
                context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
                console.log(redoarr);
            }
            // Draw the elements on the canvas
            function redraw() {
                uc = 0;
                rc = 0;
                var locX,
                        locY;

                // Make sure required resources are loaded before redrawing
                if (curLoadResNum < totalLoadResources) {
                    return; // To check if images are loaded successfully or not.
                }

                clearCanvas();
                // Draw the current state of the color layer to the canvas
                context.putImageData(colorLayerData, 0, 0);

                undoarr.push(context.getImageData(0, 0, canvasWidth, canvasHeight));
                console.log(undoarr);
                redoarr = new Array();
                // Draw the background
                context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);

                // Draw the outline image on top of everything. We could move this to a separate 
                //   canvas so we did not have to redraw this everyime.
                context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);


            }
            ;

            function matchOutlineColor(r, g, b, a) {

                return (r + g + b < 100 && a === 255);
            }
            ;

            function matchStartColor(pixelPos, startR, startG, startB) {

                var r = outlineLayerData.data[pixelPos],
                        g = outlineLayerData.data[pixelPos + 1],
                        b = outlineLayerData.data[pixelPos + 2],
                        a = outlineLayerData.data[pixelPos + 3];

                // If current pixel of the outline image is black
                if (matchOutlineColor(r, g, b, a)) {
                    return false;
                }

                r = colorLayerData.data[pixelPos];
                g = colorLayerData.data[pixelPos + 1];
                b = colorLayerData.data[pixelPos + 2];

                // If the current pixel matches the clicked color
                if (r === startR && g === startG && b === startB) {
                    return true;
                }

                // If current pixel matches the new color
                if (r === curColor.r && g === curColor.g && b === curColor.b) {
                    return false;
                }

                return true;
            }
            ;

            function colorPixel(pixelPos, r, g, b, a) {
                colorLayerData.data[pixelPos] = r;
                colorLayerData.data[pixelPos + 1] = g;
                colorLayerData.data[pixelPos + 2] = b;
                colorLayerData.data[pixelPos + 3] = a !== undefined ? a : 255;
            }
            ;

            function floodFill(startX, startY, startR, startG, startB) {
                var newPos,
                        x,
                        y,
                        pixelPos,
                        reachLeft,
                        reachRight,
                        drawingBoundLeft = drawingAreaX,
                        drawingBoundTop = drawingAreaY,
                        drawingBoundRight = drawingAreaX + drawingAreaWidth - 1,
                        drawingBoundBottom = drawingAreaY + drawingAreaHeight - 1,
                        pixelStack = [[startX, startY]];

                while (pixelStack.length) {

                    newPos = pixelStack.pop();
                    x = newPos[0];
                    y = newPos[1];

                    // Get current pixel position
                    pixelPos = (y * canvasWidth + x) * 4;

                    // Go up as long as the color matches and are inside the canvas
                    while (y >= drawingBoundTop && matchStartColor(pixelPos, startR, startG, startB)) {
                        y -= 1;
                        pixelPos -= canvasWidth * 4;
                    }

                    pixelPos += canvasWidth * 4;
                    y += 1;
                    reachLeft = false;
                    reachRight = false;

                    // Go down as long as the color matches and in inside the canvas
                    while (y <= drawingBoundBottom && matchStartColor(pixelPos, startR, startG, startB)) {
                        y += 1;

                        colorPixel(pixelPos, curColor.r, curColor.g, curColor.b);

                        if (x > drawingBoundLeft) {
                            if (matchStartColor(pixelPos - 4, startR, startG, startB)) {
                                if (!reachLeft) {
                                    // Add pixel to stack
                                    pixelStack.push([x - 1, y]);
                                    reachLeft = true;
                                }

                            } else if (reachLeft) {
                                reachLeft = false;
                            }
                        }

                        if (x < drawingBoundRight) {
                            if (matchStartColor(pixelPos + 4, startR, startG, startB)) {
                                if (!reachRight) {
                                    // Add pixel to stack
                                    pixelStack.push([x + 1, y]);
                                    reachRight = true;
                                }
                            } else if (reachRight) {
                                reachRight = false;
                            }
                        }

                        pixelPos += canvasWidth * 4;
                    }
                }
            }
            ;

            // Start painting with paint bucket tool starting from pixel specified by startX and startY
            function paintAt(startX, startY) {

                var pixelPos = (startY * canvasWidth + startX) * 4,
                        r = colorLayerData.data[pixelPos],
                        g = colorLayerData.data[pixelPos + 1],
                        b = colorLayerData.data[pixelPos + 2],
                        a = colorLayerData.data[pixelPos + 3];

                if (r === curColor.r && g === curColor.g && b === curColor.b) {
                    // Return because trying to fill with the same color
                    return;
                }

                if (matchOutlineColor(r, g, b, a)) {
                    // Return because clicked outline
                    return;
                }

                floodFill(startX, startY, r, g, b);

                redraw();
            }
            ;

            // Add mouse event listeners to the canvas
            function createMouseEvents() {

                $('#canvas').mousedown(function (e) {
                    // Mouse down location
                    var mouseX = e.pageX - this.offsetLeft,
                            mouseY = e.pageY - this.offsetTop;

                    if ((mouseY > drawingAreaY && mouseY < drawingAreaY + drawingAreaHeight) && (mouseX <= drawingAreaX + drawingAreaWidth)) {
                        paintAt(mouseX, mouseY);
                    }
                });
            }
            ;

            resourceLoaded = function () {

                curLoadResNum += 1;
                //if (curLoadResNum === totalLoadResources) {
                createMouseEvents();
                redraw();
                //}
            };

            function start() {

                var canvas = document.createElement('canvas');
                canvas.setAttribute('width', canvasWidth);
                canvas.setAttribute('height', canvasHeight);
                canvas.setAttribute('id', 'canvas');
                document.getElementById('canvasDiv').appendChild(canvas);

                if (typeof G_vmlCanvasManager !== "undefined") {
                    canvas = G_vmlCanvasManager.initElement(canvas);
                }
                context = canvas.getContext("2d");
                backgroundImage.onload = resourceLoaded();
                backgroundImage.src = "images/t1.png";

                outlineImage.onload = function () {
                    context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);

                    try {
                        outlineLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
                    } catch (ex) {
                        window.alert("Application cannot be run locally. Please run on a server.");
                        return;
                    }
                    clearCanvas();
                    colorLayerData = context.getImageData(0, 0, canvasWidth, canvasHeight);
                    resourceLoaded();
                };
                outlineImage.src = "images/d.png";
            }
            ;

            getColor = function () {

            };

        </script> 
        <script type="text/javascript"> $(document).ready(function () {
                start();
            });</script> 
        <script language="javascript">
            $('#zoomin').click(function () {
                if ($("#canvas").width()==500){
                $("#canvas").width(750);
                $("#canvas").height(750);
                var ctx = canvas.getContext("2d");
                ctx.drawImage(backgroundImage, 0, 0, 749, 749);
                ctx.drawImage(outlineImage, 0, 0, 749, 749);
                redraw();
                 } else if ($("#canvas").width()==750){

                $("#canvas").width(1000);
                $("#canvas").height(1000);
                var ctx = canvas.getContext("2d");
                ctx.drawImage(backgroundImage, 0, 0, 999, 999);
                ctx.drawImage(outlineImage, 0, 0, 999, 999);
                redraw();
                 }
            });
            $('#zoomout').click(function () {
                if ($("#canvas").width() == 1000) {

                $("#canvas").width(750);
                $("#canvas").height(750);
                var ctx = canvas.getContext("2d");
                ctx.drawImage(backgroundImage, 0, 0, 749, 749);
                ctx.drawImage(outlineImage, 0, 0, 749, 749);
                redraw();
                } else if ($("#canvas").width() == 750) {

                $("#canvas").width(500);
                $("#canvas").height(500);
                var ctx = canvas.getContext("2d");
                ctx.drawImage(backgroundImage, 0, 0, 499, 499);
                ctx.drawImage(outlineImage, 0, 0, 499, 499);
                redraw();
                }
            });
        </script>
        <div class="colorpick">
            <div class="pick" style="background-color:rgb(150, 0, 0);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(0, 0, 152);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(0, 151, 0);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(255, 0, 5);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(255, 255, 0);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(0, 255, 255);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(255, 0, 255);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(255, 150, 0);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(255, 0, 150);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(0, 255, 150);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(150, 0, 255);" onclick="hello(this.style.backgroundColor);"></div>
            <div class="pick" style="background-color:rgb(0, 150, 255);" onclick="hello(this.style.backgroundColor);"></div>
        </div>
        <script>
            function hello(e) {
                var rgb = e.replace(/^(rgb|rgba)\(/, '').replace(/\)$/, '').replace(/\s/g, '').split(',');
                myColor.r = parseInt(rgb[0]);
                myColor.g = parseInt(rgb[1]);
                myColor.b = parseInt(rgb[2]);
                curColor = myColor;
                console.log(curColor);
            }
        </script>
    </body>
</html>
Ali Zia
  • 3,825
  • 5
  • 29
  • 77
  • The two zoom in and zoom out functionality is not working! – nisar Apr 26 '16 at 07:00
  • The link in your question points to an advertisement. :-(( Please add a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) of the code that is misbehaving AND include a better description of how the code is misbehaving and how you would prefer it to work. "...not working properly" and "...messed up" are not adequate descriptions. – markE Apr 26 '16 at 16:30

1 Answers1

0

I couldn't find a meaning for adding if (rc==0) and if (uc==0) parts in your code. If you remove them your code works fine.

function undo()
{
    if (undoarr.length<=0)
        return;

    var a=undoarr.pop();
    colorLayerData=a;
    redoarr.push(a);
    clearCanvas();
    context.putImageData(a, 0, 0);
    context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
    context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
    console.log(undoarr);
}

function redo()
{
    if (redoarr.length<=0)
        return;
    var a=redoarr.pop();
    colorLayerData=a;
    undoarr.push(a);
    clearCanvas();
    context.putImageData(a, 0, 0);
    context.drawImage(backgroundImage, 0, 0, canvasWidth, canvasHeight);
    context.drawImage(outlineImage, 0, 0, drawingAreaWidth, drawingAreaHeight);
    console.log(redoarr);
}
Gokhan Kurt
  • 8,239
  • 1
  • 27
  • 51
  • If I remove these, the undo and redo are working when I click second time. Copy paste the code. You will see what I mean. – Ali Zia Apr 28 '16 at 10:54
  • I tried your code. I am sure it works properly if you remove these. Besides, even if hadn't tested it, there is no way it wouldn't work if you remove these if blocks. Maybe you have an error somewhere else and you think undo and redo are causing the error. Try to narrow down the suspicious code. – Gokhan Kurt Apr 28 '16 at 11:00
  • I tried it. The error is just in the undo and redo function. You can check it yourself. If you do undo and redo multiple times, they wont be proper. – Ali Zia Apr 28 '16 at 11:01