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

advertisement

All Aboard AJAX, HTML Canvas, and the Supertrain
by Dave Hoover | Pages: 1, 2, 3, 4, 5, 6

Now when I point my browser to http://localhost:8053/train/line and repeatedly refresh, I see the data changing! It shows the apparent progress of a train heading south from Woodinville to Redmond, along with a train heading north from Redmond to Woodinville.

Figure 3
Figure 3.

Next I will AJAX-ificate the redwood.html page to save me from having to repeatedly click Refresh. To accomplish this, I'll use the insanely simple Prototype library.

docroot/redwood.html

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

<div id="status"></div>
<script type="text/javascript">
  new Ajax.PeriodicalUpdater($("status"), "/train/line")
</script>

</body>
</html>

Pointing my browser to http://localhost:8053/redwood.html, I now see my trains' status updating every 2 seconds (the default polling period for Prototype's Ajax.PeriodicalUpdater). Cool! Unfortunately my customer won't be so easily impressed. It's time to turn that server-side state into dynamically updating client-side graphics. I'll continue taking small steps, so, like any good railroad project should, I'll start with some tracks:

docroot/redwood.html


...
<body>

<canvas
  id="redwood"
  width="500"
  height="120"
  style="border: 1px solid black">
</canvas>

<script type="text/javascript">
  var tracks = {
    north: new Track(30),
    south: new Track(85)
  }

  var canvas = undefined

  // IE will return false here
  if ($("redwood").getContext) {
    canvas = $("redwood").getContext("2d")
    drawTracks()
  }

  function drawTracks() {
    $H(tracks).values().each(function(track) {
        track.draw()
    })
  }

  function Track(y) {
    this.y = y
    this.startX = 10
    this.endX = 490
    this.tieSize = 3
    this.tieGap = 5
    this.draw = drawTrack
  }

  function drawTrack() {
    canvas.moveTo(this.startX, this.y)
    canvas.beginPath()
    var x = this.startX
    while (x < this.endX) {
      canvas.lineTo(x, this.y)
      canvas.lineTo(x, this.y + this.tieSize)
      canvas.moveTo(x, this.y)
      canvas.lineTo(x, this.y - this.tieSize)
      canvas.moveTo(x, this.y)
      x = x + this.tieGap
    }
    canvas.closePath()
    canvas.stroke()
  }
</script>

<div id="status"></div>
...

Figure 4
Figure 4.

Note that I'm not using the standard JavaScript for loops. Since I'm using the Prototype (1.4.0) JavaScript library for AJAX, I'm taking advantage of its Ruby-like collection iterators and syntactic sugar: $(), $H().values(), and each(). Now that my tracks are laid, I need to drop in some trains. First, I'll remove my Ajax.PeriodicalUpdater example, replacing it with a window.setInterval call (setInterval is an essential ingredient of creating a dynamic canvas). I'll also refactor drawTracks into a higher-level updateCanvas function:

docroot/redwood.html

  ...
  if ($("redwood").getContext) {
    canvas = $("redwood").getContext("2d")
    window.setInterval(updateCanvas, 1000 * 2)
    updateCanvas()
  }

  function updateCanvas() {
    clearScreen()
    drawTracks()
  }

  function clearScreen() {
    canvas.clearRect(0, 0, $("redwood").width, $("redwood").height)
  }

  function drawTracks() {
  ...

Pages: 1, 2, 3, 4, 5, 6

Next Pagearrow