SVG: iframe renders outside of foreignObject - html

I have an iframe inside a foreignObject inside a g inside a svg, like in the following code:
<svg width="1024" height="1024">
<g transform="translate(240, 240)">
<foreignObject width="300px" height="200px">
<div
style="height: 200px; width: 300px; background-color: blue;"
/>
</foreignObject>
</g>
<g transform="translate(240, 240)">
<foreignObject width="300px" height="200px">
<iframe
width="300"
height="200"
src="https://www.openstreetmap.org/export/embed.html">
</iframe>
</foreignObject>
</g>
</svg>
I would expect the iframe to be rendered at the position specified by the parent g's transform the same way the div is, but instead it renders at the origin of the page.
Here is the same code on CodePen.
EDIT: I can see this happening on Chrome and Safari on Mac. It is working fine on Firefox.
How can I make the iframe render in the correct position?

Related

Nested SVG's width height set in % not working in chrome or edge

<div>
<div style="width:200px;height:70px">
<div style="width:100%;height:100%;">
<svg id="svg1" width="100%" height="90%">
<rect height="100%" width="100%" fill="#00001a"></rect>
<svg id="svg2" width="90%" height="10%" x="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
<svg id="svg3" width="90%" height="90%" x="10%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
<line x1="0%" x2="2700px" y1="25%" y2="25%" stroke="#aa001a"/>
</svg>
<svg id="svg4" width="10%" height="90%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
</svg>
</div>
</div>
</div>
I have some svg's i want to set the size of relative to their parent svg. I have set the size properties using height%/width% inline, and this works perfectly in firefox. Here's a simplified example of the code-structure that is rendered in both chrome and firefox(identical as-read), this code works as expected in chrome if you just open it in an html file:
<div>
<div style="width:200px;height:70px">
<div style="width:100%;height:100%;">
<svg id="svg1" width="100%" height="90%">
<rect height="100%" width="100%" fill="#00001a"></rect>
<svg id="svg2" width="90%" height="10%" x="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
<svg id="svg3" width="90%" height="90%" x="10%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
<svg id="svg4" width="10%" height="90%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
</svg>
</div>
</div>
</div>
However, when i run my project in chrome and edge it respects #svg3's x and y values, but the size is set a lot bigger, even bigger than body. The rect inside svg3 works as expected(only filling the given % size). I found these two questions:
SVG translate seems to behave different in Chrome/Chromium
nested svg ignores transformation in Chrome and Opera
They refer to transformations, not setting size. The weird part is that the rect inside svg3 only fills the space given(as expected), but the size of the actual svg when you inspect it is a lot bigger. I am using vuejs, but since the code that is rendered in the browser is as expected, and it works as intended in firefox i believe the problem isn't with vuejs.
Any help/tips would be appreciated.
EDIT:
I maybe could have stated it better but the code above runs fine for me(in chrome as well). The structure of the code is the same as when i inspect the original code in chrome. Here is an album of images showing what i am seeing in my project. The first and the last images are probably most important because it shows the rect with 100% width and height being correctly sized but the last image shows that the svg element is larger than that area.
https://imgur.com/a/ozJqEgB
EDIT 2:
I was able to find out what was causing my issues, it was a pretty simple mistake on my part where i had svg elements that we're being written bigger than the svg itself. Here is a edited version of the last example:
<div>
<div style="width:200px;height:70px">
<div style="width:100%;height:100%;">
<svg id="svg1" width="100%" height="90%">
<rect height="100%" width="100%" fill="#00001a"></rect>
<svg id="svg2" width="90%" height="10%" x="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
<svg id="svg3" width="90%" height="90%" x="10%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
<line x1="0%" x2="500px" y1="25%" y2="25%" stroke="#236ce0" />
<line x1="50%" x2="50%" y1="0%" y2="500px" stroke="#236ce0" />
</svg>
<svg id="svg4" width="10%" height="90%" y="10%">
<rect height="100%" width="100%" fill="#ff4d4d"></rect>
</svg>
</svg>
</div>
</div>
</div>
If you open this code in chrome/edge svg3 is a 500px by 500px square, while in firefox it is 180px by 56,7px. Is this inconsistency expected? This is a problem if you wan't to have click events that are relative to the SVG, as the size and top/left margins aren't the same across browsers.

video tag embedded in svg

