views:

220

answers:

2

In the course of toying with SVG for the first time (using the Raphael library), I've run into a problem positioning dynamic elements on the canvas in such a way that they're completely contained within the canvas. What I'm trying to do is randomly position n words/short phrases.

Since the text is variable, its position needs to be variable as well so what I'm doing is:

  1. Initially creating the text at point 0,0 with no opacity.
  2. Checking the width of the drawn text element using text.getBBox().width.
  3. Setting a new x coordinate as Math.random() * (canvas_width - ( text_width/2 ) - pad).
  4. Altering the x coordinate of the text to the newly set value (text.attr( 'x', x ) ).
  5. Setting the opacity attribute of the text to 1.

I'll be the first to admit that my math acumen is limited, but this seems pretty straightforward. Somehow, I still end up with text running off beyond the right edge of my canvas. For simplicity above, I removed the bit that also sets a minimum x value by adding it to the Math.random() result. It is there, though, and I see the same problem on the leading edge of the canvas.

My understanding (such as it is), is that the Math.random() bits would generate a number between 0 and 1 which could then be multiplied by some number (in my case, the canvas width - half of the text width - some arbitrary padding) to get the outer bound. I'm dividing the width of the text in half because its position on the grid is set at its center.

I hope I've just been staring at this for too long, but is my math that rusty or am I misunderstanding something about the behavior of Math.random(), SVG, text or anything else that's under the hood of this solution?

+1  A: 

The answer turned out to be how I was thinking about the Math.random() equation. It's not quite as simple as multiplying by the max and then adding the minimum value (of course). It's really more like establishing a double wide gutter on the right end of the container and then shifting the entire boundary to eat up half of that gutter:

var x  = Math.random() * ( canvas_w - 20 - ( text.getBBox().width ) ) + ( text.getBBox().width/2 + 10 );

In English...

You have to double the width of each element you want to account for so you can shift the entire range back by that width to keep things nice and equal. In my case, I want to account for half of the width of the text plus a padding of 10.

For example...

Given a canvas width of 500, a text width of 50 and a desired "gutter" of 10, I create a random number between 0 and 430 (500 - 20 - 50). By adding back the widths I need to account for--half of the text width (25) + the padding (10)--I'm left with a random number between 35 and 465. If my text sits at the outer edges of that boundary, it can only reach as far as the 10 or 490.

Hopefully that's clear enough to make sense. Although it makes sense when I think about it, this kind of thing isn't immediately intuitive to me, so I'm sure I'll be referring back here often.

Rob Wilkerson
Nice job! Makes sense.
SB
A: 

I was thinking up an answer when I find you answered it yourself.

Heres something else you can do with text.

http://www.irunmywebsite.com/raphael/additionalhelp.html?q=rotatintextexactly

You might not be interested, but there is a database there with a small search engine that might help you more on this aor later projects.

Charles

Chasbeen