Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scale and Registration Point #14

Closed
danielribeiro opened this issue Feb 14, 2011 · 16 comments
Closed

Scale and Registration Point #14

danielribeiro opened this issue Feb 14, 2011 · 16 comments

Comments

@danielribeiro
Copy link

Hi,

When using scale on simple geometric figures, like rectangles, with the registration point on a non-zero position, the actual image is off by a factor equal to (scale - 1) * (dimension / 2). Weirdly enough, when using shapes and graphics, the scale actually changes the position, making it "move away" from the screen.

Edit: the graphics can only be seen when you use the drawRect at , instead of using the x,y position of the shape. As expected.

Edit2: The showcase on the comment below.

@danielribeiro
Copy link
Author

I've created a project that showcases the problem: https://github.com/danielribeiro/EaselBugTracker

@danielribeiro
Copy link
Author

Ok, I ended up pushing a gh-pages of the project, so that you can see it wihout installing the project: http://danielribeiro.github.com/EaselBugTracker/

@gskinner
Copy link
Member

At a quick glance, it looks like your issue is that you are setting your regX/Y based on a transformed width/height, whereas regX/Y is measured in the object's local (untransformed) coordinates.

Ex. Your code is basically doing this:
foo.regX = fooHeight*foo.scaleX/2;

when it should be just doing this if you want it to have it's registration point centered:
foo.regX = fooHeight/2;

@danielribeiro
Copy link
Author

That's right. That was the problem. I've updated the project and its gh-pages showcasing the "solution. Thanks a lot.

@danielribeiro
Copy link
Author

Quick note: if the bitmap is inside a container, and the bitmap is scaled instead of the container, the position of the bitmap can't be 0,0, it must use the correction factor I gave: corr = (scale, w) -> (scale - 1)* (w / 2))

And the correction point must be applied to the x, y, not regX, regY.

It seemed weird that the correction would have to be applied at all.

Edit: The algorithm for scaling a component of a container, that I described above, is:

scaleComponent: function(displayObject) {
    displayObject.scaleX = this.scale;
    displayObject.scaleY = this.scale;
    displayObject.x = (1 - this.scale) * this.image.width / 2;
    (displayObject.y = (1- this.scale) * this.image.height / 2);
 }

@gskinner
Copy link
Member

gskinner commented Mar 1, 2011

Would it be possible to put together a simple example of this issue, so I can see what you are trying to achieve? I'm not 100% clear on the issue. Thanks!

@logotype
Copy link

logotype commented Mar 3, 2011

Hi

I've been trying to change the regX/Y while keeping the objects position (and scale/rotation). This is fine for the 1st point change as I simply can adjust the x/y position of the object. The problem is when I try to change the regX/Y the 2nd time, I don't really know how to "interpolate" the previous/current regX to keep the position the same.

I also tried to change the Matrix2D, but I don't know how to SET the matrix back to the object?

Also, another approach would be to get the bounds of the object to change the registration point that way, so getBounds() is very welcome for the next version.

Any ideas/suggestions would be very welcome! Thanks for the great work.
Victor

@logotype
Copy link

logotype commented Mar 3, 2011

Solved it.

var globalPoint = node.parent.localToGlobal( node.x, node.y );
var localPoint = holder.globalToLocal( globalPoint.x, globalPoint.y );

var previousRegX = holder.regX;
var previousRegY = holder.regY;

holder.regX = localPoint.x;
holder.regY = localPoint.y;

var matrix = new Matrix2D();
matrix.appendTransform( holder.x, holder.y, holder.scaleX, holder.scaleY, holder.rotation, holder.skewX, holder.skewY, -( localPoint.x - previousRegX ), -( localPoint.y - previousRegY ) );
matrix.decompose( holder );

@gskinner gskinner closed this as completed Aug 7, 2012
@Harbs
Copy link

Harbs commented Sep 25, 2015

I just encountered a very similar problem to this. The regX and regY seemed to be set correctly (to the middle of the object), but the fist time a new transformation was set to the object, it jumped up and to the left to a value equal to the regX and regY.

I also noticed that the cursor for the object appeared offest from the object by the same value.

My situation was also with a scaled bitmap inside a container.

