diff --git a/lib/torque/animator.js b/lib/torque/animator.js index b83fbb6..263b5c9 100644 --- a/lib/torque/animator.js +++ b/lib/torque/animator.js @@ -26,31 +26,11 @@ maxDelta: 0.2, loop: true }); - - this.domain = invLinear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration); - this.range = linear(0, this.options.steps); - } - - - function clamp(a, b) { - return function(t) { - return Math.max(Math.min(t, b), a); - }; - } - - function invLinear(a, b) { - var c = clamp(0, 1.0); - return function(t) { - return c((t - a)/(b - a)); - }; - } - - function linear(a, b) { - var c = clamp(a, b); - return function(t) { - return c(a*(1.0 - t) + t*b); - }; + this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration); + this.domain = this.domainInv.invert(); + this.range = torque.math.linear(0, this.options.steps); + this.rangeInv = this.range.invert(); } @@ -76,6 +56,11 @@ } }, + step: function(s) { + if(arguments.length === 0) return this.range(this.domain(this._time)); + this._time = this.domainInv(this.rangeInv(s)); + }, + pause: function() { this.running = false; cancelAnimationFrame(this._tick); @@ -86,7 +71,7 @@ var delta = (t1 - this._t0)*0.001; // if delta is really big means the tab lost the focus // at some point, so limit delta change - delta = Math.min(this.options.maxDelta, delta) + delta = Math.min(this.options.maxDelta, delta); this._t0 = t1; this._time += delta; var t = this.range(this.domain(this._time)); diff --git a/lib/torque/gmaps/torque.js b/lib/torque/gmaps/torque.js index 7ee5287..8c49012 100644 --- a/lib/torque/gmaps/torque.js +++ b/lib/torque/gmaps/torque.js @@ -6,6 +6,7 @@ function GMapsTorqueLayer(options) { var self = this; this.key = 0; this.cartocss = null; + this.ready = false; this.options = _.extend({}, options); _.defaults(this.options, { provider: 'sql_api', @@ -40,8 +41,9 @@ function GMapsTorqueLayer(options) { * torque layer */ GMapsTorqueLayer.prototype = _.extend({}, - CanvasLayer.prototype, + CanvasLayer.prototype, torque.GMapsTileLoader.prototype, + torque.Event, { providers: { @@ -94,17 +96,6 @@ GMapsTorqueLayer.prototype = _.extend({}, var canvas = this.canvas; canvas.width = canvas.width; var ctx = canvas.getContext('2d'); - /* - ctx.fillStyle = 'white'; - var offset = this._map.getProjection().fromLatLngToPoint(this.getTopLeft()); - ctx.translate(-offset.x, -offset.y); - ctx.fillRect(0, 0, 100, 100); - - var a = document.getElementsByTagName('img'); - for(var i = 0; i < a.length; ++i) { - a[i].style.border = '1px solid red'; - } - */ // renders only a "frame" for(t in this._tiles) { @@ -122,20 +113,44 @@ GMapsTorqueLayer.prototype = _.extend({}, */ setKey: function(key) { this.key = key; + this.animator.step(key); this.redraw(); + this.fire('change:time', { time: this.getTime(), step: this.key }); }, /** * helper function, does the same than ``setKey`` but only * accepts scalars. */ - setTime: function(time) { + setStep: function(time) { if(time === undefined || time.length !== undefined) { throw new Error("setTime only accept scalars"); } this.setKey(time); }, + /** + * transform from animation step to Date object + * that contains the animation time + * + * ``step`` should be between 0 and ``steps - 1`` + */ + stepToTime: function(step) { + if (!this.provider) return 0; + var times = this.provider.getKeySpan(); + var time = times.start + (times.end - times.start)*(step/this.options.steps); + return new Date(time*1000); + }, + + /** + * returns the animation time defined by the data + * in the defined column. Date object + */ + getTime: function() { + return this.stepToTime(this.key); + }, + + /** * set the cartocss for the current renderer diff --git a/lib/torque/leaflet/leaflet_tileloader_mixin.js b/lib/torque/leaflet/leaflet_tileloader_mixin.js index 4acb420..995bceb 100644 --- a/lib/torque/leaflet/leaflet_tileloader_mixin.js +++ b/lib/torque/leaflet/leaflet_tileloader_mixin.js @@ -44,16 +44,18 @@ L.Mixin.TileLoader = { }, _removeOtherTiles: function (bounds) { - var kArr, x, y, key; + var kArr, x, y, z, key; + var zoom = this._map.getZoom(); for (key in this._tiles) { if (this._tiles.hasOwnProperty(key)) { kArr = key.split(':'); x = parseInt(kArr[0], 10); y = parseInt(kArr[1], 10); + z = parseInt(kArr[2], 10); // remove tile if it's out of bounds - if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { + if (zoom !== z || x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { this._removeTile(key); } } diff --git a/lib/torque/leaflet/torque.js b/lib/torque/leaflet/torque.js index 473c7a0..68ed548 100644 --- a/lib/torque/leaflet/torque.js +++ b/lib/torque/leaflet/torque.js @@ -3,7 +3,6 @@ */ L.TorqueLayer = L.CanvasLayer.extend({ - providers: { 'sql_api': torque.providers.json, 'url_template': torque.providers.jsonarray @@ -61,23 +60,11 @@ L.TorqueLayer = L.CanvasLayer.extend({ canvas.width = canvas.width; var ctx = canvas.getContext('2d'); - if(typeof this.key === 'number') { - // renders only a "frame" - for(t in this._tiles) { - tile = this._tiles[t]; - pos = this.getTilePos(tile.coord); - ctx.setTransform(1, 0, 0, 1, pos.x, pos.y); - this.renderer.renderTile(tile, this.key, pos.x, pos.y); - } - } else { - // accumulate more than one - for(t in this._tiles) { - tile = this._tiles[t]; - pos = this.getTilePos(tile.coord); - var accum = this.renderer.accumulate(tile, this.key); - ctx.setTransform(1, 0, 0, 1, pos.x, pos.y); - this.renderer.renderTileAccum(accum, 0, 0); - } + for(t in this._tiles) { + tile = this._tiles[t]; + pos = this.getTilePos(tile.coord); + ctx.setTransform(1, 0, 0, 1, pos.x, pos.y); + this.renderer.renderTile(tile, this.key, pos.x, pos.y); } }, @@ -89,20 +76,48 @@ L.TorqueLayer = L.CanvasLayer.extend({ */ setKey: function(key) { this.key = key; + this.animator.step(key); this.redraw(); + this.fire('change:time', { time: this.getTime(), step: this.key }); }, /** * helper function, does the same than ``setKey`` but only * accepts scalars. */ - setTime: function(time) { + setStep: function(time) { if(time === undefined || time.length !== undefined) { throw new Error("setTime only accept scalars"); } this.setKey(time); }, + /** + * transform from animation step to Date object + * that contains the animation time + * + * ``step`` should be between 0 and ``steps - 1`` + */ + stepToTime: function(step) { + var times = this.provider.getKeySpan(); + var time = times.start + (times.end - times.start)*(step/this.options.steps); + return new Date(time*1000); + }, + + /** + * returns the animation time defined by the data + * in the defined column. Date object + */ + getTime: function() { + return this.stepToTime(this.key); + }, + + /** + * returns an object with the start and end times + */ + getTimeSpan: function() { + var times = this.provider.getKeySpan(); + }, /** * set the cartocss for the current renderer @@ -116,6 +131,8 @@ L.TorqueLayer = L.CanvasLayer.extend({ }); +//_.extend(L.TorqueLayer.prototype, torque.Event); + L.TiledTorqueLayer = L.TileLayer.Canvas.extend({ diff --git a/lib/torque/provider.json.js b/lib/torque/provider.json.js index b73370b..23eac58 100644 --- a/lib/torque/provider.json.js +++ b/lib/torque/provider.json.js @@ -25,7 +25,7 @@ if (options.resolution === undefined ) throw new Error("resolution should be provided"); if (options.steps === undefined ) throw new Error("steps should be provided"); if(options.start === undefined) { - this.getKeySpan(); + this._fetchKeySpan(); } else { this._ready = true; } @@ -210,12 +210,21 @@ }); }, + getKeySpan: function() { + return { + start: this.options.start, + end: this.options.end, + step: this.options.step, + steps: this.options.steps + }; + }, + // // the data range could be set by the user though ``start`` // option. It can be fecthed from the table when the start // is not specified. // - getKeySpan: function() { + _fetchKeySpan: function() { var max_col, min_col, max_tmpl, min_tmpl; if (this.options.is_time){ @@ -233,13 +242,14 @@ max_col: max_col, min_col: min_col, table: this.options.table - }) + }); var self = this; this.sql(sql, function(data) { //TODO: manage bounds data = data.rows[0]; self.options.start = data.min; + self.options.end = data.max; self.options.step = (data.max - data.min)/self.options.steps; self._setReady(true); }, { parseJSON: true }); @@ -247,7 +257,7 @@ }; - torque.providers.json = json + torque.providers.json = json; })(typeof exports === "undefined" ? this : exports);