Canvas in foreign object of svg doesn't apply the transformation

svg foreignobject alternative
foreignobject svg
react foreignobject
embed html in svg
foreignobject rendering
chartist foreignobject
foreignobjectrendering
foreign object mozilla

I have a problem with the use of a canvas in svg, using foreignObject.

The probleme is that the canvas is inserted in a group, which have a transformation (translation or rotation or scale), but the canvas isn't printed with the transformation.

I am on Chrome.

You can see my example there :

https://jsfiddle.net/Surre/qjrvxgos/

<body>
  <svg width="400px" height="300px" viewBox="0 0 400 300"
       xmlns="http://www.w3.org2000/svg">
       <g transform='translate(250,10)rotate(40)'>
         <foreignObject height="700" width="370" y="0" x="0">
             <span xmlns="http://www.w3.org/1999/xhtml">
             <canvas id="canvas" width="400px" height="300px" fill-style="#FF0000"></canvas>
             <div>Comment</div>
             </span>
         </foreignObject>
       </g>
  </svg>
</body>

The "Comment" has the good transformation, but the canvas hasn't. But if you use dev tools and inspect element canvas, you will see that it's like he is in the good place, with the transformation.

Hoping you can help me.

Thanks

From what I understand, this is actually a bug in chrome that's been known about since 2015 https://bugs.chromium.org/p/chromium/issues/detail?id=467484 There's talk of fixing it

I needed a solution too though, so here's what I've put together; I use the image element (which functions fine in svg) in conjunction with a hidden canvas. The system draws all it likes to the canvas, then transfers the canvas data to the image element.

imageElement.setAttribute('href',hiddenCanvas.toDataURL("image/png"));

It's an extra step, but it produces essentially the same result. In my project I've bundled this all together into an JS element maker

this.canvas = function(id=null, x=0, y=0, width=0, height=0, angle=0, res=1){
    var canvas = document.createElement('canvas');
        canvas.setAttribute('height',res*height);
        canvas.setAttribute('width',res*width);

    var image = document.createElementNS('http://www.w3.org/2000/svg','image');
        image.id = id;
        image.style = 'transform: translate('+x+'px,'+y+'px) scale('+1/res+') rotate('+angle+'rad)';
        image.setAttribute('height',height*res);
        image.setAttribute('width',width*res);

    return {
        element:image,
        canvas:canvas,
        context:canvas.getContext("2d"),
        c:function(a){return a*res;},
        print:function(){
            this.element.setAttribute('href',this.canvas.toDataURL("image/png"));
        }
    };
};

It's kinda clunky, but I think it's what you need. It also handles resolution with the 'res' argument, and the 'c' function (which you can use with any of the canvas drawing functions

canvas.context.fillRect(canvas.c(0), canvas.c(0), canvas.c(width), canvas.c(height));

SVG support: foreignObject node not visible · Issue #1325 , Issue Running the below test does not create the expected result. The canvas should show a green and red rectangle, but, only the green rectangle is visible. It looks like the foreignObject SVG tag is not taken into account. It does work well when this document is loaded directly or through an iframe etc. Expected results: The img should load, whatever the svg's container. Ps: (not sure if SVG is the right component since the bug seems to be in HTMLImage)

I think you neither rotate nor transform your canvas. If you want to rotate/transform it you can use CSS style. See the below code.

.transform {
    -ms-transform:translateX(200px) rotate(40deg) translateY(130px); /* IE 9 */
    -webkit-transform:translateX(200px) rotate(40deg) translateY(130px); /* Chrome, Safari, Opera */
    transform:translateX(200px) rotate(40deg) translateY(130px);
    background:#FF0000;
}

This css code will work on most of the browsers. You can use this class in your example like the following.

<canvas id="canvas" width="400px" height="300px"  class="transform"></canvas>

You can see on https://jsfiddle.net/qjrvxgos/3/ your example with my update.

Embedded Canvas in SVG, SVG with embedded Canvas Data extent x y -5 -4 -3 -2 -1 0 1 2 3 4 5 canvasDim.height); // add embedded body to foreign object var foBody  The canvas should show a green and red rectangle, but, only the green rectangle is visible. It looks like the foreignObject SVG tag is not taken into account. Can you plea

