chris loughnane
chris loughnane

Reputation: 2738

Scale SVG (Raphaël) paths from center on mouse hover

I'm trying to scale SVG paths on mouse hover but because I had to transform the paths as I add them to the paper it has made a mess of the result.

Please see: http://jsfiddle.net/chrisloughnane/Kc4q2/

The paths are added with this transform attribute:

transform: 'S2.5,2.5,0,0'

and on mouse in I animate with: this.animate({transform: 's2.9,2.9,0,0'}, 200);

and mouse out I restore with: this.animate({transform: 's2.5,2.5,0,0' }, 400, "bounce");

After checking around here I found people mentioned element.getBBox() and I tried this but I'm screwing up.

var center = this.getBBox();
var adjustx = center.width / 2 ;//+ center.x;
var adjusty = center.height / 2 ;//+ center.y;
adjustx = (1 - 3)*adjustx;
adjusty = (1 - 3)*adjusty;

Could anyone point out what I'm missing please?

Or recommend a good tool to resize the SVG paths to a new default. I've tried inkscape and http://svg-edit.googlecode.com/svn/branches/2.5.1/editor/svg-editor.html

tia

Upvotes: 0

Views: 1173

Answers (1)

Chris Wilson
Chris Wilson

Reputation: 6719

Dealing with transformations is my least favorite part of Raphael. It's possible I'm missing an obvious solution here, but here is how I fixed it:

  • get the bounding box before the original transformation, when the shape is drawn exactly as the path specifies.

  • Calculate the dx and dy difference between the center of the shape before and after the mouseover. if bbox is the original, pre-scaling bounding box, then for dx this would be 2.5 * (bbox.x + bbox.width / 2) - 2.9 (bbox.x + bbox.width / 2). This can obviously be reduced.

  • translate the magnified shape backward by these amounts.

In code:

    var obj = paper.path(paths[county].path);
    obj.bbox = obj.getBBox();
    obj.attr({ transform: 'S2.5,2.5,0,0' });

    obj.mouseover(function (e) {
        var dx = -0.4 * (this.bbox.x + this.bbox.width / 2);
        var dy = -0.4 * (this.bbox.y + this.bbox.height / 2);
        this.animate({ transform: 'S2.9,2.9,0,0T' + dx + ',' + dy}, 200);
    }).mouseout(function (e) {
        this.animate({ transform: 's2.5,2.5,0,0' }, 400, "bounce");
    });

Here's an updated fiddle for you. For reference, I have it drawing red and blue rectangles representing the pre- and post-mouseover bounding boxes -- a strategy I use whenever transformations are giving me dyspepsia. You'll want to remove them, naturally.

One other thing to remember: The actual center of an irregular shape is its center of mass, not the halfway point of its bounding box. (These two points are only the same if it's a perfectly symmetrical shape, which geographic boundaries rarely create.) For shapes like the state of Alaska, with lots of islands way off in the corner, this can make a center-based scaling look awkward.

If you wanted to get really fancy, you could try and calculate the center of mass for each shape. But I doubt you want to go there, and offhand these counties appear to have roughly even distribution of mass around the center.

Upvotes: 1

Related Questions