commit
b5a2e88f1c
@ -1,7 +1,6 @@
|
|||||||
L.Mixin.TileLoader = {
|
L.Mixin.TileLoader = {
|
||||||
|
|
||||||
_initTileLoader: function() {
|
_initTileLoader: function() {
|
||||||
this._tiles = {}
|
|
||||||
this._tilesLoading = {};
|
this._tilesLoading = {};
|
||||||
this._tilesToLoad = 0;
|
this._tilesToLoad = 0;
|
||||||
this._map.on({
|
this._map.on({
|
||||||
|
@ -27,6 +27,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
}
|
}
|
||||||
options.tileLoader = true;
|
options.tileLoader = true;
|
||||||
this.keys = [0];
|
this.keys = [0];
|
||||||
|
this._tiles = {};
|
||||||
Object.defineProperty(this, 'key', {
|
Object.defineProperty(this, 'key', {
|
||||||
get: function() {
|
get: function() {
|
||||||
return this.getKey();
|
return this.getKey();
|
||||||
@ -34,7 +35,9 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
});
|
});
|
||||||
this.prevRenderedKey = 0;
|
this.prevRenderedKey = 0;
|
||||||
if (options.cartocss) {
|
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;
|
options.resolution = options.resolution || 2;
|
||||||
@ -78,8 +81,10 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
if (this.options.tileJSON) this.options.provider = 'tileJSON';
|
if (this.options.tileJSON) this.options.provider = 'tileJSON';
|
||||||
|
|
||||||
this.provider = new this.providers[this.options.provider](options);
|
this.provider = new this.providers[this.options.provider](options);
|
||||||
|
options.layer = this;
|
||||||
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
|
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
|
||||||
|
|
||||||
|
|
||||||
options.ready = function() {
|
options.ready = function() {
|
||||||
self.fire("change:bounds", {
|
self.fire("change:bounds", {
|
||||||
bounds: self.provider.getBounds()
|
bounds: self.provider.getBounds()
|
||||||
@ -92,6 +97,10 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
self.setKeys(self.getKeys());
|
self.setKeys(self.getKeys());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.on('tileLoaded', function () {
|
||||||
|
self.renderer.setCartoCSS(self.renderer.style);
|
||||||
|
})
|
||||||
|
|
||||||
this.renderer.on("allIconsLoaded", this.render.bind(this));
|
this.renderer.on("allIconsLoaded", this.render.bind(this));
|
||||||
|
|
||||||
|
|
||||||
@ -384,25 +393,25 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
setCartoCSS: function(cartocss) {
|
setCartoCSS: function(cartocss) {
|
||||||
if (this.provider.options.named_map) throw new Error("CartoCSS style on named maps is read-only");
|
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');
|
if (!this.renderer) throw new Error('renderer is not valid');
|
||||||
var shader = new carto.RendererJS().render(cartocss);
|
this.renderer.setCartoCSS(cartocss, function () {
|
||||||
this.renderer.setShader(shader);
|
// provider options
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
// provider options
|
torque.extend(this.options, options);
|
||||||
var options = torque.common.TorqueLayer.optionsFromLayer(shader.findLayer({ name: 'Map' }));
|
|
||||||
this.provider.setCartoCSS && this.provider.setCartoCSS(cartocss);
|
|
||||||
if(this.provider.setOptions(options)) {
|
|
||||||
this._reloadTiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
torque.extend(this.options, options);
|
// animator options
|
||||||
|
if (options.animationDuration) {
|
||||||
|
this.animator.duration(options.animationDuration);
|
||||||
|
}
|
||||||
|
this._clearCaches();
|
||||||
|
this.redraw();
|
||||||
|
return this;
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
// animator options
|
|
||||||
if (options.animationDuration) {
|
|
||||||
this.animator.duration(options.animationDuration);
|
|
||||||
}
|
|
||||||
this._clearCaches();
|
|
||||||
this.redraw();
|
|
||||||
return this;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
52
lib/torque/renderer/datasource.js
Normal file
52
lib/torque/renderer/datasource.js
Normal 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)
|
||||||
|
}
|
@ -3,6 +3,8 @@ var cartocss = require('./cartocss_render');
|
|||||||
var Profiler = require('../profiler');
|
var Profiler = require('../profiler');
|
||||||
var carto = global.carto || require('carto');
|
var carto = global.carto || require('carto');
|
||||||
var Filters = require('./torque_filters');
|
var Filters = require('./torque_filters');
|
||||||
|
var turbocarto = require('turbo-carto');
|
||||||
|
var CartoDatasource = require('./datasource');
|
||||||
|
|
||||||
var TAU = Math.PI * 2;
|
var TAU = Math.PI * 2;
|
||||||
var DEFAULT_CARTOCSS = [
|
var DEFAULT_CARTOCSS = [
|
||||||
@ -62,6 +64,7 @@ var Filters = require('./torque_filters');
|
|||||||
throw new Error("canvas can't be undefined");
|
throw new Error("canvas can't be undefined");
|
||||||
}
|
}
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
this.layer = options.layer;
|
||||||
this._canvas = canvas;
|
this._canvas = canvas;
|
||||||
this._ctx = canvas.getContext('2d');
|
this._ctx = canvas.getContext('2d');
|
||||||
this._sprites = []; // sprites per layer
|
this._sprites = []; // sprites per layer
|
||||||
@ -69,7 +72,8 @@ var Filters = require('./torque_filters');
|
|||||||
this._icons = {};
|
this._icons = {};
|
||||||
this._iconsToLoad = 0;
|
this._iconsToLoad = 0;
|
||||||
this._filters = new Filters(this._canvas, {canvasClass: options.canvasClass});
|
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 = 256;
|
this.TILE_SIZE = 256;
|
||||||
this._style = null;
|
this._style = null;
|
||||||
this._gradients = {};
|
this._gradients = {};
|
||||||
@ -80,18 +84,20 @@ var Filters = require('./torque_filters');
|
|||||||
torque.extend(PointRenderer.prototype, torque.Event, {
|
torque.extend(PointRenderer.prototype, torque.Event, {
|
||||||
|
|
||||||
clearCanvas: function() {
|
clearCanvas: function() {
|
||||||
var canvas = this._canvas;
|
if (this._Map) {
|
||||||
var color = this._Map['-torque-clear-color']
|
var canvas = this._canvas;
|
||||||
// shortcut for the default value
|
var color = this._Map['-torque-clear-color']
|
||||||
if (color === "rgba(255, 255, 255, 0)" || !color) {
|
// shortcut for the default value
|
||||||
this._canvas.width = this._canvas.width;
|
if (color === "rgba(255, 255, 255, 0)" || !color) {
|
||||||
} else {
|
this._canvas.width = this._canvas.width;
|
||||||
var ctx = this._ctx;
|
} else {
|
||||||
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
var ctx = this._ctx;
|
||||||
var compop = this._Map['comp-op']
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
ctx.globalCompositeOperation = compop2canvas(compop) || compop;
|
var compop = this._Map['comp-op']
|
||||||
ctx.fillStyle = color;
|
ctx.globalCompositeOperation = compop2canvas(compop) || compop;
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -103,9 +109,20 @@ var Filters = require('./torque_filters');
|
|||||||
//
|
//
|
||||||
// sets the cartocss style to render stuff
|
// sets the cartocss style to render stuff
|
||||||
//
|
//
|
||||||
setCartoCSS: function(cartocss) {
|
setCartoCSS: function(cartocss, callback) {
|
||||||
// clean sprites
|
var self = this;
|
||||||
this.setShader(new carto.RendererJS().render(cartocss));
|
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) {
|
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
|
// exports public api
|
||||||
module.exports = PointRenderer;
|
module.exports = PointRenderer;
|
||||||
|
52
package.json
52
package.json
@ -1,32 +1,36 @@
|
|||||||
{
|
{
|
||||||
"name": "torque.js",
|
"name": "torque.js",
|
||||||
"version": "2.15.1",
|
"version": "2.15.1",
|
||||||
"description": "Temporal mapping for CartoDB",
|
"description": "Temporal mapping for CartoDB",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/CartoDB/torque.git"
|
"url": "git://github.com/CartoDB/torque.git"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "CartoDB",
|
"name": "CartoDB",
|
||||||
"url": "http://cartodb.com/",
|
"url": "http://cartodb.com/",
|
||||||
"email": "wadus@cartodb.com"
|
"email": "wadus@cartodb.com"
|
||||||
},
|
},
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Andrew Hill <andrew@vizzuality.com>",
|
"Andrew Hill <andrew@vizzuality.com>",
|
||||||
"Simon Tokumine <tokumine@google.com>",
|
"Simon Tokumine <tokumine@google.com>",
|
||||||
"Javier Alvarez <jmedina@vizzuality.com>",
|
"Javier Alvarez <jmedina@vizzuality.com>",
|
||||||
"Javier Arce <javierarce@vizzuality.com>",
|
"Javier Arce <javierarce@vizzuality.com>",
|
||||||
"Javier Santana <jsantana@vizzuality.com>",
|
"Javier Santana <jsantana@vizzuality.com>",
|
||||||
"Raúl Ochoa <rochoa@cartodb.com>",
|
"Raúl Ochoa <rochoa@cartodb.com>",
|
||||||
"Nicklas Gummesson <nicklas@cartodb.com>",
|
"Nicklas Gummesson <nicklas@cartodb.com>",
|
||||||
"Francisco Dans <francisco@cartodb.com>"
|
"Francisco Dans <francisco@cartodb.com>"
|
||||||
],
|
],
|
||||||
"licenses": [{
|
"licenses": [
|
||||||
|
{
|
||||||
"type": "BSD"
|
"type": "BSD"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"carto": "https://github.com/CartoDB/carto/archive/master.tar.gz"
|
"carto": "https://github.com/CartoDB/carto/archive/master.tar.gz",
|
||||||
|
"d3": "^3.5.6",
|
||||||
|
"turbo-carto": "^0.12.1",
|
||||||
|
"turf-jenks": "^1.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "~7.0.0",
|
"browserify": "~7.0.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user