How does one get the height/width of an SVG group element? - svg

I need to know the width and height of a SVG element? Im trying to use the following:
$('g#myGroup').height()
...but the result is always zero?

svg <g> elements don't have explicit height and width attributes, they auto size to whatever they contain. You can get their actual height/width by calling getBBox on the element though:
var height = document.getElementById("myGroup").getBBox().height;
If you're really into jquery you could write it as
$('g#myGroup').get(0).getBBox().height;
according to Reed Spool

I wasn't able to get any of the answers above to work, but did come across this solution for finding it with d3:
var height = d3.select('#myGroup').select('svg').node().getBBox().height;
var width = d3.select('#myGroup').select('svg').node().getBBox().width;
getBBox() here will find the actual width and height of the group element. Easy as that.

Based on the above answer, you can create jQuery functions .widthSVG() and .heightSVG()
/*
* .widthSVG(className)
* Get the current computed width for the first element in the set of matched SVG elements.
*/
$.fn.widthSVG = function(){
return ($(this).get(0)) ? $(this).get(0).getBBox().width : null;
};
/*
* .heightSVG(className)
* Get the current computed height for the first element in the set of matched SVG elements.
*/
$.fn.heightSVG = function(){
return ($(this).get(0)) ? $(this).get(0).getBBox().height : null;
};

Related

Constant stroke width rectangle with FabricJS

Is there any way to draw rectangles using FabricJs with constant width strokes?
On every example I could find, you can set the stroke width but when you resize the rectangle, the stroke is scaled together with the shape.
I'm late to the game here but I wanted to document this somewhere. The fiddle from davidtorroija (http://jsfiddle.net/davidtorroija/nawLjtn8/) shared in the above comment was nearly a perfect solution for me, but it has a big issue. Fabric uses values called "cacheWidth" and "cacheHeight", and without changing those as well, you can end up with some dodgy rendering not matching the specified height and widths:
Without changing the cached values:
https://i.gyazo.com/6cc1223444309cd55715bd81aa9dcb39.gif
With changing the cached values:
https://i.gyazo.com/e842b57af255460fcdbdc3533a6793e6.gif
Something like this should do the trick
// Existing code
this.width *= this.scaleX
this.height *= this.scaleY
// New code
this.cacheWidth = this.width
this.cacheHeight = this.height

Shape layer height = composition height in ExtendScript

I have a plugin that detects whether the pixel width or height of an object is greater.
It works great for other objects, but with shape layers, it just says the composition size.
My code is
pixelWidth = +currentLayer.width * +width / 100;
pixelHeight = +currentLayer.height * +height / 100;
Variables width and height are the scale property, and I make it apply the percentage of Scale property affect the outcome, so its the appearing scale.
Thanks
Well I guess your question is "How to get the width and height of a shape layer in After Effects?". Am I right? Why don't you say so. As you found out the width and height properties only return the width and height of the comp. For text and shape layers you need to use the sourceRectAtTime(timeT, extents) method. It will return an object like this {top, left, width, height} these are measured from the layers anchor.
var layer = app.project.activeItem.selectedLayers[0];
$.writeln(layer.width); // gives the comp width
$.writeln(layer.height);// gives the comp height
// from the After Effects Scripting Guide
// AVLayer sourceRectAtTime() method
// app.project.item(index).layer(index).sourceRectAtTime(timeT, extents) Description
// Retrieves the rectangle bounds of the layer at the specified time index,
// corrected for text or shape layer content.
// Use, for example, to write text that is properly aligned to the baseline.
/**
* sourceRectAtTime
* #param {Number} The time index, in seconds. A floating-point value.
* #param {Boolean} True to include the extents, false otherwise. Extents apply to shape layers, increasing the size of the layer bounds as necessary.
*
* #return {Object} A JavaScript object with four attributes, {top, left, width, height}.
*/
var bounds = layer.sourceRectAtTime(0, true);
$.writeln(bounds.toSource());

How do I use inches with snap svg?

I have just started playing around with snap and have been trying to work in inches instead of pixels, is this possible? If so how do I go about using inches? It seems that some functions accept inches and some don't?
// This works
var s = Snap("1.5in", "1.5in");
// This works
s.rect("0in", "0in", "1.5in", "1.5in").attr({
stroke: "#f00",
fill: "transparent"
});
// This works
s.path("M0,144L144,0").attr({
stroke: "#f00"
});
// This fails (Error: Invalid value for <path> attribute d="M0in,0inL1.5in,1.5in")
s.path("M0in,0inL1.5in,1.5in").attr({
stroke: "#f00"
});
As you've discovered, certain SVG values only accept raw numbers (interpretted as SVG user coordinates), not lengths with units. The path "d" attribute is one of those.
That is not a snap.svg issue, that's how the underlying SVG elements work.
The easiest approach would be to create for yourself a conversion factor. The initial value for SVG user coordinates is that 1 user unit equals one CSS "px" (pixel) unit. By CSS standards, a "px" unit is exactly equal to 1/96th of an "in" (inch) unit. If you scale your SVG with transforms or a viewBox attribute, all the length units scale accordingly, so the ratio remains constant.
Therefore, to create a path equivalent to "M0in,0inL1.5in,1.5in", you would multiply each number by 96 and then concatenate the string together:
s.path("M0,0L" + 1.5*96 + "," + 1.5*96).attr({
stroke: "#f00"
});
If you've got a long and complex path to create, it's worth mentioning that Array.join("") is more efficient than the + operator for joining a long list of strings and numbers into one string.
However, be aware that the CSS/SVG "in" unit won't always display on screen as exactly an inch. If you're printing the document, it should be pretty accurate. But of course, if you're scaling or transforming your SVG, it might not be anywhere close to an inch.

