From fdc0efcd7cc39b5b09592fdd5a3c80b162406c2a Mon Sep 17 00:00:00 2001 From: Robert Byrne Date: Tue, 31 Dec 2013 01:58:40 +0000 Subject: [PATCH] #23 Image is fully loaded before executing resize and split --- WebContent/js/Image.js | 156 +++++++--------- WebContent/js/Puzzle.js | 405 +++++++++++++++++++--------------------- 2 files changed, 266 insertions(+), 295 deletions(-) diff --git a/WebContent/js/Image.js b/WebContent/js/Image.js index aebef9f..8717363 100644 --- a/WebContent/js/Image.js +++ b/WebContent/js/Image.js @@ -1,7 +1,15 @@ -var PicPuzzle_ImageActions = { +var ImagePuzzle_ImageActions = { - load: function() { + loadImage: function(imgsrc, callback) { + var img = new Image(); + + img.onload = function(){ + + callback(img); + }; + + img.src = imgsrc; }, /* @@ -14,69 +22,60 @@ var PicPuzzle_ImageActions = { * Returns: an Array of canvasElements (Images) * */ - split: function(imgsrc, tiles, callback) { + split: function(canvas, tiles) { var canvasArray = new Array(); - var split = function() { - var img = PicPuzzle_ImageActions.resize(imgsrc); - - var row_col = Math.sqrt(tiles), - tileH = Math.round(img.height / row_col), - tileW = Math.round(img.width / row_col), - - xoffset = 0, - yoffset = 0; - - var imgNumBgSizeWidth, - imgNumXOffset; - - - for (var i = 0; i < tiles; i++) { - - //create canvas element and set attributes and get the canvas context - canvasArray[i] = document.createElement('canvas'); - canvasArray[i].setAttribute('width', tileW); - canvasArray[i].setAttribute('height', tileH); - canvasArray[i].setAttribute('id', 'canvas' + i); - var ctx = canvasArray[i].getContext('2d'); - - ctx.drawImage(img, xoffset, yoffset); - + + var row_col = Math.sqrt(tiles), + tileH = Math.round(canvas.height / row_col), + tileW = Math.round(canvas.width / row_col), + xoffset = 0, + yoffset = 0, + imgNumBgSizeWidth, + imgNumXOffset; - if (i+1 > 9){ - imgNumBgSizeWidth = 16; - imgNumXOffset = 1; - } - else{ - - imgNumBgSizeWidth = 10; - imgNumXOffset = 2; - } - - //draw tile numbers - ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; - ctx.fillRect(0, 0, imgNumBgSizeWidth, 10); - ctx.fillStyle = '#fff'; - ctx.font = 'italic 10px sans-serif'; - ctx.textBaseline = 'top'; - ctx.fillText (i+1, imgNumXOffset, 1); - - //if i is a multiple of the total number of tiles to a row, - //move down a column and reset the row_col - if ((i + 1) % row_col == 0) { - yoffset -= tileH; - xoffset = 0; - } else { - //otherwise move across the image - xoffset -= tileW; - } + for (var i = 0; i < tiles; i++) { + + //create canvas element and set attributes and get the canvas context + canvasArray[i] = document.createElement('canvas'); + canvasArray[i].setAttribute('width', tileW); + canvasArray[i].setAttribute('height', tileH); + canvasArray[i].setAttribute('id', 'canvas' + i); + var ctx = canvasArray[i].getContext('2d'); + + ctx.drawImage(canvas, xoffset, yoffset); + + if (i + 1 > 9){ + + imgNumBgSizeWidth = 16; + imgNumXOffset = 1; + + }else{ + + imgNumBgSizeWidth = 10; + imgNumXOffset = 2; + } + + //draw tile numbers + ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; + ctx.fillRect(0, 0, imgNumBgSizeWidth, 10); + ctx.fillStyle = '#fff'; + ctx.font = 'italic 10px sans-serif'; + ctx.textBaseline = 'top'; + ctx.fillText (i+1, imgNumXOffset, 1); + + //if i is a multiple of the total number of tiles to a row, + //move down a column and reset the row_col + if ((i + 1) % row_col == 0) { + yoffset -= tileH; + xoffset = 0; + } else { + //otherwise move across the image + xoffset -= tileW; } - callback(canvasArray); - }; - var img = new Image(); - //console.log(img.complete); - - if (img.complete) {split();} else $(img).load(split); + } + + return canvasArray; }, /* @@ -87,35 +86,22 @@ var PicPuzzle_ImageActions = { * Returns: A resized canvas Element (Image) * */ - resize: function(imgsrc){ + resize: function(loadedImage, callback){ var img = new Image(), canvas = document.createElement('canvas'), ctx = canvas.getContext("2d"); - - img.src = imgsrc; - //console.log(imgsrc); - //console.log("image h "+img.height+"\nimage w "+img.width); - //console.log("screen h/4 "+screen.height/4+"\nscreen w/4 "+screen.width/4); - - //show message to the user if the image is a small size - if((img.width < screen.width/4 && img.width != 0) || (img.height < screen.height/4 && img.height !=0) ){ - PicPuzzle_Utils.updateText('message','As the submitted image is small it may lose quality when scaled up'); - PicPuzzle_Utils.notify('#message',3000); - } - - //maximum image size - canvas.width = screen.width/2; - canvas.height = screen.height/2; - - try{ + img.onload = function(){ + + //maximum image size + canvas.width = screen.width/2; + canvas.height = screen.height/2; ctx.drawImage(img,0,0,screen.width/2,screen.height/2); - }catch(err){ - PicPuzzle_Utils.updateText('message','Please try again, image loading did not fully complete that time.'); - PicPuzzle_Utils.notify('#message',5000); - } - - return canvas; + + callback(canvas); + }; + + img.src = loadedImage.src; } }; diff --git a/WebContent/js/Puzzle.js b/WebContent/js/Puzzle.js index 4c0ee60..eec7dcc 100644 --- a/WebContent/js/Puzzle.js +++ b/WebContent/js/Puzzle.js @@ -1,309 +1,295 @@ $(document).ready(function() { var url = window.location.href, + blankRow = 0, + blankCol = 0, idCounter, score, - target, - sound = "on", + sound = 'on', noOfMoves = 0, - image = decodeURIComponent((url.split('&')[0]).split('=')[1]), + imgsrc = decodeURIComponent((url.split('&')[0]).split('=')[1]), rowCount = (url.split('&')[1]).split('=')[1], + target = rowCount * rowCount, timerIntervalId = 0, move_snd = new Audio("sounds/move1.wav"), shuffle_snd = new Audio("sounds/shuffle1.wav"), - win_snd = new Audio("sounds/success1.wav"); + win_snd = new Audio("sounds/success1.wav"); + PicPuzzle_Utils.checkCookie(); PicPuzzle_Utils.initButtons(); - + //validate row input if(rowCount > 9){ rowCount = 9; - PicPuzzle_Utils.updateText('message','9x9 is the maximum grid size.'); - PicPuzzle_Utils.notify('#message',5000); + PicPuzzle_Utils.dialog('Invalid input', '9x9 is the maximum grid size.'); } else if (rowCount < 2){ rowCount = 2; - PicPuzzle_Utils.updateText('message','2x2 is the minimum grid size.'); - PicPuzzle_Utils.notify('#message',5000); - } - - newGame(image,rowCount); - jumblePuzzle(rowCount); - + PicPuzzle_Utils.dialog('Invalid input', '2x2 is the minimum grid size.'); + } //check for sound toggle $('#soundClick').on('click', function(e) { if(sound == "on"){ sound = "off"; $(this).button('option', 'label', 'Unmute'); - } - else{ + + }else{ sound = "on"; $(this).button('option', 'label', 'Mute'); - } - }); - - + } + }); + + + newGame(imgsrc,rowCount); - function newGame(image,rowCount){ - - var blankRow = 0, - blankCol = 0; - - PicPuzzle_ImageActions.split(image, rowCount * rowCount, function(canvasArray) { + function newGame(imgsrc, rowCount){ + ImagePuzzle_ImageActions.loadImage(imgsrc, function(loadedImage){ + + ImagePuzzle_ImageActions.resize(loadedImage, function(imageResizedOnCanvas){ + + var canvasReady = ImagePuzzle_ImageActions.split(imageResizedOnCanvas, rowCount * rowCount); - //list to keep track of the tiles which are available for random selection - var tilesAvailable = new Array(rowCount^2); + // tiles available for random selection + var tilesAvailable = new Array(rowCount^2); - //tilesAvailable contains possible tile numbers to select from at random - //array is full as no values have been randomly selected yet - for (var i = 0; i ').attr('id', 'grid'), - $tbody = $('').attr('id', 'tableBody'), - index = 0; + // array is full as no values have been randomly selected yet + for (var i = 0; i < canvasReady.length; i++) { + tilesAvailable[i] = i ; + } + + var $tbl = $('').attr('id', 'grid'), + $tbody = $('').attr('id', 'tableBody'), + index = 0; + + for (var i = 0; i < rowCount; i++) { + + var trow = $("").attr('id', 'row' + i); // New row + for (var j = 0; j < rowCount; j++) { - for (var i = 0; i < rowCount; i++) { - - var trow = $("").attr('id', 'row' + i); // New row - - for (var j = 0; j < rowCount; j++) { - - var $cell = $("
").append(canvasArray[index]); - $cell.attr('id','cell'+index); - - //Get the row and column position of the last canvas element - if(index == ((canvasArray.length -1))){ - - blankRow = i, - blankCol = j; - } - - $cell.appendTo(trow); - index++; + var $cell = $("").append(canvasReady[index]); + $cell.attr('id','cell' + index); + + // Get the row and column position of the last canvas element + if(index == ((canvasReady.length -1))){ + + blankRow = i, + blankCol = j; + } + + $cell.appendTo(trow); + index++; + } + + trow.appendTo($tbody); + $tbl.append($tbody); + $('table').remove(); + $('#content').append($tbl); } - - trow.appendTo($tbody); - $tbl.append($tbody); - $('table').remove(); - $('#content').append($tbl); - } + + // Position the blank cell in the position of the last canvas element + $('#grid tr:eq(' + blankRow + ') td:eq(' + blankCol + ')').children().hide(); + $('#grid tr:eq(' + blankRow + ') td:eq(' + blankCol + ')').attr('id', 'blankCell'); + + if (sound == 'on'){ + shuffle_snd.play(); + } + + PicPuzzle_Utils.setStartTime(new Date()); + + // ensuring timerIntervalId is cleared + if (timerIntervalId){ + clearInterval(timerIntervalId); + } + + timerIntervalId = setInterval(PicPuzzle_Utils.initTimer, 100); + + jumblePuzzle(rowCount); + + return false; + }); }); - - //Position the blank cell in the position of the last canvas element - $('#grid tr:eq('+blankRow+') td:eq('+blankCol+')').children().hide(); - $('#grid tr:eq('+blankRow+') td:eq('+blankCol+')').attr('id', 'blankCell'); - - //reset number of moves when image is scrambled - noOfMoves = 0; - PicPuzzle_Utils.updateText('moveCount',noOfMoves); - - //play start sound - if (sound == "on"){ - shuffle_snd.play(); - } - - PicPuzzle_Utils.setStartTime(new Date()); - - //ensuring timerIntervalId is cleared - if (timerIntervalId){ - clearInterval(timerIntervalId); - } - - timerIntervalId = setInterval(PicPuzzle_Utils.initTimer, 100); - - return false; - }; - - //Description: Jumbles the puzzle to a random but solvable state - //Paramaters: rowCount: The number or rows which is equal to the number - // of columns - function jumblePuzzle(rowCount){ - - var prevDir = null; - for (var i =0; i< rowCount*rowCount *2; i++){ - - //get the blank cell - var empty = $("#blankCell").get(0), - emptyrow = empty.parentNode, - ex = empty.cellIndex, - ey = emptyrow.rowIndex; - - //get possible directions - var dirs = getPossibleDirections(ex,ey,rowCount); - - - //check to make sure randDir is not the opposite of prevDir - //we do not want to undo the previous move - if (prevDir != null){ - - //remove the opposite direction from the possible choices - if (prevDir == 'u') - dirs = PicPuzzle_Utils.removeItemFromList(dirs,'d'); - else if (prevDir == 'd') - dirs = PicPuzzle_Utils.removeItemFromList(dirs,'u'); - else if (prevDir == 'r') - dirs = PicPuzzle_Utils.removeItemFromList(dirs,'l'); - else - dirs = PicPuzzle_Utils.removeItemFromList(dirs,'r'); - } - - //choose a dir at random - var randDir = PicPuzzle_Utils.randomChoice(dirs); - prevDir = randDir; - //move the empty cell in the direction - moveEmptyCell(ex,ey,randDir); - } - - } - - - //Description: Get the possible directions that the empty cell can move in - //Paramaters: empty cell position, - // empty row position, - // the number of rows - // - //Returns: The possible directions to the empty cell can move - // ['l','r','u','d'] left,right,up,down - function getPossibleDirections(ex,ey,rowCount){ - - var max = rowCount -1, - min =0; - //calculate the possible directions to choose + }; + + + + //Description: Moves the empty cell with a cell in a specified direction + //Paramaters: empty cellIndex, empty rowIndex, direction to move + function moveEmptyCell(ex,ey,direction){ + + var cellid = ""; + + //up + if(direction == 'u'){ + + cellid =document.getElementById("row"+(ey-1)).childNodes[ex].id; + } + //down + else if (direction == 'd'){ + + cellid =document.getElementById("row"+(ey+1)).childNodes[ex].id; + } + //left + else if (direction == 'l'){ + + cellid =document.getElementById("row"+ey).childNodes[ex-1].id; + } + //right + else{ + + cellid =document.getElementById("row"+ey).childNodes[ex+1].id; + } + + //swap cells + var cell = $("#"+cellid).get(0), + currow = cell.parentNode, + empty = $("#blankCell").get(0), + emptyrow = empty.parentNode, + afterempty = empty.nextSibling, + afterthis = cell.nextSibling; + currow.insertBefore(empty, afterthis); + emptyrow.insertBefore(cell, afterempty); + }; + + + + + //Description: Get the possible directions that the empty cell can move in + //Paramaters: empty cell position, + // empty row position, + // the number of rows + // + //Returns: The possible directions to the empty cell can move + // ['l','r','u','d'] left,right,up,down + function getPossibleDirections(ex,ey,rowCount){ + + var max = rowCount -1, + min = 0; + + //calculate the possible directions to choose //the random cell - + //we can go right or down //top left corner if(ex == min && ey == min){ - console.log("top left corner"); + var dirs = ['r','d']; return dirs; } //we can go right or up //bottom left corner else if(ex == min && ey == max){ - - console.log("bottom left corner"); + var dirs = ['r','u']; return dirs; } //we can go left or down //top right corner else if(ex == max && ey == min){ - - console.log("top right corner"); + var dirs = ['l','d']; return dirs; } //we can go left or up //bottom right corner else if(ex == max && ey == max){ - - console.log("bottom right corner"); + var dirs = ['l','u']; return dirs; } //we can go right, up or down //left side else if(ex == min && (ey > min && ey < max)){ - - console.log("left edge"); + var dirs = ['r','u','d']; return dirs; } //we can go left, up or down //right side else if(ex == max && (ey > min && ey < max)){ - - console.log("right edge"); + var dirs = ['l','u','d']; return dirs; } //we can go left, right or up //bottom side else if(ey == max && (ex > min && ex < max)){ - - console.log("bottom edge"); + var dirs = ['l','r','u']; return dirs; } //we can go left, right or down //top side else if(ey == min && (ex > min && ex < max)){ - - console.log("top edge"); + var dirs = ['l','r','d']; return dirs; } //we can choose a cell in any direction //cell is not touching a puzzle edge else{ - console.log("any"); + var dirs = ['l','r','u','d']; return dirs; - } - } - //Description: Moves the empty cell with a cell in a specified direction - //Paramaters: empty cellIndex, empty rowIndex, direction to move - function moveEmptyCell(ex,ey,direction){ - var cellid =""; - - //up - if(direction == 'u'){ - - cellid =document.getElementById("row"+(ey-1)).childNodes[ex].id; - console.log(cellid); - } - //down - else if (direction == 'd'){ - cellid =document.getElementById("row"+(ey+1)).childNodes[ex].id; - console.log(cellid); - } - //left - else if (direction == 'l'){ - cellid =document.getElementById("row"+ey).childNodes[ex-1].id; - console.log(cellid); - } - //right - else{ - cellid =document.getElementById("row"+ey).childNodes[ex+1].id; - console.log(cellid); - } - //swap cells - var cell = $("#"+cellid).get(0), - currow = cell.parentNode, - empty = $("#blankCell").get(0), - emptyrow = empty.parentNode, - afterempty = empty.nextSibling, - afterthis = cell.nextSibling; - currow.insertBefore(empty, afterthis); - emptyrow.insertBefore(cell, afterempty); - } - - - // Event handler for clicking table cells + } + + + //Description: Jumbles the puzzle to a random but solvable state + //Paramaters: rowCount: The number or rows which is equal to the number + // of columns + function jumblePuzzle(rowCount){ + + var prevDir = null; + + for (var i = 0; i < rowCount * rowCount * 2; i++){ + + var empty = $("#blankCell").get(0), + emptyrow = empty.parentNode, + ex = empty.cellIndex, + ey = emptyrow.rowIndex; + + var dirs = getPossibleDirections(ex,ey,rowCount); + + //check to make sure randDir is not the opposite of prevDir + //we do not want to undo the previous move + if (prevDir != null){ + + //remove the opposite direction from the possible choices + if (prevDir == 'u') + dirs = PicPuzzle_Utils.removeItemFromList(dirs,'d'); + else if (prevDir == 'd') + dirs = PicPuzzle_Utils.removeItemFromList(dirs,'u'); + else if (prevDir == 'r') + dirs = PicPuzzle_Utils.removeItemFromList(dirs,'l'); + else + dirs = PicPuzzle_Utils.removeItemFromList(dirs,'r'); + } + + var randDir = PicPuzzle_Utils.randomChoice(dirs); + prevDir = randDir; + moveEmptyCell(ex,ey,randDir); + } + }; + + $('#content').on('click', '#grid td', function(e) { idCounter = 0, score = 0; - - console.log('onclick: ' +this); var empty = $("#blankCell").get(0); if (!empty || this == empty) return; // abort, abort! - + var currow = this.parentNode, emptyrow = empty.parentNode; var cx = this.cellIndex, @@ -318,19 +304,18 @@ $(document).ready(function() { emptyrow.insertBefore(this, afterempty); noOfMoves++; - + //play the move sound - if(sound == "on"){ + if(sound == 'on'){ move_snd.play(); } - - PicPuzzle_Utils.updateText('moveCount',noOfMoves); + + PicPuzzle_Utils.updateText('moveCount', noOfMoves); } // Check if puzzle is complete after each move $("td").each(function() { - target = rowCount * rowCount; - + if ($(this).children().attr("id") == "canvas" + idCounter){ score++; if (score == target){ @@ -354,7 +339,7 @@ $(document).ready(function() { PicPuzzle_Utils.increasePuzzlesSolved(); PicPuzzle_Utils.updateText('puzzlesSolved', PicPuzzle_Utils.getCookie("puzzlesSolved")); - + PicPuzzle_Utils.playAgain( "Congratulations!
" + "You solved the puzzle in
" +