Canvas and SVG are different libraries, you can't use them together. You can convert one to another to do what you need. see the following link may it helps you http://www.inkfood.com/svg-to-canvas/ also you can do your example like the following example

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform='translate(250,10)rotate(40)'>
 <rect x="10" y="20" height="50" width="75"
      style="stroke: #ffff00; fill: #ff0000"/>
    <text x="10" y="90" style="stroke: #660000; fill: #ff0000">
    Comment</text>
</g>

Embedded Content, Except 'canvas' and 'foreignObject', embedded content is compatible with Unlike 'use', the 'image' element cannot reference elements within an SVG file. Scalable Vector Graphics (SVG) 2 The definition of '<foreignObject>' in that specification. Candidate Recommendation Scalable Vector Graphics (SVG) 1.1 (Second Edition) The definition of '<foreignObject>' in that specification. Recommendation: Initial definition

D3 can't create canvas element within SVG element / Steffen Kühne , Note: Appending the canvas directly to the parent SVG, without using foreignObject , doesn't work either. failure = Object {svg: R, node: "canvas"  SVG fragments in HTML5 embedding, without using a foreign object (that is, simply include an <svg> tag within your HTML) SVG as full document type (with .svg file extension) SVG in XML or XHTML (similar to the HTML5 method, only with XML or XHTML files) SVG as a CSS image.

What is the best way to overlay an SVG over a Canvas? - Help, However, it looks like that notebook doesn't actually have an SVG Apparently the case (canvas inside foreignObject) is not well defined in the  The viewBox is an attribute of the <svg> element. Its value is a list of four numbers, separated by whitespace or commas: x, y, width, height. The width is the width in user coordinates/px units, within the SVG code, that should be scaled to fill the width of the area into which you're drawing your SVG

<foreignObject>, The foreignObject SVG element includes elements from a different XML namespace. In the context of a browser, it is most likely (X)HTML. I'm having an issue with animating an HTML element nested inside an SVG with <foreignObject>. When the SVG is set to 100%, there's no problem, but when it's dimensions are scaled the <foreignObject> elements don't honour the resizing of the parent SVG when they're animated and act as if the SVG were set to 100%.

Comments
  • Sorry for that, I corrected it
  • Presumably a Chrome bug, why not report it to their bugtracker?
  • Question: why are you using a canvas element in your SVG at all? This looks like SVG as used in an HTML5 page, so a few things should be done here: 1) svg is part of HTML5, officially, so no XML namespaces. 2) same for all those other elements: no namespaces. 3) why not just put the canvas on the page itself instead of inside the SVG? What are you concretely trying to do here, because this is just a webpage, and it looks like you're using SVG to do things CSS can already do.
  • @Mike'Pomax'Kamermans only the SVGRoot node is in html namespace, all its children are in svg one. elements contained in a foreignObject that don't belong to the svg namespace need to have their own namespace declared, at the very least on all first parents nodes. But the svg root's xmlns declaration has a typo, could this cause the wrong behavior from chrome? I would be suprised about it, but if set, OP should set it correctly.
  • no, you miss the point. SVG is HTML5, there are no "namespaces" in HTML5, the <svg> element is a first class citizen like <p> or <div> and does not need namespacing, you just use it like any other HTML element. That also means you don't "escape" SVG namespacing for things like <span>. It's all just HTML elements.
  • I put the canvas in the group which have a transformation and want it to follow, like other objects in the group. When you open the dev tools, and inspect the canvas element, you can see that the canvas isn't where the tools show you. The tools show that it is translated ans rotated like it should be.
  • It's a member of a group of objects that have to apply somes transformations, it's why I prefer to avoid using css for only it.
  • Thank for the link, it could help, maybe. But in normal case we can use a canvas in svg with a foreign object. But how to deal with this bug I mentioned ?