Tuesday, January 29, 2013

A Size for All Windows

One of the problems web app developers face is all the differences between browsers and monitors that we are trying to write for. We want our app to look good on everyone's screen. And we want it to look good on everyone's favorite browser.

Click this link to our Dog Race project for this post. This version has been updated to adapt to your browser.

Re-size your browser window and refresh the page. You should see the size of the canvas change. The finish line moves and the dogs still end at the right hand edge.

The good news is that there are several values that the browser will reveal to us. We can use JavaScript to gather information about the current size of the window. Look at the following code:

alert(window.innerWidth + " x " + window.innerHeight);

You can find all the details here at: W3Schools.

I know it is a bit annoying, but I have left the alert in the code so that you can try different window sizes and see the values on your own screen.

I have put the height of the window in there for you to see, but this page doesn't use it anywhere. Instead we will make horizontal adjustments only. We are not checking for changes to the size while the app is running, only when it is refreshed.

To make all this work, we set up a few global variables:
var currentWidth = window.innerWidth;
var canvasLeft = currentWidth * 0.05;
var canvasWidth = currentWidth * 0.88;
We have been using canvasLeft all along, but now we are going to set it to 5% of the window size. We are adding canvasWidth which will be 88% of the window size. That number came about from experimenting with different values.

It only requires a few changes to the original script to place things in the right spot no matter what the size of the window. First we will set the size of our game board:

 function clearCanvas(thisColor){          
       ctx.fillStyle = thisColor;
       ctx.rect(canvasLeft,0,canvasWidth,400);
       ctx.fill();
 }

We also need to make sure the finish line moves:

        //draw the finish line
        ctx.strokeStyle = 'black'
        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.moveTo(canvasLeft + canvasWidth - 30,15);
        ctx.lineTo(canvasLeft + canvasWidth - 30,380);
        ctx.closePath();
        ctx.stroke();


We will use the same variable to adjust the spot on the canvas that where we want the dogs to stop:
var leaderNose = canvasLeft + canvasWidth - 90;
When it came time to print the finishing order next to each dog at the end of the race, I decided to switch the alignment from left to right so that I didn't have to worry about the width of the character:

ctx.textAlign="right";
ctx.fillText(place,canvasLeft+canvasWidth,dog*60 + 60);

