Wednesday, March 17, 2010

Canvas Wrapper with getTransform()

The Canvas spec does not include a getTransform() method, so after performing rotation/scale/translation operations there is no way to work out where you really are.

So, I have created a wrapper class, which sits over the top of Canvas, and should behave exactly the same, except you now have a getTransform() method which returns a matrix such that the following doesn't do anything:
var m = ctx.getTransform();
ctx.setTransform( m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1] );
To use, add the following line:
<script type="text/javascript" src="canvas_wrapper.js"></script>
then wrap your canvas object in a CanvasWrapper, ie:
ctx = new CanvasWrapper(document.getElementById("canvas").getContext("2d"));
It works by duplicating Canvas' matrix operations, and mimicking the Canvas interface. An annoyance is that Canvas has public fields, instead of accessor methods, so I can't tell when it has been changed and have to update the canvas state before any drawing call.

Update 10/2/2013: Thanks to Heikki Pora for a patch adding some missing features.

Update 19/5/2015: The HTML Spec now includes context.currentTransform but it doesn't work for me in Firefox or Chromium, ctx.mozCurrentTransform does work in Firefox.


  1. There is no GetTransform method in the linked class, just getCoords.

  2. Thanks Josh, I've added it now.

  3. Hi Dave! There are quite a lot of transform trackers around. Isn't it annoying that the CTM wasn't exposed in the first place, so we have to jump through silly hoops like this? Hrmph.

    Anyway, I've taken a somewhat different approach to you, so I thought you might be interested to see mine. Primarily, yours is a wrapper whereas mine's a polyfill.
    Also mine solves the public field problem by using Object.defineProperty, but I'm not sure how portable that is, and I think a polyfill for it in turn is impossible.

    I put it in a jsfiddle just now, with a simple demo:

    I suspect that some sort of merger of your ideas and mine would yield a 'best of breed'. I wonder what you think. Maybe a github mini-project is in order, even.

    Anyway, please feel free to contact me at, but remove the tasty yellow fruit from that address before using it :-)