famous-map
Version:
Map integration for Famo.us (google-maps, leaflet, open-layers & mapboxgl)
177 lines (153 loc) • 4.79 kB
JavaScript
/**
* This Source Code is licensed under the MIT license. If a copy of the
* MIT-license was not distributed with this file, You can obtain one at:
* http://opensource.org/licenses/mit-license.html.
*
* @author: Hein Rutjes (IjzerenHein)
* @license MIT
* @copyright Gloey Apps, 2014
*/
/**
* MapTransitions can transition between geographical positions using specific speed (e.g. 50 km/h).
*
* @module
*/
define(function(require, exports, module) {
'use strict';
// import dependencies
var MapUtility = require('./MapUtility');
/**
* @class
* @alias module:MapTransition
*/
function MapTransition() {
this.state = undefined;
this._startTime = 0;
this._startState = 0;
this._updateTime = 0;
this._endState = 0;
this._active = false;
this._duration = 0;
this._distance = 0;
this._callback = undefined;
}
MapTransition.SUPPORTS_MULTIPLE = 2;
/**
* @property DEFAULT_OPTIONS
* @protected
*/
MapTransition.DEFAULT_OPTIONS = {
/**
* The speed of the transition in mph.
*/
speed: 1000 // mph
};
// Interpolate: If a linear function f(0) = a, f(1) = b, then return f(t)
function _interpolate(a, b, t) {
return ((1 - t) * a) + (t * b);
}
function _clone(obj) {
return obj.slice(0);
}
/**
* Resets the position
*
* @param {Array.Number} state Array: [lat, lng]
*/
MapTransition.prototype.reset = function reset(state) {
if (this._callback) {
var callback = this._callback;
this._callback = undefined;
callback();
}
this.state = _clone(state);
this._startTime = 0;
this._updateTime = 0;
this._startState = this.state;
this._endState = this.state;
this._duration = 0;
this._distance = 0;
this._active = false;
};
/**
* Set the end position and transition, with optional callback on completion.
*
* @param {Array.Number} state Array: [lat,lng]
* @param {Object} [transition] Transition definition
* @param {Function} [callback] Callback
*/
MapTransition.prototype.set = function set(state, transition, callback) {
if (!transition) {
this.reset(state);
if (callback) {
callback();
}
return;
}
this._speed = MapTransition.DEFAULT_OPTIONS.speed;
if (transition && transition.speed) {
this._speed = transition.speed;
}
this._startState = this.get();
this._startTime = Date.now();
this._endState = _clone(state);
this._active = true;
this._callback = callback;
this._distance = MapUtility.distanceBetweenPositions(this._startState, this._endState);
this._duration = (this._distance / this._speed) * (60 * 60 * 1000);
//console.log('distance: ' + this._distance + ' km, speed: ' + transition.speed + 'km/h, duration:' + this._duration + ' ms');
};
/**
* Get the current position of the transition.
*
* @param {Date} [timestamp] Timestamp at which to get the position
* @return {Array.Number} Array: [lat, lng]
*/
MapTransition.prototype.get = function get(timestamp) {
if (!this._active) {
if (this._callback) {
var callback = this._callback;
this._callback = undefined;
callback();
}
return this.state;
}
if (!timestamp) {
timestamp = Date.now();
}
if (this._updateTime >= timestamp) {
return this.state;
}
this._updateTime = timestamp;
var timeSinceStart = timestamp - this._startTime;
if (timeSinceStart >= this._duration) {
this.state = this._endState;
this._active = false;
}
else if (timeSinceStart < 0) {
this.state = this._startState;
}
else {
var t = timeSinceStart / this._duration;
var lat = _interpolate(this._startState[0], this._endState[0], t);
var lng = _interpolate(this._startState[1], this._endState[1], t);
this.state = [lat, lng];
}
return this.state;
};
/**
* Detects whether a transition is in progress
*
* @return {Boolean}
*/
MapTransition.prototype.isActive = function isActive() {
return this._active;
};
/**
* Halt the transition
*/
MapTransition.prototype.halt = function halt() {
this.set(this.get());
};
module.exports = MapTransition;
});