Why is my canvas embedded in an inline SVG not updating?

497 views Asked by At

It seems like a contrived problem but I am trying to make a proof of concept of an HTML 5 document, containing inline SVG, which itself contains a <foreignObject> element with an HTML canvas inside. I then want to call a JavaScript function to draw on the canvas.

(How I got here: I want to use SVG as a format for defining an animated graphical view which can contain graphs, which are animated by replacing a dummy element in the SVG with a live graph using JavaScript / ECMAScript, and one of the JavaScript libraries we are considering to generate the graphs (Flot) uses an HTML canvas for the view, so I want to inject this canvas into the SVG view. A further complication is we ideally want this system to run on local files, on the file:// protocol, meaning we can't run scripts on external files (e.g. referenced with <object> or <iframe>) because browsers block them, hence the inline SVG.)

Here is an HTML source illustrating the problem:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Canvas Test</title>
    <script type="text/javascript">
      function draw_box() {
        var canvas = document.getElementById("box_canvas");
        var context = canvas.getContext("2d");
        context.fillRect(50, 20, 50, 60);
      }
    </script>
  </head>
  <body>
    <h1>Canvas Test
    <p>
    <svg width="400" viewBox="-10 -10 268 108">
      <rect style="fill: #a0a0a0" x="8" y="8" width="240" height="80" rx="40" ry="40"/>
      <g>
        <rect style="fill: #0000ff" x="0" y="0" width="240" height="80" rx="40" ry="40"/>
        <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke-linejoin: round; stroke: #000000" x="0" y="0" width="240" height="80" rx="40" ry="40"/>
        <foreignObject x="120" y="25" width="150" height="100">
          <canvas id="box_canvas" width="150" height="100" style="border:1px dotted;float:left">Canvas alt text</canvas>
        </foreignObject>
      </g>
    </svg>
    <p>
    <button type="button" onclick="draw_box();return false">Animate</button>
  </body>
</html>

The above page doesn't display the canvas at all in IE 11. In the latest version of Chrome it displays the canvas, but the effects of the JavaScript function called by the button - drawing the black box - only show up if you click on the SVG image.

What I need to know: 1) Is there something wrong with what I've written - e.g. am I missing some function call to make the SVG or foreignObject update after I have drawn on the canvas? 2) Is this a lost cause? Is the specification of <foreignObject> etc. immature enough that I could never be confident that this will work, even if we can control what browser the user views the document in? It's actually fine if this is the case because we can just say going forward that we need our graph library to generate SVG and not HTML.

Thanks a lot

0

There are 0 answers