2
\$\begingroup\$

I'm looking for a mathematical formulae to calculate map scrolling inertia. Basically I have an HTML5 Canvas displaying part of a map and I capture the mousedown / mousemove / mouseup to calculate my new offset.

And when I scroll the map I want the map to continue scrolling for a few moments after the user stopped dragging the cursor.

I do have a sample implementation but I'm not really satisfied with it. I'd be looking for a nice clean math formulae to achieve this. I'd like my map to behave for example like in Civ-5 when you scroll the map around.

Here is part of my implementation: (working jsfiddle: https://jsfiddle.net/CowWarrior/dkxnj5d8/1/)

//mouseup
stopMapDrag: function (e) {
    var movementX = (e.pageX - this.startX);
    var movementY = (e.pageY - this.startY);
    this.mapOffsetX = parseInt(this.mapOffsetX) + movementX;
    this.mapOffsetY = parseInt(this.mapOffsetY) + movementY;
    this.isDragging = false;
    this.displayMap();      

    //calculate last vector
    ui.vectorX = parseInt(e.pageX - ui.absStartX);
    ui.vectorY = parseInt(e.pageY - ui.absStartY);

    //show inertia
    setTimeout(function(){ ui.dragInertia(2); }, 30);
    console.log("(vectorX:" + ui.vectorX + ", vectorY:" + ui.vectorY + ")");

    $('#canViewport').css('cursor', 'default');
},

//need to find a good formulae for inertia
dragInertia: function (factor) {
    var movementX = parseInt(ui.vectorX / factor);
    var movementY = parseInt(ui.vectorY / factor);
    ui.mapOffsetX = parseInt(ui.mapOffsetX + movementX);
    ui.mapOffsetY = parseInt(ui.mapOffsetY + movementY);
    ui.displayMap();

    if (factor < 8)
        setTimeout(function(){ ui.dragInertia(factor * 1.2); }, 30);
},
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Math.acos() solution

I have something very close to what I am looking for but I beleive there is an even better way of doing this.

I started by plotting a graph using Desmos. I was actually looking for a less steep curve at the beginning but I think this is close enough to what I'm looking for. In this representation the Y axis is the velocity and the X axis is the time. Map inertia graph

The full fiddle of my solution is here: https://jsfiddle.net/CowWarrior/kkodtxm9/23/

I ended up changing almost nothing of the mouseup event:

stopMapDrag: function (e) {
    [...]

    //show inertia
    setTimeout(function(){ ui.dragInertia(0); }, 50);
    console.log("(vectorX:" + ui.vectorX + ", vectorY:" + ui.vectorY + ")");

    $('#canViewport').css('cursor', 'default');
},

However my dragInertia function now look like this:

dragInertia: function (iteration) {
    var multiplier = Math.acos(iteration) * 0.33;
    var movementX = parseInt(ui.vectorX * multiplier);
    var movementY = parseInt(ui.vectorY * multiplier);
    ui.mapOffsetX = parseInt(ui.mapOffsetX + movementX);
    ui.mapOffsetY = parseInt(ui.mapOffsetY + movementY);       
    ui.displayMap();

    if (iteration < 0.9)
        setTimeout(function(){ ui.dragInertia(iteration + 0.1); }, 50);
},

Please submit your answers if you have something even better to propose. I'm somehow not entirely satisfied with what I want.

\$\endgroup\$
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .