1

I am in need of some math help. I am trying to dynamically transform my Raphael set of elements to a given bound box within my canvas.

For example, say my canvas (paper) is 600 x 300 and is filled with paths. These paths are all in a set.

Now I want fill my canvas with a given bound box. The bound box is in pixel coordinates. e.g. [[50,10], [100,20]]

So the end result would be a function call that would zoom and position the SVG elements. This would cause the canvas to be cropped to the coordinate bounds.

var bbox = [[50,10], [100,20]]
animateToBoundBox(set, bbox, duration);
function animateToBoundBox(set, bbox, duration) { /* beautiful code */ }

I think the way to accomplish this would be by using the element matrix but I'm not sure. What do you think the most elegant way of handling this would be?

Thanks

slth
  • 71
  • 1
  • 3

3 Answers3

1

The other answers are correct -- you want to use setViewBox.

Here's a version that supports animation. It's not entirely beautiful and you'll have to look at the page source to extract the code, but it should do more or less exactly what you want.

Here's the view box animation as a Raphael extension:

Raphael.fn.animateViewBox = function animateViewBox( x, y, w, h, duration, easing_function, callback )
{
    var cx = this._viewBox ? this._viewBox[0] : 0,
        dx = x - cx,
        cy = this._viewBox ? this._viewBox[1] : 0,
        dy = y - cy,
        cw = this._viewBox ? this._viewBox[2] : this.width,
        dw = w - cw,
        ch = this._viewBox ? this._viewBox[3] : this.height,
        dh = h - ch,
        self = this;;
    easing_function = easing_function || "linear";

    var interval = 25;
    var steps = duration / interval;
    var current_step = 0;
    var easing_formula = Raphael.easing_formulas[easing_function];

    var intervalID = setInterval( function()
        {
            var ratio = current_step / steps;
            self.setViewBox( cx + dx * easing_formula( ratio ),
                             cy + dy * easing_formula( ratio ),
                             cw + dw * easing_formula( ratio ),
                             ch + dh * easing_formula( ratio ), false );
            if ( current_step++ >= steps )
            {
                clearInterval( intervalID );
                callback && callback();
            }
        }, interval );
}

And the (not so beautiful) demonstration is here: http://voidblossom.com/tests/easedViewBox.php

If you're really bent on using transform (which could have a few benefits if leveraged well, but will in general be fragile compared to viewbox manipulation), there's another example using transform located at http://voidblossom.com/tests/zoomByTransform.php.

Kevin Nielsen
  • 4,413
  • 21
  • 26
  • This is cool. However, I think there should be a better way to handle this zoom than changing the viewbox. Check out this example done with D3: http://bl.ocks.org/2206590 I think transforming would be better for both performance and visuals. The svg vectors would hold their attribute properties. For instance, if you use the method above on some shapes with a stroke, the stroke will become larger or smaller just has if you were zooming in or out in photoshop. – slth Jan 31 '13 at 01:46
  • Very well. Check out the second example I added at the end of the question... and pardon its rough edges. – Kevin Nielsen Jan 31 '13 at 04:36
  • 1
    That's what I'm talking about! I'm happy that I inspired you to write some code. Nicely done. I'm going to play around with this and report back. My reasoning behind wanting to use the transform method was because I've had unexpected results in various versions of IE in the past when animating the viewBox. The animation was kind of jittery. Unfortunately the project I'm working on now is going to be used by quite a few IE users. I guess at the end of the day it's all just doing DOM manipulation on SVG attributes though. – slth Jan 31 '13 at 17:51
  • Ah, IE... for what it's worth, that D3 demo you posted performs a great deal better in Firefox than my Raphael equivalent. Not sure why, but if you happen to figure it out, I'd love to know what you found. – Kevin Nielsen Jan 31 '13 at 18:37
  • Hey, for whatever it's worth -- I am working on a project related to violent crime statistics and I decided to revisit the animated US map. How'd this turn out for you? Because my viewbox-based animation approach works a great deal better in Firefox. Did you ever get something together that made you happy? – Kevin Nielsen Feb 12 '13 at 04:25
0

Not sure if I completely understand what you are looking for, but it sounds like you want to zoom the view to a specific bounding box. Have you looked at the setViewBox function? Basically your function would call it like this:

setViewBox(bbox[0][0], bbox[0][1], bbox[1][0] - bbox[0][1], bbox[1][1] - bbox[0][0])
InvisibleBacon
  • 3,137
  • 26
  • 27
  • You are absolutely correct. It doesn't look like it supports animation but it works for me. Thank you! – slth Jan 30 '13 at 19:22
0

From what I can tell, everything you want to accomplish would be better handled with Paper.setViewBox() in an animation. See http://raphaeljs.com/reference.html#Paper.setViewBox

Plynx
  • 11,341
  • 3
  • 32
  • 33