Jump to content

dragging problem on touch devices


dmko
 Share

Recommended Posts

Originally, I had a Sprite which I managed to drag around by something like the following:

1. Attaching pointerdown, pointermove, pointerup, pointeroutside

2. For movement- events pass InteractionData, which allows calling getLocalPosition(parent, pointHolder, interactionData.global);

3. Simply update the position to pointHolder

(there's a slight difference to my actual code where pointerdown also logs an offset which is added to the movements, and helpers/cleanup/etc. but we can ignore that for now)

This worked fine - but then I noticed that really fast movements all around tended to "lose" the object and it would stop tracking briefly. I could then duplicate it without crazy motions but the sort of use case that kids would definitely do.

So my new code took a different approach, which works perfectly on desktop but fails on the iPad:

1. only attach pointerdown to the sprite

2. when the sprite is touched:

  • start a ticker
  • add pointerup and pointerupoutside to renderer.plugins.interaction (this will kill the ticker and remove themselves)

3. while the ticker is ticking:

  • get the main InteractionManager from renderer.plugins.interaction
  • get the updated point via interactionManager.mouse.getLocalPosition(parent, pointHolder, interactionManager.mouse.global);
  • set the position to this

Clearly the reason this fails is because InteractionManager.mouse != touch. Is there a workaround for that?

Alternatively, is there a way to get a single global touch event, regardless of which object is active or even if no interactive objects were touched? (i.e. I could start the listener with the sprite pointerdown, but then track pointermove via a stage-wide listener to avoid the tracking problem above, even if there's no stage-sized interactive listener below it)

 

Link to comment
Share on other sites

n/m... seems InteractionManager itself will dispatch the events more reliably for some reason... I dunno why, but this approach seems to work better than just listening on the sprite itself - and it's cross-platform :)


Maybe this base class will help others too:
 

export class DragContainer extends PIXI.Container {
    private touchPoint: PIXI.Point = new PIXI.Point();
    private dragOffset:PIXI.Point = new PIXI.Point();

    //if listenerTarget is provided, then dragging only starts when that is touched (though this container itself is what moves)

    //screenLimit sets the boundries for draggable area

    constructor(private renderer: (PIXI.WebGLRenderer | PIXI.CanvasRenderer), listenerTarget?:PIXI.DisplayObject, public screenLimit?: PIXI.Rectangle) {
        super();

        if(listenerTarget === undefined) {
            listenerTarget = this;
        }

        listenerTarget.on('pointerdown', (iEvent:PIXI.interaction.InteractionEvent) => {
            
            this.clearListeners();
            this.updateTouchPoint(iEvent.data);
            this.dragOffset.x = this.x - this.touchPoint.x;
            this.dragOffset.y = this.y - this.touchPoint.y;
            renderer.plugins.interaction.on('pointermove', this.onDragMove, this);
            renderer.plugins.interaction.on('pointerup', this.onDragEnd, this);
            renderer.plugins.interaction.on('pointeroutside', this.onDragEnd, this);

            this.emit('dragStart');
        });        
    }

    onDragMove(iEvent:PIXI.interaction.InteractionEvent) {
        
        this.updateTouchPoint(iEvent.data);

        let targetX:number = this.touchPoint.x + this.dragOffset.x;
        let targetY:number = this.touchPoint.y + this.dragOffset.y;
        let allowMove:boolean = (this.screenLimit === undefined) ? true : this.screenLimit.contains(targetX, targetY);

        if(allowMove) {
            this.position.set(targetX, targetY);
            this.emit('dragMove');
        }
        
    }
    onDragEnd(iEvent:PIXI.interaction.InteractionEvent) {
        this.clearListeners();
        this.emit('dragEnd');
    }

    clearListeners() {
        this.renderer.plugins.interaction.off('pointermove', this.onDragMove, this);
        this.renderer.plugins.interaction.off('pointerup', this.onDragEnd, this);
        this.renderer.plugins.interaction.off('pointeroutside', this.onDragEnd, this);
    }

    updateTouchPoint(iData:PIXI.interaction.InteractionData) {
        iData.getLocalPosition(this.parent, this.touchPoint, iData.global);
    }
}

 

Edited by dmko
added screenLimit code
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...