SVG - Inline position element after text - html

I want to position SVG several elements inline inside a single SVG.
I have the following:
<svg>
<g>
<use width="28" height="28"class="cls-11"></use>
<text id="policyRectText" transform="translate(50,20)" class="cls-54">Runs on a small number of endpoints</text>
<circle r="15" stroke-width="4" transform="translate(250,15)" class="cls-8"></circle>
</g>
</svg>
So to position an element before dynamic text is easy, but how can i position after it?

This is how I would do it:
First I'm putting the <text> in a <g> element since it's transformed and I need to get the bounding box:
let bb = theTransformedText.getBBox();
Once I have the position and the size of the text (bb) I'm using the data to set the cx and the cy attributes for the circle.
I've commented out the <use> element since it has no xlink:href attribute.
let bb = theTransformedText.getBBox();
let r = parseFloat(theCircle.getAttribute("r"));// the circle's radius.
let sw = parseFloat(theCircle.getAttribute("stroke-width"));// the stroke width
theCircle.setAttributeNS(null, "cx", bb.x + bb.width + r + sw/2);
// assuming that the font size is 16 you need to offset the circle half font size
theCircle.setAttributeNS(null, "cy", bb.y + 8);
<svg viewBox="0 -50 400 100">
<g>
<!--<use width="28" height="28"class="cls-11"></use>-->
<g id="theTransformedText">
<text id="policyRectText" transform="translate(50,20)" class="cls-54">Runs on a small number of endpoints</text>
</g>
<circle id="theCircle" r="15" stroke-width="4" class="cls-8"></circle>
</g>
</svg>

Related

How to animate an object with <img> tag move along a path?

