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.
Related
I can't seem to get a foreignObject to work from within an SVG pattern. I can get it to work on its own, but not in a pattern. I've had a quick look around:
its listed as a valid content element for a pattern in SVG 1.1 and SVG 2.0
Its used in this accepted answer
Something about not allowing foreignObject and svg:use, but I don't know if its relevant
so I'm at a loss really what I'm doing wrong. I've added a contrived snippet to reproduce below, but I'm specifically interested in arbitrary html in a foreignObject, in a pattern.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML inside SVG</title>
<style type="text/css"></style>
</head>
<body>
<svg width="500" height="300" style="border:1px red solid" xmlns="http://www.w3.org/2000/svg">
<!-- doesn't work -->
<pattern id=tex width=100 height=100>
<foreignObject x="0" y="0" width="100" height="100">
<img xmlns="http://www.w3.org/1999/xhtml" src="https://i.picsum.photos/id/258/200/200.jpg" x="0" y="0" width="100" height="100" />
</foreignObject>
</pattern>
<pattern id=tex2 width=100 height=100>
<circle fill=blue cx=50 cy=50 r=50 width=100 height=100></circle>
</pattern>
<!-- foreignObject on its own works -->
<foreignObject x="0" y="0" width="200" height="100">
<img xmlns="http://www.w3.org/1999/xhtml" src="https://i.picsum.photos/id/258/200/200.jpg" x="0" y="0" width="100" height="100" />
</foreignObject>
<!-- pattern with foreignObject doesn't work-->
<rect fill="url(#tex)" stroke="black" x=0 y=100 width="100" height="100"/>
<!-- basic pattern works-->
<rect fill="url(#tex2)" stroke="black" x=0 y=200 width="100" height="100"/>
</svg>
</body>
</html>
I’m afraid it looks like browsers don’t support this, even though the spec says it’s valid.
https://bugzilla-dev.allizom.org/show_bug.cgi?id=1348768
https://bugzilla-dev.allizom.org/show_bug.cgi?id=486240
Here’s another demo of the issue from 2014 codepen.io/yoksel/details/BidHq (SO won’t let me post the link without accompanying code, but the code is irrelevant in this case)
I don't know how to make rect element with 2-sided radius only, please find the exhibit:
<!DOCTYPE html>
<html>
<body>
<svg width="400" height="180">
<rect x="50" y="20" rx="1" ry="50" width="30" height="150" style="fill:red;stroke:black;stroke-width:5;opacity:0.5">
Sorry, your browser does not support inline SVG.
</svg>
</body>
</html>
Sorry if I'm not going about this the right way. I am trying to embed HTML within an SVG shape, and trying to center align the HTML with the shape.
Here is my code:
<svg xmlns = "http://www.w3.org/2000/svg" class="shape1" width="200" height="200" style="margin-top:-100px;">
<circle cx="100" cy="50" r="100" fill="white">
</circle>
<foreignObject x="0" y="80" width="100%" height="100%">
<body xmlns="http://www.w3.org/1999/xhtml">
<div>
<h3 style="font-family:'myriad Pro' ">HOME</h3>
</div>
</body>
</foreignObject>
</svg>
As it stands, I have to do it manually, but it does not seem to be consistent across Chrome and Firefox.
My code below is not working as expected. Not showing the image in the background of the rectangle.
<html>
<body>
<svg width="600" height="700">
<rect width="300" height="400" class="eq__NEcontainer__currentAlarmAction" style="fill:url(#godhelpme);">
<title stroke="blue">My test</title>
</rect>
<defs id="godhelpme">
<pattern width="200" height="200" x="0" y="0" patternUnits="userSpaceOnUse">
<image width="200" height="200" class="eq__NEcontainer__currentAlarmAction" xlink:href="CurrentList.png"></image>
</pattern>
</defs>
</svg>
</body>
</html>
The rectangle is always black as in the image. Any ideas ?. I have tried debugging using chrome. In the debugger clicking on the image tag shows empty. I have attached the images for reference.. Any help would be of greatly appreciated.
You cannot reference a <defs> element as the fill, you want the <pattern>. So put the id on the <pattern> element instead. Also in general you should aim to put your <defs> elements before where they're used, it's more efficient that way.
Like this:
<html>
<body>
<svg width="600" height="700">
<defs>
<pattern id="godhelpme" width="200" height="200" x="0" y="0"
patternUnits="userSpaceOnUse">
<image width="200" height="200"
class="eq__NEcontainer__currentAlarmAction"
xlink:href="CurrentList.png"></image>
</pattern>
</defs>
<rect width="300" height="400" class="eq__NEcontainer__currentAlarmAction"
style="fill:url(#godhelpme);">
<title stroke="blue">My test</title>
</rect>
</svg>
</body>
</html>
Is there a way - preferably without using JavaScript - to put some HTML contents into an SVG shape using foreignObject, such that the SVG shape will auto-resize (or scale) to fit its contents?
I.e. something very vaguely like this pseudocode example, but valid, and functional in the way I've described:
<?xml version="1.0" standalone="yes"?>
<svg xmlns = "http://www.w3.org/2000/svg">
<rect x="10" y="10" width="SCALE_TO_FIT_CONTENTS" height="SCALE_TO_FIT_CONTENTS" fill="gray">
<foreignobject width="100%" height="100%">
<body xmlns="http://www.w3.org/1999/xhtml">
<div>Some HTML text</div>
</body>
</foreignobject>
</rect>
</svg>
without using javascript, there is no possible way you could do that. In fact, the SVG shapes cannot be used as containers. But, I hope this is what you're asking for:
<script type="text/javascript">
function myFun(){
var w = document.getElementById("myDiv").scrollWidth;
document.getElementById("myRect").setAttribute("width",w);
}
</script>
<svg xmlns = "http://www.w3.org/2000/svg" onload="myFun()">
<rect id="myRect" x="10" y="10" width="0" height="100" fill="red"></rect>
<foreignObject x="10" y="10" position="absolute" width="100%" height="100%">
<div id="myDiv" style="display: inline-block;">Some HTML text that resizes its SVG container</div>
</foreignObject>
</svg>
A nice trick would be to wrap everything in a <g> element and then measure that element using getBBox() and then the height of the inner content is known, and could be used to modify the parent SVG element's height.
var svg = document.querySelector('svg');
var bbox = svg.firstElementChild.getBBox();
svg.setAttribute("height", bbox.height + "px");
<svg>
<g>
<rect x="10" y="10" width="100" height="200px" fill="red"></rect>
<foreignObject x="10" y="500" position="absolute" width="100%" height="100%">
<div id="myDiv" style="display: inline-block;">Some HTML text that resizes its SVG container</div>
</foreignObject>
<text dy='500'>aaaaaaaaa</text>
</g>
</svg>