Skip to content

January 10, 2013

5

How to scale complex SVG image with CompositeSprite in ExtJs 4.1

by Joe Kuan

Suppose you have created a complex SVG image using Ext.draw.CompositeSprite which contains a group of Sprite objects with the same group id. To translate the whole set from one position to another is easy. However, extra care is needed if you want to scale a CompositeSprite object.

The following is the original SVG (CompositeSprite object) displayed in ExtJs
port image

If you do the following:

compositeSprite.setAttributes({
    scale: {
       x: 0.5,
       y: 0.5
    }
}, true);

After calling setAttributes with half the scale, this will produce a corrupted SVG image as below:
corrupted scaled port image

As you can see, all the individual elements are correctly scaled BUT the distances between the elements are still the same. This is caused by the way we passed to setAttributes – with only x and y attributes. The setAttributes updates the SVG matrix transformation in the context of each SVG element’s own bounding box, not on the whole composite bounding box. In order to take the whole SVG image into account, you need to do the following:

var bbox = compositeSprite.getBBox();
compositeSprite.setAttributes({
    scale: {
       x: 0.5,
       y: 0.5,
       cx: bbox.x + bbox.width / 2,
       cy: bbox.y + bbox.height / 2
    }
}, true);

Note on using ExtJs 4.1 or earlier

There is currently a typo bug (which I submitted) in ExtJs 4.1 or earlier that stops the scale setting to work. You need to change the the scale method in Ext.draw.Surface class as the following highlighted lines:

    // @private
    scale: function(sprite) {
        var bbox,
            x = sprite.attr.scaling.x || 1,
            y = sprite.attr.scaling.y || 1,
            // centerX = sprite.attr.scaling.centerX,
            // centerY = sprite.attr.scaling.centerY;
            centerX = sprite.attr.scaling.cx,
            centerY = sprite.attr.scaling.cy;

        if (!Ext.isNumber(centerX) || !Ext.isNumber(centerY)) {

After all these changes, the scale setting works as expected:
Scaled port image

Advertisements
5 Comments Post a comment
  1. mirws
    Jan 22 2013

    I’m looking for extjs 4, svg image editor :)

    Reply
  2. Jacob Lauzier
    Jan 24 2013

    THANK YOU. I linked to this article in the Ext documentation. Hopefully, they’ll fix it soon.

    Reply
  3. Huw
    Mar 31 2013

    Useful info…I’m creating an expanded version of the Gauge chart that renders all sorts of analogue info…90, 180, 270, 360 axes, with custom needles, etc. I’ve been applying scale, rotate and transform to sprites and have noticed some ‘shifting’ that I’ve had to adjust for using the cx, cy config items.
    Are you building network/device management applications? I have done that in my day…used to love putting together those visual, interactive views of a device!

    Reply
    • Joe Kuan
      Mar 31 2013

      Thanks. Yes, I am building a drag & drop network management application with proper color gradient cable connected device and the color of the cables changes according to the volume of traffics.

      Reply
      • Huw
        Apr 2 2013

        After banging my head against the problem for a couple of hours (that included figuring out how to apply an override to Surface in a Cmd built project) I finally got my scaling working correctly. Thanks.

        Are your sprites defined with ‘unity’ coordinates, i.e. 0…1 scale to simplify scaling or do you use Sprite:getBBox() to tailor the scale values?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: