Pixi.js: Sprite snaps to mouse at sprite anchor position on mousemove

Created on 23 Jun 2013  ·  5Comments  ·  Source: pixijs/pixi.js

  1. When dragging (mousemove), regardless of where on the sprite the mouse is placed, the sprite repositions itself such that the mouse pointer is now at the sprite's anchor position.
  2. For larger sprites, this shift is fairly jarring.
  3. It'd be nice to not require the mouse pointer to be at the anchor position. Internally, the anchor position must be maintained for calculations, etc. irrespective of mouse position on the sprite.
  4. Sample code and image attached. Notes on reproduction:

    • Code adapted and simplified from the dragging example in pixi.js (Example 8).

    • Download the image and rename to "aboriginal-bunny.png" as referenced in the code.

    • The bunny anchor point is set to 0.1, 0.1

    • Place the mouse cursor somewhere close to the bottom of the sprite, essentially anywhere far from the anchor point

    • On mousedown, the sprite's alpha changes, but everything else is the same, so the problem does not appear to be on mousedown.

    • Next, drag -- begin moving with mouse button down -- just slightly

    • Note the sudden shift of the sprite so the mouse is on its anchor point.

    • Henceforth, dragging is maintained with the mouse at this anchor.

<!DOCTYPE HTML>
<html>
<head>
    <!-- Shamelessly adapted from pixi.js Example 8 - Dragging -->
    <title>Sprite to Mouse Snapping issue</title>
    <script src="pixi.js"></script>
</head>
<body>
    <script>

    var stage = new PIXI.Stage(0x97c56e, true);
    var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight, null);

    // add the renderer view element to the DOM
    document.body.appendChild(renderer.view);
    renderer.view.style.position = "absolute";
    renderer.view.style.top = "0px";
    renderer.view.style.left = "0px";
    requestAnimFrame( animate );

    // create a texture from an image path
    var texture = PIXI.Texture.fromImage("aboriginal-bunny.png");

    createAboriginalBunny(100, 100);

    function createAboriginalBunny(x, y)
    {
        var bunny = new PIXI.Sprite(texture);
        bunny.setInteractive(true);

        // leaving anchor point at 10% to illustrate the problem clearer
        bunny.anchor.x = 0.1;
        bunny.anchor.y = 0.1;

        /*
         * Set-up dragging
         */     
        bunny.mousedown = bunny.touchstart = function(data)
        {
            this.data = data;
            this.alpha = 0.5;
            this.dragging = true;
        };

        bunny.mouseup = bunny.mouseupoutside = bunny.touchend = bunny.touchendoutside = function(data)
        {
            this.alpha = 1
            this.dragging = false;
            // set the interaction data to null
            this.data = null;
        };

        bunny.mousemove = bunny.touchmove = function(data)
        {
            if(this.dragging)
            {
                // need to get parent coords..
                var newPosition = this.data.getLocalPosition(this.parent);
                this.position.x = newPosition.x;
                this.position.y = newPosition.y;
            }
        }

        // move the sprite to initial pos
        bunny.position.x = x;
        bunny.position.y = y;

        stage.addChild(bunny);
    }

    function animate() {
        requestAnimFrame( animate );
        renderer.render(stage);
    }

    </script>

    </body>
</html>

aboriginal-bunny

Most helpful comment

First of all, thank you for the detailed bug report and the sample code, it helps a lot when we are given so much information!

Unfortunately, this is not a bug. This issue is caused by you setting the position of the sprite to the position of the mouse each mousemove (most likely because that is what the example does). Really, what should happen is you should update your sprite by the delta of the mouse movement. Try something like this:

        /*
         * Set-up dragging
         */     
        bunny.mousedown = bunny.touchstart = function(data)
        {
            this.data = data;
            this.alpha = 0.5;
            this.dragging = this.data.getLocalPosition(this.parent);;
        };

        bunny.mouseup = bunny.mouseupoutside = bunny.touchend = bunny.touchendoutside = function(data)
        {
            this.alpha = 1
            this.dragging = false;
            // set the interaction data to null
            this.data = null;
        };

        bunny.mousemove = bunny.touchmove = function(data)
        {
            if(this.dragging)
            {
                // need to get parent coords..
                var newPosition = this.data.getLocalPosition(this.parent);
                this.position.x += (newPosition.x - this.dragging.x);
                this.position.y += (newPosition.y - this.dragging.y);
                this.dragging = newPosition;
            }
        }

The important bits are on mousedown I store the location of the mouse, then on mousemove I update my sprite position by how much the mouse has _moved_ (not set it to the new position), then I update the stored mouse position for the next time. I hope this helps!

All 5 comments

First of all, thank you for the detailed bug report and the sample code, it helps a lot when we are given so much information!

Unfortunately, this is not a bug. This issue is caused by you setting the position of the sprite to the position of the mouse each mousemove (most likely because that is what the example does). Really, what should happen is you should update your sprite by the delta of the mouse movement. Try something like this:

        /*
         * Set-up dragging
         */     
        bunny.mousedown = bunny.touchstart = function(data)
        {
            this.data = data;
            this.alpha = 0.5;
            this.dragging = this.data.getLocalPosition(this.parent);;
        };

        bunny.mouseup = bunny.mouseupoutside = bunny.touchend = bunny.touchendoutside = function(data)
        {
            this.alpha = 1
            this.dragging = false;
            // set the interaction data to null
            this.data = null;
        };

        bunny.mousemove = bunny.touchmove = function(data)
        {
            if(this.dragging)
            {
                // need to get parent coords..
                var newPosition = this.data.getLocalPosition(this.parent);
                this.position.x += (newPosition.x - this.dragging.x);
                this.position.y += (newPosition.y - this.dragging.y);
                this.dragging = newPosition;
            }
        }

The important bits are on mousedown I store the location of the mouse, then on mousemove I update my sprite position by how much the mouse has _moved_ (not set it to the new position), then I update the stored mouse position for the next time. I hope this helps!

Hello,

This resolves my issue, and is much clearer to understand, thanks. And yes, my code is based on how the example works, so would be good if the example could be updated -- I recall having trouble understanding how it worked, guess it did not fully work. :P

A related question, is there strictly a need to set interaction data to null on mouseup?

I'm also still unclear when getLocalPosition is required, vs. just the current position.

PS. no worries re: bug report detail, least I could do. Thanks for providing the library. :)

The reason for getLocalPosition is to transform the absolute coords of the mouse event, into local relative coords that DisplayObjects use. Each DisplayObject's position is relative to its parent, so we take the absolute mouse coords and transform them to be relative to the parent with this.data.getLocalPosition(this.parent).

It is isn't particularly necessary to set this.data = null on mouseup. Really you should be able to just use the data param to each function, and not use this.data at all.

Thanks again for your help; pretty new to graphics libs, so getting to terms with various implementation choices. Appreciate the pixi devs taking the time to answer my questions in a timely manner.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lucap86 picture lucap86  ·  3Comments

Makio64 picture Makio64  ·  3Comments

st3v0 picture st3v0  ·  3Comments

finscn picture finscn  ·  3Comments

softshape picture softshape  ·  3Comments