Positioning SVG Elements
While playing with SVG for the first time (using the Raphael library, I ran into the problem of positioning dynamic elements on the canvas so that they are completely contained in the canvas. What I am trying to do is randomly position n words / short phrases.
Since the text is variable, its position must also be variable, so I do the following:
- Initially, we create text at a point
0,0
with no transparency. - Checking the width of a drawn text element with
text.getBBox().width
. - Setting the new coordinate
x
asMath.random() * (canvas_width - ( text_width/2 ) - pad)
. - Changing the text coordinate
x
for the newly set value (text.attr( 'x', x )
). - Setting the text opacity attribute to 1.
I'll be the first to admit that my mathematical grasp is limited, but it seems pretty straightforward. Either way, I am still getting text to go beyond the right edge of my canvas. For simplicity, above, I've removed the bit that also sets the minimum value x
by adding it to the result Math.random()
. It is there though, and I see the same issue at the foreground of the canvas.
My understanding (such as it is) is that the bit Math.random()
will generate a number between 0 and 1, which can then be multiplied by some number (in my case, the canvas width is half the text width - arbitrary padding) to get the outer border. I split the width of the text in half because its position on the grid is centered.
I hope I've been looking at this for too long, but is my math so rusty or am I missing something about behavior Math.random()
, SVG, text, or anything else that's under the hood of this solution?
a source to share
The answer turned out to be what I thought about the equation Math.random()
. It's not as easy as multiplying by max and then adding the minimum value (of course). It's more like creating a double wide gutter at the right end of the container, then offsetting the entire border to eat half of that gutter:
var x = Math.random() * ( canvas_w - 20 - ( text.getBBox().width ) ) + ( text.getBBox().width/2 + 10 );
In English...
You need to double the width of each element you want to account for, so you can slide the entire range back that width to keep everything nice and equal. In my case, I want to account for half the width of the text plus a space of 10.
For instance...
Given the width of the canvas 500
, the width of the text, 50
and the desired "gutter" 10
, I create a random number between 0
and 430
( 500 - 20 - 50
). By adding back the width I need to account for - half the width of the text ( 25
) + padding ( 10
). I was left with a random number between 35
and 465
. If my text sits on the outer borders of this border, it can only reach 10
or 490
.
Hopefully this is clear enough to make sense. While it makes sense when I think about it, such a thing is not immediately intuitive to me, so I'm sure I'll come back here often.
a source to share