XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

ExplorerCanvas: Interactive Web Apps
by Dave Hoover | Pages: 1, 2, 3

InteractiveCanvas.html

<html>
<head>

<script type="text/javascript" src="excanvas.js"></script>
<script type="text/javascript" src="prototype-1.4.0.js"></script>
<script type="text/javascript">

window.onload = function() {
    if ( document.addEventListener ) {
        document.addEventListener("click", onClick, false);
    } else if ( document.attachEvent ) {
        document.attachEvent("onclick", onClick);
    } else {
        alert("Your browser will not work for this example.");
    }
};

function onClick(e) {
    var context = $("zoo").getContext("2d");
    var position = getRelativePosition(e);
    context.clearRect(0, 0, $("zoo").width, $("zoo").height);
    context.beginPath();
    context.arc(position.x, position.y, 10, 0, 2*Math.PI, false);
    context.closePath();
    context.fill();
}

function getRelativePosition(e) {
    var t = $("zoo");
    var x = e.clientX+(window.pageXOffset||0);
    var y = e.clientY+(window.pageYOffset||0);
    do
        x-=t.offsetLeft+parseInt(t.style.borderLeftWidth||0),
        y-=t.offsetTop+parseInt(t.style.borderTopWidth||0);
    while (t=t.offsetParent);
    return {x:x,y:y};
}

</script>
</head>
<body>
<canvas id="zoo" width="500" height="300" style="border: 1px solid black"></canvas>

</body>
</html>

Enter the bad old days of JavaScripting ... Internet Explorer handles event listeners differently than the other browsers, so I had to put some conditional logic in the onload method. The different browsers also pass in canvas coordinates differently, so I needed to create the getRelativePosition (found via the canvas-developers group) function to give me the coordinates I need. I extracted the drawing functionality to the onClick function and added the clearRect call, which clears the screen before I redraw the squirrel.

Thus far, I developed all of this without a server, and no AJAX. The zoologists could use the app right now, but they wouldn't be able to see each other's updates: each zoologist would have only his or her own isolated tracking information. It's time to introduce a server to allow the zoologists to cooperatively track the squirrel. Just like my last article, I'll use Ruby's WEBrick server to keep things simple. I'll start by polling the server for the location of the squirrel and refreshing the canvas with its coordinates.

cosley-server.rb

require 'webrick'
include WEBrick

server = HTTPServer.new( :Port => 8053 )
server.mount("/", HTTPServlet::FileHandler, ".")

server.mount_proc("/squirrel/location") do |request, response|
  response['Content-Type'] = "text/plain"

  response.body = '({"x":50,"y":50})'
end

trap("INT") { server.shutdown }

server.start

This server will use its current directory as the docroot. I also mounted a closure that will respond to http://localhost:8053/squirrel/location with hard-coded JSON coordinates.

InteractiveCanvas.html

<html>
<head>
<script type="text/javascript" src="excanvas.js"></script>
<script type="text/javascript" src="prototype-1.4.0.js"></script>

<script type="text/javascript">

window.onload = function() {
    startPolling();
    setupClick();
};

function startPolling() {
    new PeriodicalExecuter(function() {
            new Ajax.Request('/squirrel/location',
                { onComplete: function(request) {
                        var jsonData = eval(request.responseText);
                        if (jsonData == undefined) { return; }
                    draw(jsonData);
                  }});
    }, 1);
}

function setupClick() {
    if ( document.addEventListener ) {
        document.addEventListener("click", onClick, false);
    } else if ( document.attachEvent ) {
        document.attachEvent("onclick", onClick);
    } else {
        alert("Your browser will not work for this example.");
    }
}

function onClick(e) {
    draw(getRelativePosition(e));
}

function draw(position) {
    var context = $("zoo").getContext("2d");
    context.clearRect(0, 0, $("zoo").width, $("zoo").height);
    context.beginPath();
    context.arc(position.x, position.y, 10, 0, 2*Math.PI, false);
    context.closePath();
    context.fill();
}

function getRelativePosition(e) {
    var t = $("zoo");
    var x = e.clientX+(window.pageXOffset||0);
    var y = e.clientY+(window.pageYOffset||0);
    do
        x-=t.offsetLeft+parseInt(t.style.borderLeftWidth||0),
        y-=t.offsetTop+parseInt(t.style.borderTopWidth||0);
    while (t=t.offsetParent);
    return {x:x,y:y};
}

</script>
</head>
<body>
<canvas id="zoo" width="500" height="300" style="border: 1px solid black"></canvas>

</body>
</html>

I needed to make a few changes to the client code. I refactored the onload method to a more declarative style because things were getting messy in there. The startPolling function was the major addition. It combines two Protoype classes to poll the server via AJAX for the location of the squirrel once every second. It evals the asynchronous JSON response and redraws the squirrel in its latest location. Point your browser at http://localhost:8053/InteractiveCanvas.html and you'll see the squirrel sitting in the upper left corner.

The problem is that the zoologists can see where the squirrel was, but they can't tell the server where the squirrel is now (the cute little thing keeps moving back up to the corner). One more AJAX call should finish the job. First I'll update the server by mounting another closure that can handle coordinate updates.

Pages: 1, 2, 3

Next Pagearrow