Home

Awesome

Canvas Interceptor

canvas-interceptor.js is a snippet to aid with debugging canvas issues, and designed to create reduced test cases.

Load canvas-interceptor.js before the web page uses the HTML5 canvas API. Then the all method calls and property invocations on canvas objects will be logged and stored in the __proxyLogs property on the canvas context. The final code to recreate the canvas can be generated by calling getCanvasReplay(canvas).

Example:

<script src="canvas-interceptor.js"></script>

<canvas id="mycanvas"></canvas>
<!-- ... a lot of canvas magic on #mycanvas... -->

<script>
var canvas = document.getElementById('mycanvas');
var code = getCanvasReplay(canvas);
// code can be copied to a new file to recreate the canvas,
// and used to e.g. create reduced test cases for canvas bugs.
// E.g. via the console: copy(code)
</script>

See test.html for more examples.

Usage

If you control the source code, loading the snippet via a <script> tag as in the above example should work as expected. But if you want to debug a third-party application, it is more convenient to paste something in the JavaScript console.

  1. Identify the first script in the page, and set a breakpoint at the start of the file.

  2. Reload the page. The browser will now trigger that breakpoint.

  3. Paste the following code:

    ;(function(){
    var x = new XMLHttpRequest;
    x.open('GET', 'https://robwu.nl/s/canvas-interceptor.js', false);
    x.send();
    window.eval(x.responseText.replace(/(["'])use strict\1/g, ''));
    })();
    
  4. Step out of the debugger.

  5. Now you can freely use the public methods (documented below) to debug canvas issues.

Reducing test cases

After calling getCanvasReplay(), you can end up with thousands lines of code. This code can be pasted to a file and used for debugging. Here are some tips to reduce the file, in order to pinpoint the bug:

Browser compatibility

Run test.html to see whether the tool works as expected.

API documentation

When canvas-interceptor.js is loaded, it modifies the prototype of CanvasRenderingContext2D to intercept calls. The following APIs are exposed:

If you need to use a canvas method without logging, retrieve the original property from .__proxyOriginal, and call the method (value) or setter/getter. Example: ctx.__proxyOriginal.scale.value.call(ctx, 1, 1) or ctx.__proxyOriginal.lineWidth.set.call(ctx, 1).