Proper way to calculate the height and width of a SVG text

I need to calculate the height and width of a svg text element. Is there a way to do so without actually adding it to the DOM of my page? I need only the measures not the actual element.
I am using neither d3 nor Raphael, but only plain JavaScript. (Maybe I should use one of the former for my calculations?)
What I am after is just a function like imagettfbbox in PHP, but in plain JavaScript. Is there such a thing? Or is it easy to write?
Since I am not actually using the text elements it seems strange to me to add them and hide them (I also have read somewhere that Firefox has problems with calculating the bbox of hidden elements, Calculating vertical height of a SVG text). But maybe this is the only way to go? Will I have to work with opacity in that case? Do I destroy the element somehow afterwards?
Maybe there is no good way to achieve exactly what I was after. However, giving up the "without actually adding it to the DOM of my page" part, the following function seems to achieve my goal.
function bboxText( svgDocument, string ) {
var data = svgDocument.createTextNode( string );
var svgElement = svgDocument.createElementNS( svgns, "text" );
svgElement.appendChild(data);
svgDocument.documentElement.appendChild( svgElement );
var bbox = svgElement.getBBox();
svgElement.parentNode.removeChild(svgElement);
return bbox;
}
Edit:
A note on the calculation of the height: the height of the bbox returned, i.e. bbox.height, is always the full height of the glyph, i.e. a will have the same height as A. And I could not find a way to calculate them more exactly.
However, one can calculate the height of uppercase accented characters, e.g. Ä. This will be just the negative of the y coordinate of the bbox, i.e. -bbox.y.
Using this one can calculate, for example, some coordinates for vertical alignment. For example to emulate the dominantBaseline attribute set to text-before-edge, text-after-edge, and central.
text-before-edge: dy = -bbox.y
text-after-edge: dy = -bbox.height -bbox.y
central: dy = -bbox.y -bbox.height/2
Where dy is the vertical translation. This can be used to get around limitations of some applications that do not support these alignments set by attributes.
I have encountered a similar problem in VB.Net !
I written a VB.Net program that generate a SVG file and that needs to compute width of text to compute next vertical bar position as you can see in following image
The B line vertical bar is positionned in computing max text width of A line elements.
To do that in Console VB.Net application, I execute following lines of code
Private Sub WriteTextInfo(sInfo As String)
If sInfo <> "" Then
'display Text in SVG file
sw.WriteLine("<text x ='" & (xPos + 10) & "' y='" & yPos & "' fill='black' font-family='Arial' font-size='20'>" & sInfo & "</text>")
'Create Font object as defined in <text> SVG tag
Dim font As New Font("Arial", 20.0F)
'Compute width of text in pixels
Dim xSize = TextRenderer.MeasureText(sInfo, font)
'Divide pixels witdh by a factor 1.4 to obtain SVG width !
Dim iWidth As Decimal = Math.Truncate(CDec(xSize.Width) / 1.4)
'If new vertical position is greater than old vertical position
If xPos + iWidth > xPosMax Then
xPosMax = xPos + iWidth
End If
End If
End Sub
In resume, I compute text's width in pixels using TextRenderer.MeasureText() function and I divide this number by 1.4 to obtain SVG width.
1.4 value is obtained by experiment relatively to my case !
To use TextRendered and Font objects, I have added reference to
System.Drawing
System.Windows.Forms
As you can see, I don't use any DOM method to compute text's width because I compute it in VB.Net program.

SVG Zoom and Pan

I have an SVG layout (from D3) of a tree. I have an SVG element in my HTML that takes up 100% of the width and height of the page. Then, within that SVG element, D3 renders a group element with a bunch of circles and lines in it. For example:
<svg style='width:100%;height:100%;'>
<g>
...stuff...
</g>
</svg>
I want to be able to zoom and pan so that a certain portion of the tree (group element) takes up the screen. I have the exact coordinates of the area I want to zoom in on, so ideally, I want to move the SVG element X pixels up and to the left, then scale the whole element by Y. How can I best do that?
From what I'm reading, the viewBox attribute is best for this, but I just can't figure out how I would be able to zoom in on just one portion. This example seems to get at what I want, but my SVG element is measured in percentages, not pixels. And even though the coordinate system is supposed to be arbitrary, I'm having a hard time converting between the two.
Here, I use this to zoom into certain regions of the SVG image. Change cx to the x coordinate, cy to the y coordinate, width and height are your call. The line you should be interested in is the svgDocument.setAttribute(...)
function zoomTarget1() {
var svgDocument = document.getElementsByTagName('svg')[0];
var cx = 20;
var cy = 20;
var width = 610;
svgDocument.setAttribute("viewBox", cx+" "+cy+" "+width+" 590");
var reShow = svgDocument.getElementById("FloorSelection");
showReturnButton(cx,cy, width, reShow);
}

Resources