Implementing an HTML5 Canvas screen overlay
Part of our Dev Camp project this year involves being able to annotate a presentation slide using a mouse, finger or stylus. We instantly looked to the HTML5 Canvas element to provide a bitmap drawing surface.
Sizing and scaling the Canvas
When first trying to create a canvas that overlaid the screen I discovered that they had two height/width properties.
- canvas.style.height/width – CSS attributes
- canvas.height/width – DOM properties
Scaling the canvas with the window can be done by setting the the style.width and style.height in an event handler. This thought makes the co-ordinates of the screen and that of the canvas out of sync so lines don't appear under where you draw them. Unfortunately changing the DOM properties causes the canvas to clear itself, necessitating copying the canvas, resizing it, and copying back the content but rescaled.
An easiler solution was to fix the size to the canvas and only change the CSS attributes translating between the screen co-ordinates and those of the canvas, this gives rescaling for free and will also make matters easier when displaying the annotations on multiple screens with different resolutions.
To make the canvas appear in front of everything else it was given a-really-big-number™ for its z-index.
Annotating with pointer events
Annotating on the canvas was done by adding event listeners for mousedown, mousemove, and mouseup. This worked well on traditional devices with a mouse but not at all on newer touch-orientated devices. Rather than duplicating effort and coding for both mouse events and touch events (and possibly others; pen for example), pointer events were used.
Earlier in the year we had a lunchtime mini-conf video of Jacob Rossi's W3Conf talk 'Pointing-forward' where he spoke about the proposed pointer events W3C specification from Microsoft for handling hardware agnostic pointer input. It is supported in IE10 with vendor prefixes and in IE11. Fortunately there's a polyfil, hand.js, to enable support in other browsers.
One slight additional change required for touch devices is to disable the default behaviour of the events; dragging your finger over the device is usually mapped to scroll.
Hiding the canvas and disabling it to allow interaction with underlying content was easily achieved using two CSS attributes: visibilty (hidden/visible), and pointerEvents (none/auto).
We ended up with a canvas that could be shown and hidden, overlaying the slide and allowing the user to annotate on top without disturbing the content underneath. As well as being able to switch off annotation mode, so that you could then interact with the slide, but keep the annotation overlay visible.
Leave a Reply