The modern world dictates developers and designers fairly high standards of quality and ease of use of web applications. As a rule, a good impression of the application consists of many small things that should be harmoniously combined with each other. One of such trifles can be the inertial movement of “draggable” (draggable) objects on the page - we will talk about this in today's small article. The feature is especially relevant when the user interacts with the application via touch devices, since the screen size of such devices is limited, and you want to move an object from one point to another with one “flick of the wrist” and not multiple screen touches.
We once asked ourselves a similar question as part of developing
the 2GIS map API , and today we decided to share our modest experience.
Before considering the details of the implementation of inertia, let's take a look at the ready-made examples:
Ok, now to the point.
Experiment space
As a test example, add inertial movement to one of the mapping APIs that still do not have such a feature. Thus, we: a) learn something; b) inflict irreversible benefits on someone.
')
Let's look for such a “deprived” API.
Bing ,
google ? No, these guys are fine with dragging a card. Let's see how things are with
OpenLayers 3 . Yes, our “patient”, we will set up experiments on him.
Despite the youth of the “test subject”, the installation did not cause any difficulties, just like in the
documentation :

The source code of all html, js and css examples files can be found in the folder ol3 / examples.
Outline Algorithm
In fact, everything is quite simple.
Preparation for inertial movement:
- we catch the moment of the start of dragging the card and record the current time;
- we catch the moment of the end of dragging (the user released the mouse button) and at this moment:
- measure the duration of the drag (in ms.);
- measure the distance that was traveled along the X axis and along the Y axis (in pix.);
- read the speed of dragging the map on the X axis and on the Y axis (in pixels. per ms.):
- speed = distance / duration.
- we consider the initial pulse along the X axis and along the Y axis:
- impulse = mass * speed, where mass is just a constant.
- call the method that is responsible for the inertial movement of the card at the end of the drag, let's call it inertiaMove.
The inertiaMove method is called once a certain period (every 16 ms., For example). In this method we:
- we shift the center of the map by a pulse value along the X axis and along the Y axis;
- reduce the impulse by dividing it by the attenuation coefficient (constant);
- we check if the impulse has "rolled down" along the X axis and along the Y axis to a certain limit (also constant), if it has "rolled down", we stop the movement.

“Emergency” stop dragging. The card must forcibly stop moving in two cases:
- if the user clicked on the map;
- if the user has changed the scale of the map.
Code
Since OpenLayers 3 is made on the basis of the
Closure library , we will write code according to its rules.
Looking at the file structure, we will see that in the interactions catalog there are all objects that are responsible for interacting with the map. Among them is the
ol.interaction.DragPan object, which is responsible for dragging, we will create and inherit our
ol.interaction.DragPanInertia from it and implement the inertial motion of the map in it.
Also for convenience
, a polyfill implementation has
been added for the
Erik Möller requestAnimationFrame method.
As for the forced stopping of the movement of the card, this is done by a very simple subscription to the corresponding events:
var eventType = ol.BrowserFeature.HAS_TOUCH ? goog.events.EventType.TOUCHEND : goog.events.EventType.MOUSEDOWN;
In order for the map to start using the objects we have implemented, they must be registered in the
create.teractions method of the
ol.Map object.
First we hook up our implementation, replacing
goog.require('ol.interaction.DragPan');
on
goog.require('ol.interaction.DragPanInertia');
And then the string
interactions.push(new ol.interaction.DragPan(ol.interaction.condition.noModifierKeys));
replace with
interactions.push(new ol.interaction.DragPanInertia(ol.interaction.condition.noModifierKeys));
As you have probably noticed, the code implemented by us lies
on github , and, thanks to
github pages , you can
see in action an example of a map with inertia when moving. An example is best viewed in Google Chrome, since it has not been optimized for various browsers and devices, this is not the main purpose of the article. As for the OpenLayers 3 itself, the library is under active development and is not yet used in “combat” applications (there are problems when
working with touch devices , as well as with the
stability of the API itself ). Nevertheless, we wish developers time, inspiration and good pull requests into a project that is so useful to users.