Zooming And undo-redo on canvas not working properly
<p>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.</p>

<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Painitng&lt;/title&gt;
        &lt;style&gt;
            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;
            }
        &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;button id="zoomin"&gt;Zoom In&lt;/button&gt;
        &lt;button id="zoomout"&gt;Zoom Out&lt;/button&gt;
        &lt;button onclick="undo()"&gt;Undo&lt;/button&gt;
        &lt;button onclick="redo()"&gt;Redo&lt;/button&gt;
        &lt;div id="canvasDiv"&gt;&lt;/div&gt;
        &lt;script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"&gt;&lt;/script&gt; 
        &lt;script type="text/javascript"&gt;
            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 &lt;= 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 &lt;= 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 &lt; 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 &lt; 100 &amp;&amp; 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 &amp;&amp; g === startG &amp;&amp; b === startB) {
                    return true;
                }

                // If current pixel matches the new color
                if (r === curColor.r &amp;&amp; g === curColor.g &amp;&amp; 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 &gt;= drawingBoundTop &amp;&amp; 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 &lt;= drawingBoundBottom &amp;&amp; matchStartColor(pixelPos, startR, startG, startB)) {
                        y += 1;

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

                        if (x &gt; 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 &lt; 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 &amp;&amp; g === curColor.g &amp;&amp; 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 &gt; drawingAreaY &amp;&amp; mouseY &lt; drawingAreaY + drawingAreaHeight) &amp;&amp; (mouseX &lt;= 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 () {

            };

        &lt;/script&gt; 
        &lt;script type="text/javascript"&gt; $(document).ready(function () {
                start();
            });&lt;/script&gt; 
        &lt;script language="javascript"&gt;
            $('#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();
                }
            });
        &lt;/script&gt;
        &lt;div class="colorpick"&gt;
            &lt;div class="pick" style="background-color:rgb(150, 0, 0);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(0, 0, 152);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(0, 151, 0);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(255, 0, 5);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(255, 255, 0);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(0, 255, 255);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(255, 0, 255);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(255, 150, 0);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(255, 0, 150);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(0, 255, 150);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(150, 0, 255);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
            &lt;div class="pick" style="background-color:rgb(0, 150, 255);" onclick="hello(this.style.backgroundColor);"&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;script&gt;
            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);
            }
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;
</code></pre>