I want to create an animation in which an object (in this case, the first blue line in the image https://i.stack.imgur.com/RDwQ2.png) move along an svg path. The line is provided in the form of PNG.
I tried using the tag but it's not changing anything.
Here is basically an example of what I wanted animate image on SVG Path.
Below is my code.
<svg height="238.158mm" viewbox="0 0 1920 900" width="508.071mm" xmlns="http://www.w3.org/2000/svg">
<path class="green-line" d="M 1.09,741.82
C 1.09,741.82 17.09,734.00 17.09,734.00
17.09,734.00 51.45,718.73 51.45,718.73
51.45,718.73 74.55,709.09 74.55,709.09
74.55,709.09 110.91,694.73 110.91,694.73
110.91,694.73 157.45,678.18 157.45,678.18
157.45,678.18 199.82,665.27 199.82,665.27
199.82,665.27 253.82,650.55 253.82,650.55
253.82,650.55 312.67,638.00 312.67,638.00
312.67,638.00 387.67,627.33 387.67,627.33
387.67,627.33 453.33,621.00 453.33,621.00
453.33,621.00 505.33,618.67 505.33,618.67
505.33,618.67 576.67,620.33 576.67,620.33
576.67,620.33 619.33,623.67 619.33,623.67
619.33,623.67 636.67,625.00 636.67,625.00
636.67,625.00 715.67,636.33 716.00,636.33
716.33,636.33 783.00,648.33 783.00,648.33
783.00,648.33 846.67,665.00 846.67,665.00
846.67,665.00 895.33,679.00 895.33,679.00
895.33,679.00 951.33,697.67 951.33,697.67
951.33,697.67 1026.00,723.33 1026.00,723.33
1026.00,723.33 1097.33,747.67 1097.33,747.67
1097.33,747.67 1176.67,776.00 1176.67,776.00
1176.67,776.00 1236.67,798.00 1236.67,798.00
1236.67,798.00 1265.00,807.67 1265.00,807.67
1265.00,807.67 1316.00,826.55 1316.00,826.55
1316.00,826.55 1351.64,837.27 1351.64,837.27
1351.64,837.27 1389.09,847.82 1389.09,847.82
1389.09,847.82 1429.45,858.36 1429.45,858.36
1429.45,858.36 1452.91,863.82 1452.91,863.82
1452.91,863.82 1470.81,868.06 1470.81,868.06
1470.81,868.06 1489.88,872.06 1489.88,872.06
1489.88,872.06 1503.88,874.25 1503.88,874.25
1503.88,874.25 1513.50,875.94 1513.50,875.94
1513.50,875.94 1533.44,879.31 1533.44,879.31
1533.44,879.31 1546.38,881.56 1546.38,881.56
1546.38,881.56 1556.19,883.00 1556.19,883.00
1556.19,883.00 1566.19,884.19 1566.19,884.19
1566.19,884.19 1596.69,887.69 1596.69,887.69
1596.69,887.69 1614.12,889.88 1614.12,889.88
1614.12,889.88 1633.06,891.12 1633.06,891.12
1633.06,891.12 1645.25,892.25 1645.25,892.25
1645.25,892.25 1682.62,895.06 1682.62,895.06
1682.62,895.06 1693.31,896.12 1693.31,896.12
1693.31,896.12 1707.22,897.04 1707.22,897.04
1707.22,897.04 1723.17,897.78 1723.17,897.78
1723.17,897.78 1729.09,898.22 1729.09,898.22
1729.09,898.22 1763.43,899.22 1763.43,899.22
1763.43,899.22 1768.74,899.48 1768.78,899.48
1768.83,899.48 1774.59,899.56 1774.59,899.56
1774.59,899.56 1778.34,899.88 1778.34,899.88
1778.34,899.88 1779.50,899.97 1779.50,899.97
1779.50,899.97 1793.39,899.91 1793.39,899.91
1793.39,899.91 1807.48,899.96 1807.48,899.96
1807.48,899.96 1817.13,900.00 1817.13,900.00
1817.13,900.00 1822.35,899.83 1822.43,899.87
1822.52,899.91 1884.73,899.91 1884.73,899.91
1884.73,899.91 1897.73,899.91 1897.73,899.91
1897.73,899.91 1918.64,900.27 1918.64,900.27
1918.64,900.27 1919.62,900.00 1919.62,900.00" id="animatePath" style="fill:none;stroke:none ;stroke-miterlimit:10;">
</path>
<image height="250px" id="car" width="1918px" x="0" xlink:href="/data/cms/images/1668585137_img-top-panel-curve.png" y="500">
<animatemotion begin="0s" dur="20s" repeatcount="indefinite" restart="whenNotActive" xlink:href="#car">
<mpath xlink:href="#animatePath">
</mpath>
</animatemotion>
</image>
</svg>
</div>

Stretching a complex SVG based on text within it

So I made an Illustrator SVG to work as a background of headers in a website I am designing. I am trying to find a way to dynamically resize this background SVG based on the text that is inside it. I have already used lengthAdjust="spacingAndGlyphs", however, some of the text that I input into it becomes rather squished if it is a longer line, and rather stretched if it is a shorter line of text. I have Googled for solutions for hours to no avail (I may have found a few solutions on other stack overflow pages, however, I cannot seem to get them to work in my case. Then again, I am new to svg in html pages, so maybe it is just my ignorance that is preventing me from understanding them). I am also open to other solutions that do not involve SVGs. Here it is, please let me know if you have any questions. I also made a CodePen project if you wish to mess around with the code: https://codepen.io/jZ00codeR/pen/VgywKJ
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 431.31 58.47" style="enable-background:new 0 0 431.31 58.47;" xml:space="preserve">
<style type="text/css">
.st0{fill:#005FB3;}
.st1{fill:none;}
.st2{fill:#FFFFFF;}
.st3{font-family:'neue-aachen-pro';font-weight:600;}
.st4{font-size:40.8839px;}
.st5{letter-spacing:-1;}
</style>
<g>
<path class="st0" d="M431.31,58.47L431.31,58.47c-143.6-9.99-287.71-9.99-431.31,0l0,0l19.76-17.44c10.02-7.32,10.02-16.27,0-23.59
L0,0l0,0c143.6,9.99,287.71,9.99,431.31,0l0,0l-19.76,17.44c-10.02,7.32-10.02,16.27,0,23.59L431.31,58.47z"/>
<rect x="27.04" y="6.33" class="st1" width="377.23" height="45.81"/>
<text transform="matrix(1 0 0 1 40.04 40.407)" class="st2 st3 st4 st5 changeHead" textLength="351.23" lengthAdjust="spacingAndGlyphs">This is the text that is getting squished.</text>
</g>
</svg>
I've made a few changes. The text is now centered around the center of the svg element.
I'm using javascript to calculate the length of the text and resize the text if it's wider than 350units. You may decide this maxim value of 350 in base of the width of the .st1 rect.
// the initial text size
let fontSize = 40;
txt.setAttribute("style", `font-size:${fontSize}px`);
// get the length of the text
let textLength = txt.getComputedTextLength();
while(textLength > 350){// where 350 is the max width allowed
fontSize --
txt.setAttribute("style", `font-size:${fontSize}px`);
textLength = txt.getComputedTextLength();
}
svg{border:1px solid}
text{font-family:'neue-aachen-pro';fill:#FFFFFF;}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 431.31 58.47" >
<style type="text/css">
.st0{fill:#005FB3;}
.st1{fill:none;}
</style>
<g>
<path class="st0" d="M431.31,58.47L431.31,58.47c-143.6-9.99-287.71-9.99-431.31,0l0,0l19.76-17.44c10.02-7.32,10.02-16.27,0-23.59
L0,0l0,0c143.6,9.99,287.71,9.99,431.31,0l0,0l-19.76,17.44c-10.02,7.32-10.02,16.27,0,23.59L431.31,58.47z"/>
<rect x="27.04" y="6.33" class="st1" width="377.23" height="45.81"/>
<text id="txt" dominant-baseline="middle" text-anchor="middle" x="215.655" y="29.235">This is the text, a very long text.</text>
</g>
</svg>
UPDATE
This is working on Edge and IE too:
Instead of dominant-baseline="middle" I'm using svg transform to translate the text in the center.
// the initial text size
var fontSize = 40;
txt.setAttribute("style", "font-size:"+fontSize+"px");
// get the length of the text
var textLength = txt.getBBox().width;
while(textLength > 350){// where 350 is the max width allowed
fontSize --
txt.setAttribute("style", "font-size:"+fontSize+"px");
txt.setAttributeNS(null,"transform", "translate(0,"+(fontSize/4)+")");
textLength = txt.getBBox().width;
}
svg{border:1px solid}
text{font-family:'neue-aachen-pro';fill:#FFFFFF;}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 431.31 58.47" >
<style type="text/css">
.st0{fill:#005FB3;}
.st1{fill:none;}
</style>
<g>
<path class="st0" d="M431.31,58.47L431.31,58.47c-143.6-9.99-287.71-9.99-431.31,0l0,0l19.76-17.44c10.02-7.32,10.02-16.27,0-23.59
L0,0l0,0c143.6,9.99,287.71,9.99,431.31,0l0,0l-19.76,17.44c-10.02,7.32-10.02,16.27,0,23.59L431.31,58.47z"/>
<rect x="27.04" y="6.33" class="st1" width="377.23" height="45.81"/>
<text id="txt" text-anchor="middle" x="215.655" y="29.235">This is the text, a very long text.</text>
</g>
</svg>

React - html tags inside svg

I am making circle menu, so I use SVG to create a circle, and now I want to show a link with some image inside of part of the circle. How i can do it? My code -
render(){
return(
<svg id={"menuLevel" + index} width={200} height={200}>
<path fill="white" stroke="rgba(0,0,0,0.2)" strokeWidth="2" d={"M"+width+","+width+" L"+previousX+", "+previousY+" A"+width+","+width+" 0 0,0 "+x+", "+y+" z"}></path>
</svg>
)
}
I tried something like this -
<path fill="white" stroke="rgba(0,0,0,0.2)" strokeWidth="2" d={"M"+width+","+width+" L"+previousX+", "+previousY+" A"+width+","+width+" 0 0,0 "+x+", "+y+" z"}>
<foreignobject x="120" y="120" width="180" height="180">
<Link ...><Image .../></Link>
</foreignobject>
</path>
But it doesn't work, this foreign object have still 0 width and 0 height and content doesn't show.
UPDATE
I need to assign link component to all path objects
<svg id={"menuLevel" + index} width={width*2+2} height={width*2+2}>
{arr.map(function(item){
let angleInRadians = -item * Math.PI / 180.0;
let previousX = x;
let previousY = y;
x = width + width * Math.cos(angleInRadians);
y = width + width * Math.sin(angleInRadians);
return(
<path fill="white" stroke="rgba(0,0,0,0.2)" strokeWidth="2" d={"M"+width+","+width+" L"+previousX+", "+previousY+" A"+width+","+width+" 0 0,0 "+x+", "+y+" z"}>
</path>
)
})}
</svg>
Please check it here JSFiddle. Use image element to add the image to SVG: https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/SVG_Image_Tag
<svg width="5cm" height="4cm" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
<circle x="0" y="0" r="200"></circle>
<image xlink:href="https://www.google.co.uk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" x="0" y="0" height="200px" width="200px"/>
</svg>
Please note:
If you do not set the x or y attributes, they will be set to 0.
If you do not set the height or width attributes, they will be set to 0.
Having a height or width attribute of 0 will disable rendering of the image.
Update 1
Here is a working example to add a React component together with the image: JSFiddle. But I make the Link component as a sibling of the SVG, and then using absolute to position them. Not a perfect solution.
Update 2
To make a path clickable: JSFiddle.
Update 3
This is an image with clickable paths, integrated with ReactJS: JSFiddle:
var Link = React.createClass({
render: function() {
return <a className="link" href={this.props.href} target="_blank">{this.props.children}</a>
}
});
var Hello = React.createClass({
render: function() {
return <div id="container"><svg xmlns="http://www.w3.org/2000/svg" width="300px" height="300px">
<Link href="http://www.google.com">
<g transform="translate(100, 100)"><image href="https://www.google.co.uk/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" x="0" y="0" height="200px" width="200px"/></g>
</Link>
<Link href="http://www.facebook.com">
<g><image href="https://www.facebook.com/images/fb_icon_325x325.png" x="0" y="0" height="100px" width="100px"/></g>
</Link>
</svg></div>
}
});

Align text to the middle of polygon, and border collapse in SVG

All,
Question 1:
I have been experienced difficulties in aligning text to the middle of the polygons in SVG, HTML.
There are a number of polygons. But, I only put 3 up for the easiness.
For each polygon, I have the points value for Xs and Ys.
Hence, It is possible to get an approximately average value of x and y, and use these values in "text" elements.
It is acceptable to align text to the SVG polygons if there are only a small number of them.
So I wonder if there is a SVG property, or any other way to align the text to the polygon automatically?
Such as text-align, or position: centre, which you don't have to calculate the x,y value, it will align to the middle of polygons?
Here is the JSFiddle:
http://jsfiddle.net/matildayipan/umb2fmuc/
HTML:
<svg height="503" width="900" fill="white" stroke="black" stroke-width="2">
<g id="Ashfield">
<polygon points="536,379 535,377 536,374 539,368 541,367 541,363 539,363 540,359 546,362 557,362 559,358 559,359 565,358 568,359 567,363 563,368 564,382 562,386 558,386 554,390 554,392 552,392 551,395 547,397 547,399 545,398 548,392 548,386 546,385 537,386 536,379"/>
<text data-brackets-id="152" x="536" y="380" style="font-size: 12px;"> Ashfield </text>
</g>
<g id="Auburn">
<polygon points="437,360 438,358, 437,345 441,337 441,331 439,329 439,326 441,320 452,318 455,317 457,314 468,312 472,304 483,304 483,306 485,307 488,307 493,302 499,304 493,311 493,315 496,316 497,318 496,321 497,324 501,325 501,334 496,339 490,342 486,340 482,341 480,347 480,349 482,349 479,350 479,353 486,363 484,364 482,371 467,377 451,378 447,373 445,373 443,370 441,370 439,367 436,366 437,360"/>
</g>
<g id="Bankstown">
<polygon points="403,430 405,428 405,425 399,418 399,405 402,405 404,403 404,400 397,394 397,390 393,389 393,383 394,382 399,383 402,372 405,369 406,365 408,364 413,353 421,360 423,360 436,370 438,370 438,372 443,374 451,381 468,380 478,375 480,375 481,380 485,380 486,378 489,377 485,402 489,404 494,404 488,406 486,413 478,422 468,425 467,430 461,431 461,443 462,449 464,450 464,469 467,472 468,476 462,477 456,481 443,483 441,487 438,489 438,491 430,490 430,486 426,486 422,490 420,486 424,483 424,481 417,475 417,473 414,470 406,469 406,464 408,463 407,457 404,455 399,455 395,446 391,445 394,442 393,432 395,432 397,429 399,431 403,430"/>
</g>
</svg>
As you can see, I use x, y to roughly align the text "Ashfield" to the polygon(Ashfield).
Question 2:
As it shows, the border of polygon "Auburn" and "Bankstown" are having a small gap in between. How can I merge them together to make it looks like a single border, just exactly like the map?
What you are looking for is text-anchor="middle".
http://www.w3.org/TR/SVG/text.html#TextAlignmentProperties
It will centre the text horizonatally on the point you specify. However there is no reliable way to center the text vertically, but using dy="0.5em" may be a reasonable approximation for you for a single line of text. You can tweak the dy amount to suit the font you are using and it should work for any font size.
<svg>
<circle cx="150" cy="75" r="5" fill="red"/>
<text x="150" y="75" text-anchor="middle" dy="0.5em"font-size="20">Here is some centred text</text>
</svg>

How to place two <g> side by side in an svg?

Hello all I am new to html5 and svg tag.I want to ask a question about svg html element.
Here is my code
<html>
<div>
<svg width = "1335" height = "400">
// I want to have two svg:g side by side one of more width and second of less width
such that width of svg = first g + second g
<g>
// All the elements inside g should have same width as g
</g>
<g>
</g>
</svg>
<div>
</html>
I have tried it using transform.But failed.
Is it possible to have two g elements side by side as I can't set x and y of g ?
Can any one guide me of doingthis another way.
You can use a transform, the problem then is how to get such values that make the transformed g at the right place. A possible way (the simplest, really) is to get the difference between coordinates of bounding boxes. Say you have a bounding box BB1 for group G1 and BB2 for G2, you could compute a translation to be applied to G2.
Of course we need a script to do that computation runtime. Such script will use
var BB1 = document.getElementById("G1").getBBox()
Here the code
<svg>
<script>
function align(evt) {
var G1 = document.getElementById("G1")
var G2 = document.getElementById("G2")
var BB1 = G1.getBBox()
var BB2 = G2.getBBox()
G2.setAttribute("transform", "translate("+ ((BB1.x+BB1.width)-BB2.x) + " " + ((BB1.y+BB1.height)-BB2.y) + ")")
}
</script>
<g id="G1">
<rect fill="red" x="10" y="10" width="40" height="30" />
</g>
<g id="G2" onclick="align(evt)">
<rect fill="blue" x="70" y="60" width="100" height="50" />
</g>
</svg>
you can experiment on jsFiddle with it
The <g> element doesn't have a position or a size, that's why you can't set x and y, it's just a logical container. Also SVG doesn't really have concept of layout in the same way as HTML does, which is what it looks like you're trying to achieve. If you want two elements next to each other, just draw them next to each other:
<svg width = "1335" height = "400">
<rect x="0" y="0" width="667" height="400" fill="#0f0"/>
<rect x="668" y="0" width="667" height="400" fill="#00f"/>
</svg>
If you just enclose each <g> in a separate SVG tag, and then close the set of SVG fragments within a <section> tag, the renderings with lay out just like images...flowing to the right and wrapping for me and my CSS--I can disect the CSS to figure out how/why if you really need that.
the simple example of how to do Irish flag by SVG
<!DOCTYPE html>
<html>
<body>
<h1>Irish Flag SVG image</h1>
<svg version="1.1"
baseprofile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<!--creating rect side by side for irish flag -->
<rect x="0" y="0" width="300" height="200" fill="green"/>
<rect x="100" y="0" width="300" height="400" fill="white"/>
<rect x="200" y="0" width="300" height="400" fill="orange"/>
</svg>
</body>
</html>