Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The Matt Esch's example may work with only some (rectangular) elements, but to get metrics of all possible elements (and also in cases where element is affected by nested transformations of parent groups) we have to use an other approach. To get various metrics (width, height, bbox width, bbox height, corner coordinates, side lengths etc.) of whichever transformed SVG element I made a get_metrics()-function:</p> <p>Full functional example: <a href="http://output.jsbin.com/zuvuborehe/" rel="nofollow noreferrer">http://output.jsbin.com/zuvuborehe/</a></p> <p>The following image shows one possible use case of get_metrics():</p> <p><img src="https://i.stack.imgur.com/h5Fz1.png" alt="Metrics example"></p> <p>The function <code>get_metrics()</code> uses pure javascript, no libraries. But it can OC be used with libraries, like Raphaël. It is based on native <code>element1.getTransformToElement(element2)</code> which can get relation matrix between two elements, which are in this case the transformed element (eg. <code>&lt;path&gt;</code>) and SVG root element (<code>&lt;svg&gt;</code>). Of course you can use other elements also, like image, polygon, rectangle etc. By the way, the <code>getTransformToElement</code> is very powerful and versatile, it can be used eg. to flatten transforms of path consisting of whichever path commands ( even arcs if they are first converted to Cubics using Raphaël's path2curve) this way: <a href="http://jsbin.com/atidoh/9" rel="nofollow noreferrer">http://jsbin.com/atidoh/9</a>.</p> <pre><code>SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(elem) { return elem.getScreenCTM().inverse().multiply(this.getScreenCTM()); }; function get_metrics(el) { function pointToLineDist(A, B, P) { var nL = Math.sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)); return Math.abs((P.x - A.x) * (B.y - A.y) - (P.y - A.y) * (B.x - A.x)) / nL; } function dist(point1, point2) { var xs = 0, ys = 0; xs = point2.x - point1.x; xs = xs * xs; ys = point2.y - point1.y; ys = ys * ys; return Math.sqrt(xs + ys); } var b = el.getBBox(), objDOM = el, svgDOM = objDOM.ownerSVGElement; // Get the local to global matrix var matrix = svgDOM.getTransformToElement(objDOM).inverse(), oldp = [[b.x, b.y], [b.x + b.width, b.y], [b.x + b.width, b.y + b.height], [b.x, b.y + b.height]], pt, newp = [], obj = {}, i, pos = Number.POSITIVE_INFINITY, neg = Number.NEGATIVE_INFINITY, minX = pos, minY = pos, maxX = neg, maxY = neg; for (i = 0; i &lt; 4; i++) { pt = svgDOM.createSVGPoint(); pt.x = oldp[i][0]; pt.y = oldp[i][1]; newp[i] = pt.matrixTransform(matrix); if (newp[i].x &lt; minX) minX = newp[i].x; if (newp[i].y &lt; minY) minY = newp[i].y; if (newp[i].x &gt; maxX) maxX = newp[i].x; if (newp[i].y &gt; maxY) maxY = newp[i].y; } // The next refers to the transformed object itself, not bbox // newp[0] - newp[3] are the transformed object's corner // points in clockwise order starting from top left corner obj.newp = newp; // array of corner points obj.width = pointToLineDist(newp[1], newp[2], newp[0]) || 0; obj.height = pointToLineDist(newp[2], newp[3], newp[0]) || 0; obj.toplen = dist(newp[0], newp[1]); obj.rightlen = dist(newp[1], newp[2]); obj.bottomlen = dist(newp[2], newp[3]); obj.leftlen = dist(newp[3], newp[0]); // The next refers to the transformed object's bounding box obj.BBx = minX; obj.BBy = minY; obj.BBx2 = maxX; obj.BBy2 = maxY; obj.BBwidth = maxX - minX; obj.BBheight = maxY - minY; return obj; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload