Reputation: 87
I'm working on a project where i have to add Svg Text element dynamically using javascript with given width and height of text frame without getting disturbed the font ratio. I am unable to do that please help me.
Thanks in advance
function opacityValue() {
var opValue = document.getElementById("myRange").value;
document.getElementById("opacityValue").textContent = "(" + opValue / 100 + ")";
}
//
function txtOnFloor() {
var color = document.getElementById("clr").value;
var opacity = document.getElementById("myRange").value / 100;
var fontFamily = document.getElementById("family").value;
var svgs = document.getElementById("svgcontent");
var svg = svgs.getElementsByTagName("g")[0];
svg.innerHTML = "";
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
var g2 = document.createElementNS("http://www.w3.org/2000/svg", "g");
var rectNull = document.createElementNS("http://www.w3.org/2000/svg", "rect");
var svgText = document.createElementNS("http://www.w3.org/2000/svg", "text");
var svgTexttemp = document.getElementById("bg_svgtext").value;
var textWidth = svgTexttemp.length;
g.setAttribute("id", "gvr");
var textNode = document.createTextNode("" + svgTexttemp + "");
svgText.appendChild(textNode);
/////
var width1 = parseInt(document.getElementById("w1").value);
var width2 = document.getElementById("w2");
if (width2 != null && width2 != 0) {
width2 = parseInt(width2.value) / 100;
}
else {
width2 = 0;
}
var width = width1 + width2;
var depth1 = parseInt(document.getElementById("d1").value);
var depth2 = document.getElementById("d2");
if (depth2 != null && width2 != 0) {
depth2 = parseInt(width2.value) / 100;
}
else {
depth2 = 0;
}
var depth = depth1 + depth2;
var ratio = width / depth;
//
if (ratio > 1) {
for (var i = 1; i <= 100; i++) {
if (ratio >= i && ratio < i + 1) {
var fSize = (width / textWidth)*i;
svgText.setAttribute("font-size", fSize);
}
}
svgText.setAttribute("textLength", (fSize * textWidth) / ratio);
svgText.setAttribute("lengthAdjust", "spacingAndGlyphs");
}
else if (ratio <= 1) {
svgText.setAttribute("font-size", (width / textWidth)*2.3);
svgText.setAttribute("textLength", width);
svgText.setAttribute("lengthAdjust", "spacingAndGlyphs");
}
//
svgText.setAttribute("fill", "" + color + "");
svgText.setAttribute("opacity", "" + opacity + "");
if (fontFamily == "Fira Bold") {
svgText.setAttribute("font-family", "Fira");
svgText.setAttribute("font-weight", "bold");
}
else if (fontFamily == "Verdana Bold") {
svgText.setAttribute("font-family", "Verdana");
svgText.setAttribute("font-weight", "bold");
}
else if (fontFamily == "Arial Bold") {
svgText.setAttribute("font-family", "Arial");
svgText.setAttribute("font-weight", "bold");
}
else if (fontFamily == "Calibri Bold") {
svgText.setAttribute("font-family", "Calibri");
svgText.setAttribute("font-weight", "bold");
}
else {
svgText.setAttribute("font-family", "" + fontFamily + "");
}
//
svgText.setAttribute("x", "5");
svgText.setAttribute("y", depth);
svgText.setAttribute("id", "bg_txt");
//
debugger;
var textWidth = svgText.getAttribute("textLength");
var x = (width - textWidth)/2;
rectNull.setAttribute("x", x);
rectNull.setAttribute("y", "0");
rectNull.setAttribute("stroke", "null");
rectNull.setAttribute("fill", "none");
rectNull.setAttribute("height", depth);
rectNull.setAttribute("width", width);
//
g2.appendChild(rectNull);
g2.appendChild(svgText);
g.appendChild(g2);
svg.appendChild(g);
}
<div class="table table-bordered" id="btext" style="border:none;">
<div class="bTexts">
<span style="color:#000;font-size:15px; font-family:Helvetica">Text Value:</span><br />
<input type="text" id="bg_svgtext" placeholder="Enter your text value" value="Floor Plan" style="font-size:14px;height:16px; width:220px;margin-top:7px;font-family:Helvetica" />
</div>
<div>
<table style="margin-top:10px;color:#000;font-size:13px; font-weight:bold; font-family:Helvetica;">
<tr>
<td style="padding:0px; padding-right:22px;"><span style="">Width:</span></td>
<td style="padding:0px; padding-right:22px;"><input id="w1" type="text" name="width" value="100" style="width:30px;height:16px;" />m</td>
<td style="padding:0px; padding-right:22px;"><input id="w2" type="text" name="width" value="0" style="width:30px;height:16px;" />cm</td>
</tr>
<tr style="">
<td style="padding:0px; padding-right:22px;padding-top:8px;"><span style="">Depth:</span></td>
<td style="padding:0px; padding-right:22px;padding-top:8px;"><input id="d1" type="text" name="Depth" value="100" style="width:30px;height:16px;" />m</td>
<td style="padding:0px; padding-right:22px;padding-top:8px;"><input id="d2" type="text" name="Depth" value="0" style="width:30px;height:16px;" />cm</td>
</tr>
</table>
</div>
<div class="boothname" style="margin-bottom:10px;padding-left:0px;">
<span style="font-family: Helvetica; font-size:15px;">Font Settings</span>
</div>
<div>
<table style="color:#000;font-size:13px; width:210px; font-weight:bold; font-family:Helvetica;">
<tr>
<td><span style="padding-right:20px;">Font</span></td>
<td style="padding-left:60px;">
<select id="family" style="color:black; width:100px; height:23px; font-size:11px;padding: 2px 26px 2px 10px !important;background-position: calc(114% - 22px) calc(1em + 0px), calc(114% - 17px) calc(1em + 0px), 120% 0;" class="form-control classic ddldesign">
<option style="font-size:12px;" value="Fira">Fira</option>
<option style="font-size:12px;" value="Fira Bold">Fira Bold</option>
<option style="font-size:12px;" value="Verdana">Verdana</option>
<option style="font-size:12px;" value="Verdana Bold">Verdana Bold</option>
<option style="font-size:12px;" value="Calibri">Calibri</option>
<option style="font-size:12px;" value="Calibri Bold">Calibri Bold</option>
<option style="font-size:12px;" value="Arial">Arial</option>
<option style="font-size:12px;" value="Arial Bold">Arial Bold</option>
</select>
</td>
</tr>
<tr>
<td><span>Color</span></td>
<td style="padding-left:60px;"><input type="color" style="width:20px;" name="color" value="#046FAA" id="clr" /></td>
</tr>
<tr>
<td><span>Alpha</span></td>
<td style="padding-left:60px;">
<input type="range" oninput="opacityValue()" min="0" max="100" value="100" style="width:50px;float:left;" id="myRange">
<span id="opacityValue" style="margin-left:5px;">(1)</span>
</td>
</tr>
</table>
</div>
<div class="boothname" style="margin-bottom:10px;padding-left:0px;">
<div style="font-family: Helvetica; font-size:15px;">Click For Add To The Floor</div>
<div style="margin-left:85px; margin-top:5px;"><button class="btn" style="height:26px; padding: 5px 20px" onclick="txtOnFloor()">Add</button></div>
</div>
</div>
<div>
<svg id="svgcontent">
<g></g>
<g></g>
</svg>
</div>
I had tried a function on add button click but the font get disturbed.
How can I implement getBBox if it will work?
Upvotes: 0
Views: 1737
Reputation: 21811
To make the example clearer, I've shortened it to the relevant parts. The best strategy will be to let the browser do the sizing of the text for you. It will work for all aspect ratios, so the case distinction you made is not needed.
after it has been added to the document (so that it is actually rendered), get the size of its bounding box. For the .getBBox()
method for text elements
each glyph must be treated as a separate graphics element. The calculations must assume that all glyphs occupy the full glyph cell. The full glyph cell must have width equal to the horizontal advance and height equal to the EM box for horizontal text.
If you surround the <text>
element with a inner <svg>
element, you can define the viewBox
attribute to equal that bounding box. If the width and height attributes match your desired final size, the text will be automatically fitted. The preserveAspectRatio
attribute defines the exact rules for that fitting.
var width = 100, height = 100, text="Floor Plan";
var content = document.querySelector("#svgcontent");
// add a rect to visualize the target size
var rectNull = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rectNull.classList.add("booth-outline");
rectNull.setAttribute("width", width);
rectNull.setAttribute("height", height);
content.appendChild(rectNull);
// inner svg as a container for the text with sizing capabilities
var innerSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
innerSvg.classList.add("booth");
// target sizes
innerSvg.setAttribute("width", width);
innerSvg.setAttribute("height", height);
// position text content to the bottom left such that its size
// fills the target dimensions
innerSvg.setAttribute("preserveAspectRatio", "xMinYMax meet");
// text content
var svgText = document.createElementNS("http://www.w3.org/2000/svg", "text");
svgText.textContent = text;
innerSvg.appendChild(svgText);
// render
content.appendChild(innerSvg);
// and measure size
var box = svgText.getBBox();
// convert to viewBox attribute format
var viewBox = [box.x, box.y, box.width, box.height].join(" ");
innerSvg.setAttribute("viewBox", viewBox);
#svgcontent {
overflow: visible;
}
.booth-outline {
fill: none;
stroke: black;
}
.booth text {
font-family: serif;
font-size: 10px;
}
<svg id="svgcontent" width="250" height="250"></svg>
Upvotes: 2