Tutorial: HTML5 Canvas Demo in Drupal

The image of the Old Glory below was created with HTML5 canvas and there are a few tricks involved in getting it to work with Drupal 7. The first step is to get the HTML5 doctype at the top of all your Drupal pages. You can modify html.tpl.php, the template determining this, but careful if you do, and maybe the simplest approach is to install the Elements and HTML5 Tools modules. Before enabling those modules, viewing the page source shows doctype references to xhtml, afterwards it does not. Don't forget to clear the cache after enabling the modules and before viewing the source if you want to check (Configuration > Performance > Clear all caches). Then this HTML/CSS puts the rectangle at the upper right:

 <div id="canvasContainer" style="float:right; border:1px solid black; margin:0 0 15px 15px">
  <canvas id="flag" width="296" height="156"></canvas>
 </div>

It looks good, but is it really a canvas? We have to get Javascript into play to draw something. First enable the PHP filter global module, then choose PHP code for the text format on the page with the canvas. This is the jQuery we want to get executed, the ready() function should execute at page load time and draw a red stripe across the top of the canvas:

  jQuery(document).ready(function() {
    var canvas = document.getElementById("flag");
    if (canvas.getContext)
    {
      var ctx = canvas.getContext("2d");
      // Top red stripe.
      ctx.fillStyle = "#B22234";
      ctx.fillRect(0, 0, 296, 12);
    } // if (canvas.getContext)
  });

In order to get the Javascript executed, enter the following at the top of the page being written, above all the HTML, replacing [jQuery here] with the actual jQuery code to be executed (as a PHP string with the single quotes):

<?php
  drupal_add_js('[jQuery here]', 'inline');
?>

Assuming the red stripe showed up, we've got a proof of concept. It's a stopgap though, we'd like to get the Javascript into a .js file and have it be associated with the page. This can be done through the theme, but a simple approach I prefer uses the Javascript Libraries Manager Module. This module was contributed by Drupal Gardens and provides a general solution to Javascript management in Drupal, including external libraries like jQuery UI as well as your own custom code. Your Javascript can be associated with all the pages on your site or just some of them, as here, where the Javascript is to be associated with one page only. So upload the Javascript Libraries module to your site and enable it.

Drupal Gardens has a nice rundown here and most of it applies to any Drupal site, especially the Adding custom JavaScript section towards the bottom. Create flag.js and add exactly the Javascript / jQuery above, only changing the second parameter in fillRect(), which draws a red stripe across the canvas but 24 pixels down this time:

  ctx.fillRect(0, 24, 296, 12);

Follow the Drupal Gardens directions for uploading a custom file (it will go in your sites folder) and make it disabled - there is another step to get it attached to a page. This involves creating a block, then attaching the block to the page and the Javascript to the block. Create the block by choosing Structure > Blocks > Add block. Add title, body, and description as you see fit, and attach the block to Sidebar first. Save the block at that point, then return right away to edit it; this part threw me, because the key Javascript part of the block's visibility settings (at the bottom of the block creation page) only shows up when editing. Now adjust the visibility settings. For Pages, choose Only the listed pages and type in canvas-demo in the text box, the name of this page. JavaScript libraries should be under Visibility settings when editing the first time. Under Available libraries, check the Javascript file you've uploaded - it's description should be there. Again save the block. You can see the block on this page in the left sidebar under the navigation menu, where it says "Old Glory in HTML5 canvas".

With any luck that second red stripe should appear on the canvas when refreshing the page. At this point, remove the inline PHP at the top of the page and revert to one of the HTML text formats. When uploaded, flag.js was renamed to flag.js.txt and stored in /sites/default/files/javascript_libraries/. The Javascript can be amended and uploaded with FTP; as always, be liberal in clearing the cache if changes are being ignored.

The official specs for the flag are here: the colors, aspect ratio (19 / 10), and so on. In vector graphics systems like this, objects drawn earlier in the sequence are covered up by what is drawn later. So the strategy for the flag is to draw a white-filled, black-stroked rectangle to fill the entire canvas, then the red stripes as rectangles, then the blue field, and finally the stars. The stars are the only challenging part and each of them is drawn with this function:

function drawStar(ctx, tx, ty, scale)
{
  // USE:  Draw regular five-pointed star.
  // IN:   ctx = graphics context to draw in
  //       tx = x amount to translate
  //       ty = y amount to translate
  //       scale = scale factor (0.5 to halve, 2.0 to double)
  // NOTE: Uses the ctx's current fillStyle and strokeStyle 

  ctx.save();

  // Values below will be translated and scaled as set here.
  ctx.translate(tx, ty);
  ctx.scale(scale, scale);

  // Draw five-pointed star in 380 x 362 box.
  ctx.beginPath();
  ctx.moveTo(35,163);
  ctx.lineTo(415,163);
  ctx.lineTo(107,387);
  ctx.lineTo(225,25);
  ctx.lineTo(343,387);
  ctx.lineTo(35,163);
  ctx.closePath();
  ctx.stroke();
  ctx.fill();

  ctx.restore();
} // drawStar()

The graphics context is sent in, (tx, ty) to translate or position, and parameter scale to size. The numbers in the function draw a five pointed star in a 380 x 362 coordinate system - get out the trig book! There is no particular significance to the size of the coordinate system; you just don't want it too small. That is the beauty of vector graphics, they scale up and down with great fidelity. Figures break down at really small sizes and I was afraid of that with the stars, but they look pretty good with scale = 0.03. Here is the entire Javascript file.

Mike Bertrand

December 12, 2013