I'm trying to embed a video inside an svg (the svg will only ever be viewed on the web). For that, I'm using the foreignObject tag:
<svg version="1.1" class="center-block" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="600"
style="border: 1px solid black;">
<g>
<g transform="translate(151,104) scale(1,1)">
<rect x="0" y="0" width="300" height="200"></rect>
<foreignObject x="0" y="0" width="300" height="200">
<video width="300" height="200" controls="" style="position: fixed; left: 151px; top: 104px;">
<source src="http://techslides.com/demos/sample-videos/small.mp4" type="video/mp4">
</video>
</foreignObject>
</g>
</g>
</svg>
It "works" in the sense that the video is displayed, but it's off by several pixels relative to its parent <g>. I tried several combinations: with style for the video, without styles, with namespaced video tag, etc. This works a lot better in firefox, but breaks completely in Chrome (Mac and Linux). I don't want to add an html tag outside the svg as this will be more hassle (the svg is created dynamically with React).
Has anyone been able to get something similar working?
There you go:
Translate moves the origin from the top left to the specified coordinates. If you embed an object at 0,0 it will be placed at the new origin. In this case you must embed it at -translation coordinates.
Even so, I had to increase the width and height. Why? I don't know. It doesn't seem to be a scale by 2. If someone knows I am curious to know.
<svg version="1.1" class="center-block" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="600" style="border: 1px solid black;">
<g>
<g transform="translate(151,104) scale(1,1)">
<rect x="0" y="0" width="300" height="200"></rect>
<foreignObject x="-151" y="-104" width="500" height="400">
<video xmlns="http://www.w3.org/1999/xhtml" width="300" height="200" controls="" style="position: fixed; left: 151px; top: 104px;">
<source src="http://techslides.com/demos/sample-videos/small.mp4" type="video/mp4" />
</video>
</foreignObject>
</g>
</g>
</svg>

SVG clippath not working with foreignObject in Chrome

I'm trying to get a video mask of some text, overlayed on top of another instance of video. I've achieved the desired effect in FF:
The Text overlay masking the an instance of the same video it is overlayed on top of. I used the following code to do this:
<video id="bkg" src="/locations.mp4" autoplay loop></video>
<svg class="svg" xmlns="http://www.w3.org/2000/svg">
<clippath id="cp-circle">
<text
text-anchor="middle"
x="50%"
y="98%"
>TEXT TEXT</text>
</clippath>
<g clip-path="url(#cp-circle)">
<foreignObject width="853" x="0"
y="0" height="480">
<body xmlns="http://www.w3.org/1999/xhtml">
<video id="bkg2" src="/locations.mp4" autoplay loop></video>
</body>
</foreignObject>
</g>
</svg>
<script>
document.getElementById("bkg").playbackRate = 0.8;
</script>
In Chrome this simply renders the two videos on top of each other, with no masking. Any idea why or if there is a workaround?
Chrome does not support SVG foreignObject correctly. WebKit bug (Filed). See http://svgdesign.guru for example.

Scaling svg image together with div

I'm trying to get svg image to scale nicely (http://coub.com/view/5tbis) with sibling div content so that they'd look like one thing. I managed to get it working in fireforx but not in chrome and ie, all latest versions. Here is my code:
<!DOCTYPE html>
<html>
<body>
<div style="display: flex; height: 10em;">
<div style="height: 100%">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="width: 100%; height: 100%; " viewBox="0 0 400 400">
<rect x="0" y="0" width="400" height="200" fill="yellow" stroke="black" />
<rect x="0" y="200" width="400" height="200" fill="green" stroke="black" />
<circle cx="200" cy="200" r="100" stroke="black" stroke-width="3" fill="red" />
</svg>
</div>
<div style="display: flex; flex-direction: column; width: 100%">
<div style="flex: 1; background-color: green"> </div>
<div style="flex: 1; background-color: yellow"> </div>
</div>
</div>
</body>
</html>
In IE and Chrome there is a blank space around svg and in Chome, svg proportions does not always match divs' ones.
Any help is highly appreciated.
UPDATE: ok, preserveAspectRatio="none" fixes the problem for ie and chrome, but I still don't understand why do they behave in this way? The wrapper div do not have width, why svg then doesn't change it according its own width?
UPDATE: preserveAspectRatio="xMidYMid slice" makes it even better, but only for ff and ie

HTML <div> inside SVG shape

Is it possible to put a div inside an svg shape?
Here's an example of what I'm trying to do:
<!DOCTYPE html>
<html>
<body xmlns="http://www.w3.org/1999/xhtml">
<svg id="main" xmlns="http://www.w3.org/2000/svg" version="1.1">
<foreignObject x="10" y="10" width="100" height="150">
<div>I'm a div in an svg</div>
</foreignObject>
<rect fill="red" stroke="darkred" class="box" x="90" y="90" rx="20" ry="20" width="320" height="320" id="box_0">
<foreignObject width="100" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<div>Hi, I'm a div inside a shape!! I don't work :(</div>
</body>
</foreignObject>
</rect>
</svg>
</body>
</html>
The second <div> doesn't show, is this somehow doable?
A <rect> element cannot have a <foreignObject> element as a child. You'd have to make the <foreignObject> element a later sibling and locate it on top of the rect element.