Merge branch 'master' into tile-size

Conflicts:
	lib/torque/renderer/point.js
This commit is contained in:
Raul Ochoa 2016-08-03 17:57:58 +02:00
commit f3e4a79529
10 changed files with 178 additions and 88 deletions

View File

@ -6,3 +6,5 @@ Torque.js is an efficient and stylish rendering method to animate your data. Tor
* [Getting Started with Torque.js](getting_started.md)
* [Torque API Methods](torque_api.md)
* [Advanced Interaction Methods](torque_interaction_methods.md)
* [Torque Time Slider](torque_time_slider.md)

View File

@ -1,6 +1,6 @@
# Getting Started
Although the most straightforward way to use Torque is through either the CartoDB Editor, or by passing the layer's viz.json to [CartoDB.js](http://docs.cartodb.com/cartodb-platform/cartodb-js/getting-started/), many use cases work best with the standalone [Torque.js](https://github.com/CartoDB/torque/tree/master/dist). Assuming you have a public dataset with a `date` column, it is really simple to create an animated map with the library. First, you need to have a Leaflet map prepared in an HTML page:
Although the most straightforward way to use Torque is through either the CARTO Editor, or by passing the layer's viz.json to [CARTO.js](https://carto.com/docs/carto-engine/carto-js/getting-started/), many use cases work best with the standalone [Torque.js](https://github.com/CartoDB/torque/tree/master/dist). Assuming you have a public dataset with a `date` column, it is really simple to create an animated map with the library. First, you need to have a Leaflet map prepared in an HTML page:
```html
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v0.7.7/leaflet.css" />
@ -15,7 +15,7 @@ Although the most straightforward way to use Torque is through either the CartoD
});
L.tileLayer('http://{s}.api.cartocdn.com/base-dark/{z}/{x}/{y}.png', {
attribution: 'CartoDB'
attribution: 'CARTO'
}).addTo(map);
</script>
</body>
@ -51,7 +51,7 @@ This HTML file automatically generates the Torque.js library, which includes any
</script>
```
You can use any kind of tile source outside CartoDB, by specifying the location of a [valid TileJSON](https://github.com/mapbox/tilejson-spec) file:
You can use any kind of tile source outside CARTO, by specifying the location of a [valid TileJSON](https://github.com/mapbox/tilejson-spec) file:
```javascript
var torqueLayer = new L.TorqueLayer({
@ -71,7 +71,7 @@ Optionally, it is also possible to use a custom SQL query for your visualization
});
```
Like in a video player, you can use animation control methods such as `play`, `stop` and `pause` at any point. Torque's animator fires a `change:time` event each time the animation "ticks" to the next frame, and there are a number of properties and methods that can be run during playback, which are detailed in the [API documentation](/cartodb-platform/torque/torqueapi/). At any point, for example, the styling of the layer's markers can be changed using the `layer.setCartoCSS('##style##')`.
Like in a video player, you can use animation control methods such as `play`, `stop` and `pause` at any point. Torque's animator fires a `change:time` event each time the animation "ticks" to the next frame, and there are a number of properties and methods that can be run during playback, which are detailed in the [API documentation](https://carto.com/docs/carto-engine/torque/torqueapi/). At any point, for example, the styling of the layer's markers can be changed using the `layer.setCartoCSS('##style##')`.
## Usage Examples
The best way to start learning about the library is by taking a look at some of the examples below:
@ -85,9 +85,9 @@ The best way to start learning about the library is by taking a look at some of
The following links contain examples, and other public information, about using Torque maps.
- Torque [CartoCSS Reference page](https://github.com/cartodb/torque-reference), useful for building parsers, tests, compilers, and syntax highlighting/checking
- CartoDB repository of [examples](https://github.com/CartoDB/torque/tree/master/examples)
- A CartoDB [time example](http://cartodb.github.com/torque/) of a Torque map and data
- CartoDB wiki page describing [how spatial aggregration works](https://github.com/CartoDB/torque/wiki/How-spatial-aggregation-works)
- CARTO repository of [examples](https://github.com/CartoDB/torque/tree/master/examples)
- A CARTO [time example](http://cartodb.github.com/torque/) of a Torque map and data
- CARTO wiki page describing [how spatial aggregration works](https://github.com/CartoDB/torque/wiki/How-spatial-aggregation-works)
- The [Guardian's Data Blog](http://www.guardian.co.uk/news/datablog/interactive/2012/oct/01/first-world-war-royal-navy-ships-mapped) about Royal Navy ships in WWI using a Torque map
- An example of how to create a [simple Torque visualization](https://github.com/CartoDB/torque#getting-started) and the [source code](https://github.com/CartoDB/torque/blob/master/examples/navy_leaflet.html) used to create the example
- An example of how to use CartoDB.js to [add a Torque layer from a named map with auth_tokens enabled](https://gist.github.com/chriswhong/a4d1e6305ecaf2ad507a)
- An example of how to use CARTO.js to [add a Torque layer from a named map with auth_tokens enabled](https://gist.github.com/chriswhong/a4d1e6305ecaf2ad507a)

View File

@ -28,12 +28,12 @@ attribution | Attribution to be added in the bottom right of the map
maxZoom | Maximum zoom for the layer.
tileSize | Size, in pixels of the tiles
##### Using a CartoDB table directly
##### Using a CARTO table directly
Name | Description
--- | ---
user | A string object, your CartoDB [account name](/cartodb-editor/your-account/#account). Default value is ```null```
table | A string object, the CartoDB table name where data is found (also known as a dataset.) Default value is ```null```
user | A string object, your CARTO [account name](/carto-editor/your-account/#account). Default value is ```null```
table | A string object, the CARTO table name where data is found (also known as a dataset.) Default value is ```null```
##### Using a custom SQL query
@ -62,7 +62,7 @@ Method | Options | Returns | Description |
`getTime()` | | current animation time (Date) | gets the real animation time
`isRunning()` | | `true`/`false` | describes whether the Torque layer is playing or is stopped
**Note:** Torque.js interprets the beginning and ending date/time from your "Time Column" as one block, then divides that up into [Steps](/cartodb-platform/cartocss/properties-for-torque/#torque-frame-count-number), depending on the number you set. It does not necessarily draw one frame for each row.
**Note:** Torque.js interprets the beginning and ending date/time from your "Time Column" as one block, then divides that up into [Steps](/carto-engine/cartocss/properties-for-torque/#torque-frame-count-number), depending on the number you set. It does not necessarily draw one frame for each row.
#### Layer Control Methods
@ -75,9 +75,9 @@ Method | Options | Returns | Description |
Method | Options | Returns | Description
---|---|---|---|
`setCartoCSS(cartocss)` | `cartocss string` | `this` | style the map rendering using client-side CartoCSS (not available with [Named maps](/cartodb-platform/maps-api/named-maps/))
`setCartoCSS(cartocss)` | `cartocss string` | `this` | style the map rendering using client-side CartoCSS (not available with [Named maps](/carto-engine/maps-api/named-maps/))
Torque supports a limited subset of CartoCSS rules defined in the [torque-reference](https://github.com/cartodb/torque-reference). To see the full list of supported rules, read the [Torque CartoCSS documentation](/cartodb-platform/cartocss/properties-for-torque/). `value` and `zoom` variables can be used. `value` is the value of aggregation. `zoom` is the current zoom being rendered.
Torque supports a limited subset of CartoCSS rules defined in the [torque-reference](https://github.com/cartodb/torque-reference). To see the full list of supported rules, read the [Torque CartoCSS documentation](/carto-engine/cartocss/properties-for-torque/). `value` and `zoom` variables can be used. `value` is the value of aggregation. `zoom` is the current zoom being rendered.
TorqueLayer currently expects `marker` styling.

View File

@ -29,7 +29,7 @@ This layer source object is used for Torque maps. Note that it does not allow su
Used to create an animated torque layer with customized settings.
```javascript
// initialize a torque layer that uses the CartoDB account details and SQL API to pull in data
// initialize a torque layer that uses the CARTO account details and SQL API to pull in data
var torqueLayer = new L.TorqueLayer({
user : 'viz2',
table : 'ow',
@ -120,7 +120,7 @@ var map = new L.Map('map', {
zoom: 3
});
L.tileLayer('http://{s}.api.cartocdn.com/base-dark/{z}/{x}/{y}.png', {
attribution: 'CartoDB'
attribution: 'CARTO'
}).addTo(map);
var torqueLayer = new L.TorqueLayer({
user : 'viz2',

View File

@ -1,25 +1,25 @@
# Torque Time Slider
You can use the `time_slider` option to show an animated time slider with Torque layers. This option is enabled by default when creating visualizations with [cartodb.createVis](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#cartodbcreatevis) and [createLayer](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#cartodbcreatelayermap-layersource--options--callback). Both require a map_id DOM object.
You can use the `time_slider` option to show an animated time slider with Torque layers. This option is enabled by default when creating visualizations with [cartodb.createVis](http://docs.carto.com/carto-engine/carto-js/api-methods/#cartodbcreatevis) and [createLayer](http://docs.carto.com/carto-engine/carto-js/api-methods/#cartodbcreatelayermap-layersource--options--callback). Both require a map_id DOM object.
**Enable / Disable the Torque Time Slider**
Description | The Torque time slider is enabled by default, for your visualization or layer.
Sample Torque.js Code | `{ time_slider: true });`
Default Value | `true`, enabled by default.
Available Values | See [boolean](http://docs.cartodb.com/cartodb-platform/cartocss/properties/#boolean).
Available Values | See [boolean](http://docs.carto.com/carto-engine/cartocss/properties/#boolean).
Related Examples | To disable the time slider option, use `time_slider: false`. See [No Torque Time Slider - Example Code](http://bl.ocks.org/michellechandra/081ca7160a8c782266d2).<br/><br/>For a code example about how to use the `time_slider` option to modify a Torque map, see [Torque with a Custom Time Slider](http://bl.ocks.org/csobier/cebdd47242d7ca98ec5e).
**Note:** The `time_slider` option is specific for Torque.js only. All the other CartoDB.js options are also supported for Torque.js. For the complete list of arguments, options, and returns, see [CartoDB.js API Methods](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#api-methods).
**Note:** The `time_slider` option is specific for Torque.js only. All the other CARTO.js options are also supported for Torque.js. For the complete list of arguments, options, and returns, see [CARTO.js API Methods](http://docs.carto.com/carto-engine/carto-js/api-methods/#api-methods).
## Customize Animation for your Time Slider
You can customize the animation of your Torque time slider by editing the `-torque-frame-count` and `-torque-animation-duration` CartoCSS properties. (Optionally, you can create a [CartoDB.js](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#api-methods) map to create a custom time slider). This section also describes how time interval data is aggregated, and describes the formula used to calculate time buckets.
You can customize the animation of your Torque time slider by editing the `-torque-frame-count` and `-torque-animation-duration` CartoCSS properties. (Optionally, you can create a [CARTO.js](http://docs.carto.com/carto-engine/carto-js/api-methods/#api-methods) map to create a custom time slider). This section also describes how time interval data is aggregated, and describes the formula used to calculate time buckets.
- [`-torque-frame-count`](http://docs.cartodb.com/cartodb-platform/cartocss/properties-for-torque/#torque-frame-count-number) specifies the number of animation steps/frames in your torque animation. You can change the time slider timestamp by adjusting the number of steps.<br /><br />**Tip:** This is the _Steps_ option from the [Torque wizard](/cartodb-editor/maps/#torque) of the CartDB Editor.
- [`-torque-frame-count`](http://docs.carto.com/carto-engine/cartocss/properties-for-torque/#torque-frame-count-number) specifies the number of animation steps/frames in your torque animation. You can change the time slider timestamp by adjusting the number of steps.<br /><br />**Tip:** This is the _Steps_ option from the [Torque wizard](/carto-editor/maps/#torque) of the CARTO Editor.
- [`-torque-animation-duration`](http://docs.cartodb.com/cartodb-platform/cartocss/properties-for-torque/#torque-animation-duration-number) specifies the length of time for your animation, in seconds. You can adjust the duration of the animation as needed.<br /><br />**Tip:** This is the _Duration (secs)_ option from the [Torque wizard](/cartodb-editor/maps/#torque) of the CartoDB Editor.
- [`-torque-animation-duration`](http://docs.carto.com/carto-engine/cartocss/properties-for-torque/#torque-animation-duration-number) specifies the length of time for your animation, in seconds. You can adjust the duration of the animation as needed.<br /><br />**Tip:** This is the _Duration (secs)_ option from the [Torque wizard](/carto-editor/maps/#torque) of the CARTO Editor.
### Aggregating Time Interval Data
@ -29,12 +29,12 @@ Before customizing the time slider, you should understand how Torque time interv
- Reads the last date/time stamp to from your dataset
- Aggregates the time period based on the first and last date/time stamp (including seconds)
- Once the time interval is defined, it breaks the time period up in smaller "buckets"
- The number of buckets is based on the number of [Steps](http://docs.cartodb.com/cartodb-platform/cartocss/properties-for-torque/#torque-frame-count-number) you select for your Torque map
- The number of buckets is based on the number of [Steps](http://docs.carto.com/carto-engine/cartocss/properties-for-torque/#torque-frame-count-number) you select for your Torque map
- Each bucket, or step, is one animation frame
Thus, the start and end time for each bucket depends on the number of divided steps (not a specific start time or end time that you entered).
**Note:** If you are creating Torque maps with the CartoDB Editor, the date format of the Torque time slider is automatically calculated by CartoDB and cannot be edited. See [Calculating the Time Slider in the CartoDB Editor](#calculating-the-time-slider-in-the-cartodb-editor) for more details.
**Note:** If you are creating Torque maps with the CARTO Editor, the date format of the Torque time slider is automatically calculated by CARTO and cannot be edited. See [Calculating the Time Slider in the CARTO Editor](#calculating-the-time-slider-in-the-carto-editor) for more details.
### Formula for Calculating Time Buckets
@ -48,11 +48,11 @@ Where:
- `times.start` = the earliest time in your date/time column
- `times.end` = the latest time in your date/time column
The Torque time slider displays these buckets of time, animating the entire sequence of your dataset, and divides the time according to the number of specified steps. You can alter the [duration](http://docs.cartodb.com/cartodb-platform/cartocss/properties-for-torque/#torque-animation-duration-number) of the animation, and adjust the time slider timestamp with the number of [Steps](http://docs.cartodb.com/cartodb-platform/cartocss/properties-for-torque/#torque-frame-count-number).
The Torque time slider displays these buckets of time, animating the entire sequence of your dataset, and divides the time according to the number of specified steps. You can alter the [duration](http://docs.carto.com/carto-engine/cartocss/properties-for-torque/#torque-animation-duration-number) of the animation, and adjust the time slider timestamp with the number of [Steps](http://docs.carto.com/carto-engine/cartocss/properties-for-torque/#torque-frame-count-number).
#### Calculating the Time Slider in the CartoDB Editor
#### Calculating the Time Slider in the CARTO Editor
When creating Torque maps with the CartoDB Editor, the date format of the Torque time slider is automatically calculated by CartoDB, depending on the range of time in your dataset. It cannot be edited. If your data contains the following range of time, the time slider displays as described:
When creating Torque maps with the CARTO Editor, the date format of the Torque time slider is automatically calculated by CARTO, depending on the range of time in your dataset. It cannot be edited. If your data contains the following range of time, the time slider displays as described:
- Time range is _less than one day_, the time slider displays the _time_
- Time range is _less than three days_, the time slider displays the _day and time_

View File

@ -1,7 +1,6 @@
L.Mixin.TileLoader = {
_initTileLoader: function() {
this._tiles = {}
this._tilesLoading = {};
this._tilesToLoad = 0;
this._map.on({

View File

@ -27,6 +27,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
}
options.tileLoader = true;
this.keys = [0];
this._tiles = {};
Object.defineProperty(this, 'key', {
get: function() {
return this.getKey();
@ -34,7 +35,9 @@ L.TorqueLayer = L.CanvasLayer.extend({
});
this.prevRenderedKey = 0;
if (options.cartocss) {
torque.extend(options, torque.common.TorqueLayer.optionsFromCartoCSS(options.cartocss));
// We're only passing the Map header to the global options because the parser won't like turbocarto expressions
var headerCartoCSS = options.cartocss.replace(/\n/g,'').match(/Map\s*?\{.*?}/g)[0];
torque.extend(options, torque.common.TorqueLayer.optionsFromCartoCSS(headerCartoCSS));
}
options.resolution = options.resolution || 2;
@ -78,8 +81,10 @@ L.TorqueLayer = L.CanvasLayer.extend({
if (this.options.tileJSON) this.options.provider = 'tileJSON';
this.provider = new this.providers[this.options.provider](options);
options.layer = this;
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
options.ready = function() {
self.fire("change:bounds", {
bounds: self.provider.getBounds()
@ -92,6 +97,10 @@ L.TorqueLayer = L.CanvasLayer.extend({
self.setKeys(self.getKeys());
};
this.on('tileLoaded', function () {
self.renderer.setCartoCSS(self.renderer.style);
})
this.renderer.on("allIconsLoaded", this.render.bind(this));
@ -384,11 +393,9 @@ L.TorqueLayer = L.CanvasLayer.extend({
setCartoCSS: function(cartocss) {
if (this.provider.options.named_map) throw new Error("CartoCSS style on named maps is read-only");
if (!this.renderer) throw new Error('renderer is not valid');
var shader = new carto.RendererJS().render(cartocss);
this.renderer.setShader(shader);
this.renderer.setCartoCSS(cartocss, function () {
// provider options
var options = torque.common.TorqueLayer.optionsFromLayer(shader.findLayer({ name: 'Map' }));
var options = torque.common.TorqueLayer.optionsFromLayer(this.renderer._shader.findLayer({ name: 'Map' }));
this.provider.setCartoCSS && this.provider.setCartoCSS(cartocss);
if(this.provider.setOptions(options)) {
this._reloadTiles();
@ -403,6 +410,8 @@ L.TorqueLayer = L.CanvasLayer.extend({
this._clearCaches();
this.redraw();
return this;
}.bind(this));
},
/**

View File

@ -0,0 +1,52 @@
var d3 = require('d3');
var jenks = require('turf-jenks');
function TorqueDataSource (tiles) {
this.tiles = tiles
}
module.exports = TorqueDataSource
TorqueDataSource.prototype.getName = function () {
return 'TorqueDataSource'
}
TorqueDataSource.prototype.getRamp = function (column, bins, method, callback) {
var ramp = []
var error = null
var values = Object.keys(this.tiles).map(function (t) {
return this.tiles[t].renderData;
}.bind(this)).reduce(function (p,c,i) {
for(var i = 0; i<c.length; i++) {
p.push(c[i]);
}
return p;
},[]);
var extent = d3.extent(values);
if (!method || method === 'equal' || method === 'jenks') {
var scale = d3.scale.linear().domain([0, bins]).range(extent)
ramp = d3.range(bins).map(scale)
} else if (method === 'quantiles') {
ramp = d3.scale.quantile().range(d3.range(bins)).domain(values).quantiles()
} else if (method === 'headstails') {
var sortedValues = values.sort(function(a, b) {
return a - b;
});
if (sortedValues.length < bins) {
error = 'Number of bins should be lower than total number of rows'
} else if (sortedValues.length === bins) {
ramp = sortedValues;
} else {
var mean = d3.mean(sortedValues);
ramp.push(mean);
for (var i = 1; i < bins; i++) {
ramp.push(d3.mean(sortedValues.filter(function (v) {
return v > ramp[length - 1];
})));
}
}
} else {
error = new Error('Quantification method ' + method + ' is not supported')
}
callback(error, ramp)
}

View File

@ -3,6 +3,8 @@ var cartocss = require('./cartocss_render');
var Profiler = require('../profiler');
var carto = global.carto || require('carto');
var Filters = require('./torque_filters');
var turbocarto = require('turbo-carto');
var CartoDatasource = require('./datasource');
var TAU = Math.PI * 2;
var DEFAULT_CARTOCSS = [
@ -62,6 +64,7 @@ var Filters = require('./torque_filters');
throw new Error("canvas can't be undefined");
}
this.options = options;
this.layer = options.layer;
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
this._sprites = []; // sprites per layer
@ -69,7 +72,8 @@ var Filters = require('./torque_filters');
this._icons = {};
this._iconsToLoad = 0;
this._filters = new Filters(this._canvas, {canvasClass: options.canvasClass});
this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
this.style = this.options.cartocss || DEFAULT_CARTOCSS;
this.setCartoCSS(this.style);
this.TILE_SIZE = options.tileSize || 256;
this._style = null;
this._gradients = {};
@ -80,6 +84,7 @@ var Filters = require('./torque_filters');
torque.extend(PointRenderer.prototype, torque.Event, {
clearCanvas: function() {
if (this._Map) {
var canvas = this._canvas;
var color = this._Map['-torque-clear-color']
// shortcut for the default value
@ -93,6 +98,7 @@ var Filters = require('./torque_filters');
ctx.fillStyle = color;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
}
},
setCanvas: function(canvas) {
@ -103,9 +109,20 @@ var Filters = require('./torque_filters');
//
// sets the cartocss style to render stuff
//
setCartoCSS: function(cartocss) {
// clean sprites
this.setShader(new carto.RendererJS().render(cartocss));
setCartoCSS: function(cartocss, callback) {
var self = this;
if (PointRenderer.isTurboCarto(cartocss)) {
var datasource = new CartoDatasource(self.layer._tiles);
turbocarto(cartocss, datasource, function (err, parsedCartoCSS) {
self.setShader(new carto.RendererJS().render(parsedCartoCSS));
self.layer.redraw();
self.layer.animator.start();
callback && callback();
});
} else {
self.setShader(new carto.RendererJS().render(cartocss));
callback && callback();
}
},
setShader: function(shader) {
@ -483,6 +500,17 @@ var Filters = require('./torque_filters');
}
});
PointRenderer.isTurboCarto = function (cartocss) {
var reservedWords = ['ramp', 'colorbrewer', 'buckets']
var isTurbo = reservedWords
.map(function (w) {
return w + '('
})
.map(String.prototype.indexOf.bind(cartocss))
.every(function (f) { return f === -1 })
return !isTurbo
}
// exports public api
module.exports = PointRenderer;

View File

@ -21,18 +21,18 @@
"Nicklas Gummesson <nicklas@cartodb.com>",
"Francisco Dans <francisco@cartodb.com>"
],
"licenses": [{
"type": "BSD"
}
],
"license": "BSD-3-Clause",
"dependencies": {
"carto": "https://github.com/CartoDB/carto/archive/master.tar.gz"
"carto": "cartodb/carto#master",
"d3": "~3.5.6",
"turbo-carto": "~0.15.1",
"turf-jenks": "~1.0.1"
},
"devDependencies": {
"browserify": "~7.0.0",
"canvas": "~1.2.1",
"leaflet": "0.7.3",
"mapnik": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb1",
"mapnik": "cartodb/node-mapnik#1.4.15-cdb8",
"node-qunit-phantomjs": "1.3.0",
"phantomjs-polyfill": "0.0.1",
"qunit": "~0.7.5",