I solved this (I'm not sure why it helped), but not setting the regX and regY until the first time the object was transformed.

@Harbs
Copy link

Harbs commented Sep 26, 2015

I spent some more time on this and it seems to me like something is wrong:

It appears that the only way to get things to behave correctly is to offset the container x and y properties by the same value as the regX and regY properties, otherwise, the image draws offset from where it should be.

Here's some code to illustrate the point. The code has the visual effect I need, but the object has the "wrong" x and y properties shifted to compensate the effects of setting regX and regY. Please note that setting scale and rotation has the same issues.

        function handleImageLoad(){
            canvas = document.getElementById("my-canvas");
            stage = new createjs.Stage(canvas);
            stage.enableMouseOver();
            container = new createjs.Container();
            container.initialX = 0;
            container.initialY = 0;

            var containerMatrix = new createjs.Matrix2D();

            containerMatrix.tx = 50;
            containerMatrix.ty = 40;
            var tVals = containerMatrix.decompose();
            container.setTransform(tVals.x,tVals.y,tVals.scaleX,tVals.scaleY,tVals.rotation,tVals.skewX,tVals.skewY);

            // img is a scope variable of the image loaded which triggered handleImageLoad
            bitmap = new createjs.Bitmap(img);
            imageBounds = new createjs.Rectangle(0,0,200,200)
            var xScale = imageBounds.width/img.width;
            var yScale = imageBounds.height/img.height;
            bitmap.scaleX = xScale;
            bitmap.scaleY = yScale;

            image = new createjs.Container();
            image.addChild(bitmap);
            // imageTransform is a variable of a Matrix2D which has the trasnform of the image within its container.
            imageTransform.decompose();
            container.addChild(image);
            stage.addChild(container);
            image.setTransform(tVals.x,tVals.y,tVals.scaleX,tVals.scaleY,tVals.rotation,tVals.skewX,tVals.skewY,bitmap.width/2,bitmap.height/2);
            image.cursor = "move";

            image.on("mousedown",function(evt){

                var pt = image.globalToLocal(evt.stageX,evt.stageY);
                var b = image.getBounds();

                var offX = (pt.x - (b.width/2));
                var offY = (pt.y - (b.height/2));
                var m = image.getMatrix().clone();
                m.tx = 0;
                m.ty = 0;
                var tp = m.transformPoint(offX,offY);
                image.mouseOffsetX = tp.x;
                image.mouseOffsetY = tp.y;
            });
            image.on("pressmove", function(evt) {

                // this is "wrong" because it's actually setting the x and y a value greater than what it should be equal to the regX and regY
                var pt = image.parent.globalToLocal(evt.stageX,evt.stageY);
                var currentX = pt.x - image.mouseOffsetX;
                var currentY = pt.y - image.mouseOffsetY;
                image.x = currentX;
                image.y = currentY;
                stage.update();   
            });
            //here's the wonky part. If I set the regX here without giving the "wrong" x and y, the image shifts out of place.
            var bounds = image.getBounds();
            image.regX = bounds.width/2;
            image.regY = bounds.height/2;
            image.x += image.regX;
            image.y += image.regY;
            stage.update();
        }

@Harbs
Copy link

Harbs commented Sep 26, 2015

Now I'm thinking that I just did not understand regX and regY. I see that getMatrix() returns the correct tx and ty values even though the x and y values are wrong.

I think the take-away here is that x and y are not properties you can rely on for the location of an object if regX and regY are set. The real location of an object seems to be x-regX,y-regY (or decomposing the matrix although the matrix does not seem to be stored in the object. It seems to be generated by getMatrix() so x-regX and y-regY probably has less overhead). A convenience getter for these would probably be nice.

For me coming from Flash this is all a bit of an adjustment.

@gskinner
Copy link
Member

The registration point in EaselJS is the point on which ALL transformations act, including translation. If you think about it in Flash terms, it is like moving the origin point of your symbol. This of course is not actually supported in Flash at run-time, but we thought it would be a handy feature in EaselJS.

It gets more confusing when you consider Flash authoring, which supports a transformation point that is independent of the origin point. However, it's important to note that this is an author-time only construct, and does not exist at run time.

You can absolutely work with Matrix2D directly, and apply it using myDisplayObject.transformMatrix = myMatrix. This will override any other transformations (ex. x/y/rotation/scale).

Hope that helps.

@Harbs
Copy link

Harbs commented Sep 27, 2015

Thanks. Yes. It is helpful.

It would be a nice idea to make it a bit clearer in the docs exactly what regX and regY actually do. I thought it was just a convenience property for "transform matrix around point" which is a bit complex to do in ActionScript.

You can absolutely work with Matrix2D directly, and apply it using myDisplayObject.transformMatrix = myMatrix. This will override any other transformations (ex. x/y/rotation/scale).

Somehow I missed this. Thanks. When this property is set does it remove the other properties or just overrides them? (i.e. if transformMatrix is then set back to null it will revert back to the old values)

@gskinner
Copy link
Member

I can take a look at the docs and see if there's a way to improve them.

Right, transformMatrix just overrides the transformation, causing the display list to ignore the other properties, it does not modify them at all.

@Harbs
Copy link

Harbs commented Sep 27, 2015

Here's a suggestion for the change. (There was an inconsitency in the doc between "left offset" and "y offset". I changed "y" to "top" to be consistent.)

    /**
     * The left offset for this display object's registration point. This offset applies to all matrix transformations
     * including tranlation. For example, to make a 100x100px Bitmap rotate around its center, you would set regX
     * and {{#crossLink "DisplayObject/regY:property"}}{{/crossLink}} to 50. To keep the horizontal position, the
     * {{#crossLink "DisplayObject/x:property"}}{{/crossLink}} should be set to -50.
     * @property regX
     * @type {Number}
     * @default 0
     **/
    this.regX = 0;

    /**
     * The top offset for this display object's registration point. This offset applies to all matrix transformations
     * including tranlation. For example, to make a 100x100px Bitmap rotate around its center, you would set
     * {{#crossLink "DisplayObject/regX:property"}}{{/crossLink}} and regY to 50. To keep the vertical position, the
     * {{#crossLink "DisplayObject/y:property"}}{{/crossLink}} should be set to -50.
     * @property regY
     * @type {Number}
     * @default 0
     **/
    this.regY = 0;

@wdamien
Copy link
Member

wdamien commented Sep 29, 2015

@Harbs Can you submit a pull request? It makes changes (even doc ones) easier to review / merge in. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants