Is there a well-defined way to compute the x-coordinate of the right edge of an svg text element? - svg

Suppose I have the following text element, and it is left-aligned as below.
<text xml:space="preserve" text-anchor="start" y="134.799806172" x="450" >
Foo Bar</text>
Observe that text-anchor is start, so I am providing the x and y coordinates of the left edge.
Is there a well-defined way to compute the right edge of this text element?
To give some context, this element must be left-aligned because it has to line up with other elements on the left.
However, I want to have a different element that is center-aligned with this element, so I want to compute the right edge and thereby find the center.

You can use getBBox(), example:
var text = document.querySelector("text");
var bbox = text.getBBox();
bbox will be an object with width, height, x and y properties.

Related

How to draw a responsive SVG path with points on it?

I am trying to draw this SVG path.
I could achieve it using SVG Line and Curve properties for a fixed height and width using fixed coordinates.
But, I need to draw this responsively which means, the width of the path, space between the lines, the distance between each point, and the curves at the sides should be responsive.
It contains levels indicated by numbers as shown in the image, and the length of the path should be determined by the number of levels given.
While trying to draw this responsively, I was stuck at
Getting the start and end-point of the Lines
Getting control points for the curves
Responsive adjustment of the distance between each point and space between the curves
Determining the length of the path based on the number of levels given
I am trying to do these using percentages based on the parent div's width by some mathematical calculations. But, it seems it breaks some or other cases due to its complexity.
There are some other things to do along with these, but this is the top-level version of what needs to be done.
Is there any direct method or formula or calculation for achieving this?
(or)
Is there any other approach to draw this?
(or)
Are there any tutorials for learning to draw these types of SVG paths?
After creating the path you need to calculate the position of the numbers and circles on the path. For this you need to know the length of the path calculated with the getTotalLength() method. Next you need a loop to calculate the position of the numbers on the path. For this I've used the getPointAtLength()
method. On each of this pointd you create a new circle (use) element and a new text element.
Please read the comments in the code.
//constants used to create a new element in svg
const SVG_NS = "http://www.w3.org/2000/svg";
const SVG_XLINK = "http://www.w3.org/1999/xlink";
//the total length of the path
let length= thePath.getTotalLength();
//the number of points on the path
let n = 15;
let step = length/n;
for(let i= 1; i<=n; i++){
//creates a new point on the path at a given length
let point = thePath.getPointAtLength(i*step);
//create a new use element (or a circle) and set the center of the circle on the calculated point
let use = document.createElementNS(SVG_NS, 'use');
use.setAttributeNS(SVG_XLINK, 'xlink:href', '#gc');
use.setAttribute("x", point.x);
use.setAttribute("y", point.y);
//create a new text element on the same point. Thr text content is the i number
let text = document.createElementNS(SVG_NS, 'text');
text.setAttribute("x", point.x);
text.setAttribute("y", point.y);
text.textContent = i;
//append the 2 new created elements to the svg
svg.appendChild(use);
svg.appendChild(text);
}
svg {
border: solid;
}
text {
fill: black;
font-size: 4px;
text-anchor: middle;
dominant-baseline: middle;
}
<svg viewBox="0 0 100 80" id="svg">
<defs>
<g id="gc">
<circle fill="silver" r="3" />
</g>
</defs>
<path id="thePath" fill="none" stroke="black" d="M10,10H70A10,10 0 0 1 70,30H20A10,10 0 0 0 20,50H70A10,10 0 0 1 70,70H20" />
</svg>
Please observe that since the svg element has a viewBox attribute and no with it takes all the available width making it responsive.

How to calculate the y coordinate of a rectangle without transforms in Inkscape?

Imagine I have an Inkscape file with the following rectangle:
I want to calculate the Y coordinate reported by Inkscape (596.654).
How can I do it (manually) ?
I tried this:
The top of the page seems to have a Y coordinate of 744.
I subtract from that number the y coordinate of the rectangle in the XML editor (417) and its height (37) and get 744 - 417 - 37 = 290.
Note that the rectangle doesn't have any transforms and doesn't belong to a group.
Here's the simplified version of your SVG with only the relevant information included:
<svg width="297mm" height="210mm"
viewBox="0 0 1052.3622 744.09448">
<g transform="translate(0,-308.26772)">
<rect x="216.1537" y="417.34927"
width="385.25827" height="37.859257"
style="stroke-width:1;"
/>
</g>
</svg>
Despite what you thought, there is a transform in there (in the group).
SVG internal coordinates have their origin in the top left. Whereas Inkscape displays a converted value relative to the more normal origin at bottom left. The displayed value also takes into account the stroke width.
Your rectangle is drawn (internal coords) at
y = rectY + translateY
= 417.34927 - 308.26772
= 109.08155
The page has a height of 744.09448. So the displayed ccoordinate will be:
y = pageHeight - rectY - rectH - strokeWidth/2
= 744.09448 - 109.08155 - 37.859257 - 0.5
= 596.653673

How to add centered text with gm for node (graphicsmagick/imagemagick)?

This relates to the "gm" extension for node, http://aheckmann.github.io/gm/docs.html
I need to add some text centered around a bounding box (horizontally is enough). The function drawText() requires x,y coordinates, but there is no way to draw centered text.
I would otherwise need a function which can return the width of a text string in the font/size given, so I can calculate my starting x position in javascript, before calling drawText().
You can use the region and gravity functions this way:
gm(filePath)
.region(WIDTH, HEIGHT, X, Y)
.gravity('Center')
.fill(color)
.fontSize(textFontSize)
.font(font)
.drawText(0, 0, 'This text will be centered inside the region')

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);
}

Create native SVG <circle> elements from Illustrator/Gephi

I'm trying to add interactivity to a network graph I made in Gephi, which outputs SVG. I'm using a Raphael template that likes my nodes to be inputted as SVG circles. The problem is that my SVG circles from Gephi are actually bezier curves. For example:
<path fill="#D52A2A" d="M663.395,426.958c0-2.869-2.324-5.194-5.193-5.194s-5.191,2.325-5.191,5.194
c0,2.867,2.322,5.189,5.191,5.189C661.069,432.148,663.395,429.826,663.395,426.958"/>
Is there any way to convert a path like this to a standard SVG circle element with an x, y, and radius?
You could analyze the paths, but it's easier if you know which paths are circles to begin with, then you could do a quick approximation like this:
var p = document.querySelector("path");
var c = document.createElementNS("http://www.w3.org/2000/svg", "circle");
var b = p.getBBox();
c.cx.baseVal.value = b.x + b.width/2;
c.cy.baseVal.value = b.y + b.height/2;
c.r.baseVal.value = b.width/2; // assuming width and height are the same
p.parentNode.appendChild(c);
Hints that your path is a circle might be that the bbox width and height are very close to equal, or that the path 'd' attribute gephi outputs uses the same form always for circles (not sure if that's the case).
Gephi is opensource, so another option is to look at making it output what you want to begin with.
Update: here's a jsfiddle showing this.

Resources