Sometimes the fanciest effects are the easiest to code. If you want to copy and paste the entire script into your own editor, here it is below. Don't forget to give Drop Your Anchor a try. C U Next Time!

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
    <meta name="description" content="">
    <meta name="keywords" content="">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=1;">
    <title>Dog Race</title>
    <style>body{color:#FFFFFF}</style>
    <script type="text/javascript">
    /* Demo Script for 'Writing Games with Canvas in HTML5'
    © Copyright 2013, Budd Churchward
    */
   
   
   
  
   
    var myRed = "#FE0000";         //red - first value is 254
    var myBlue = "#0200DD";        //blue - first value is 2
    var myYellow = "#FCFF00";      //yellow - first value is 252
    var myMagenta = "#660066";     //magenta - first value is 253
    var myOrange = "#FF6600";      //orange is - first value is 255
    var myGreen = "#06FF00";       //green is - first value is 6
    var myBrown = "#993300";       //brown is - first value is 153
    var myBackground = "#007777";  //background -- first value is 0
   
    var currentWidth = window.innerWidth;
    var canvasLeft = currentWidth * 0.05;
    var canvasWidth = currentWidth * 0.88;
   
function canvasDogRaces(){

    // Get the canvas element.
    canvas = document.getElementById("myCanvas");

    // Make sure you got it.
    if (canvas.getContext){
        ctx = canvas.getContext("2d");
        alert(window.innerWidth + " x " + window.innerHeight);
       
        clearCanvas(myBackground);
       
        drawDog(myGreen, canvasLeft + 20, 10);
        drawDog(myYellow, canvasLeft + 20, 70);
        drawDog(myBrown, canvasLeft + 20, 130);
        drawDog(myRed, canvasLeft + 20, 190);
        drawDog(myBlue, canvasLeft + 20, 250);
        drawDog(myMagenta, canvasLeft + 20, 310);
        //draw the finish line
        ctx.strokeStyle = 'black'
        ctx.beginPath();
        ctx.lineWidth = 1;
        ctx.moveTo(canvasLeft + canvasWidth - 30,15);
        ctx.lineTo(canvasLeft + canvasWidth - 30,380);
        ctx.closePath();
        ctx.stroke();
       
       
        // set start point for each dog and image array
        for (var x = 0; x < 6; x++){
            hisSpot[x] = canvasLeft + 2;
            dogImage[x] = 0;
            }
        dogCatcher();
        delayLoop=self.setInterval(function(){scooter(15)},20);
    }else{

       alert("Your browser does not\n support 'Canvas'");

    }

 }


 var delayLoop = 0;
 var runningDogX = canvasLeft;
 var testSpot = 0;

 var hisSpot = new Array();
 var dogImage = new Array();


 var thisDog = new Array();
 thisDog[0] = "Arlo";
 thisDog[1] = "O'Yeller";
 thisDog[2] = "Brownie";
 thisDog[3] = "Red Rover";
 thisDog[4] = "Bo";
 thisDog[5] = "Max";

var placeText = new Array();
placeText[0] = "1st Place: ";
placeText[1] = "2nd Place: ";
placeText[2] = "3rd Place: ";

 function showWinner(dog){
     ctx.fillStyle='White';
    ctx.font="24px Arial";
    ctx.textAlign="left";
    ctx.fillText(placeText[place] + thisDog[dog],canvasLeft + 20,40*place+30);
    }
   
 function goAgain(){
     location.reload();
     }

 function dogCatcher(){
     for(var dog = 0; dog < 6; dog++){
         dogImage[dog] = ctx.getImageData(hisSpot[dog], dog * 60 + 15,70 ,55);
        //ctx.putImageData(dogImage[dog],0,dog * 60);
        }
     }
var leaderNose = canvasLeft + canvasWidth - 90;
var place = 0;

function scooter(){
    var step = 1;
    var keepGoing = 0;
    for(var dog = 0; dog < 6; dog++){
         if(hisSpot[dog]>0){
             step = Math.floor(Math.random() * 8)+1;
             hisSpot[dog] = hisSpot[dog] + step;
             ctx.putImageData(dogImage[dog],hisSpot[dog],dog * 60 + 15);
             keepGoing++;
             if(hisSpot[dog]>leaderNose){
                 hisSpot[dog]=0;
                 if(place<3){showWinner(dog); }
                 place++;
                 ctx.textAlign="right";
                 ctx.fillText(place,canvasLeft+canvasWidth,dog*60 + 60);
                 }
             }
         }
         if(keepGoing==0){clearInterval(delayLoop); }
    }
   
function myDogSpot(x,y){
    ctx.putImageData(dogImage,x, y);
    }

 function drawDog(thisColor,dogX,dogY){
      // draw tail
     ctx.beginPath();
     ctx.lineWidth = 3;
     ctx.strokeStyle = 'black';
     ctx.moveTo(dogX + 5,dogY+32);
     ctx.lineTo(dogX-10,dogY + 25);
     ctx.closePath();
     ctx.stroke();
   
     // draw body
     ctx.fillStyle = thisColor;
     ctx.beginPath();    
     ctx.rect(dogX+8,dogY + 30,24,16);
     ctx.rect (dogX,dogY + 35, 10, 25);
     ctx.rect (dogX + 30,dogY + 35, 10, 25);
     ctx.fill();
     ctx.arc(dogX + 8, dogY + 38, 8,  0, 2*Math.PI, true);
     ctx.arc(dogX + 32, dogY + 38, 8, 0, 2*Math.PI, true);
     ctx.closePath();
     ctx.fill();
   
     // draw head
     ctx.beginPath();
     ctx.arc(dogX + 36, dogY + 22, 8,  0, 2*Math.PI, true);
     ctx.closePath();
     ctx.fill();
     ctx.beginPath();
     ctx.arc(dogX + 40, dogY + 22, 8, 0, Math.PI, false);
     ctx.closePath();
     ctx.fill();
   
     // draw nose
     ctx.fillStyle = 'black';
     ctx.beginPath();
     ctx.rect(dogX +46,dogY +22,3,3);
     ctx.closePath();
     ctx.fill();
   
     // draw eye
     ctx.beginPath();
     ctx.rect(dogX +40,dogY +20,3,3);
     ctx.closePath();
     ctx.fill();
   
     // draw ear
     ctx.beginPath();
     ctx.arc(dogX + 30, dogY + 18, 4, Math.PI, 0.2 *Math.PI, false);
     ctx.closePath();
     ctx.fill();

      }
   

 function clearCanvas(thisColor){          
       ctx.fillStyle = thisColor;
       ctx.rect(canvasLeft,0,canvasWidth,400);
       ctx.fill();
 }

 </script>
 </head>
 <body onload="canvasDogRaces()" bgcolor="#339999">    

    <h3>     

        <div id="rowOne_text">Welcome to the Races</div>     

        <div id="rowTwo_text">Pick Your Dog</div>   

    </h3>

 

    <canvas id="myCanvas" width="1440" height="400" ;">  

    </canvas>

</body>
</html>

No comments:

Post a Comment