Merge branch 'bi_provider' of github.com:CartoDB/torque into bi_provider
This commit is contained in:
commit
8ce2a629f1
@ -111,36 +111,42 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
|
||||
},
|
||||
|
||||
setFilters:function(){
|
||||
setFilters: function() {
|
||||
this.provider.setFilters(this._filters);
|
||||
this._reloadTiles();
|
||||
return this;
|
||||
},
|
||||
filterByRange:function(variableName,start,end){
|
||||
this._filters[variableName] = {type: 'range', range: {start:start,end:end}}
|
||||
|
||||
filterByRange: function(variableName, start, end) {
|
||||
this._filters[variableName] = {type: 'range', range: {start: start, end: end} }
|
||||
this._filtersChanged()
|
||||
this.fire('dataUpdate')
|
||||
return this
|
||||
},
|
||||
filterByCat:function(variableName,categories){
|
||||
|
||||
filterByCat: function(variableName, categories) {
|
||||
this._filters[variableName] = {type: 'cat', categories: categories}
|
||||
this._filtersChanged()
|
||||
return this
|
||||
},
|
||||
|
||||
clearFilter: function(name){
|
||||
if(name){
|
||||
if(name) {
|
||||
delete this._filters[name]
|
||||
}
|
||||
else{
|
||||
else {
|
||||
this._filters = {}
|
||||
}
|
||||
this._filtersChanged()
|
||||
return this
|
||||
},
|
||||
|
||||
_filtersChanged:function(){
|
||||
this.provider._filters = this._filters;
|
||||
this._clearTileCaches()
|
||||
this._render()
|
||||
},
|
||||
|
||||
_clearTileCaches: function() {
|
||||
var t, tile;
|
||||
for(t in this._tiles) {
|
||||
@ -150,6 +156,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_clearCaches: function() {
|
||||
this.renderer && this.renderer.clearSpriteCache();
|
||||
this._clearTileCaches();
|
||||
@ -335,6 +342,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
canvas.width = canvas.width;
|
||||
},
|
||||
|
||||
/*
|
||||
_filterTile:function(tile){
|
||||
var noPoints = tile.x.length
|
||||
|
||||
@ -366,6 +374,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
}
|
||||
return renderFlags
|
||||
},
|
||||
*/
|
||||
|
||||
/**
|
||||
* render the selectef key
|
||||
@ -396,7 +405,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
||||
this.renderer._ctx.drawImage(tile._tileCache, 0, 0);
|
||||
} else {
|
||||
|
||||
tile.renderFlags=this._filterTile(tile)
|
||||
//tile.renderFlags = this._filterTile(tile)
|
||||
this.renderer.renderTile(tile, this.key);
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ var Profiler = require('../profiler');
|
||||
var prof_point_count = Profiler.metric('ProviderJSON:point_count');
|
||||
var prof_process_time = Profiler.metric('ProviderJSON:process_time').start()
|
||||
|
||||
// count number of dates
|
||||
var dates = 0;
|
||||
// count number of steps
|
||||
var steps = 0;
|
||||
var maxDateSlots = -1;
|
||||
for (r = 0; r < rows.length; ++r) {
|
||||
var row = rows[r];
|
||||
@ -97,10 +97,15 @@ var Profiler = require('../profiler');
|
||||
}
|
||||
}
|
||||
|
||||
if(this.options.cumulative) {
|
||||
steps = (1 + maxDateSlots) * rows.length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// var type = Uint8Array;
|
||||
|
||||
|
||||
// reserve memory for all the dates
|
||||
// var timeIndex = new Int32Array(maxDateSlots + 1); //index-size
|
||||
// var timeCount = new Int32Array(maxDateSlots + 1);
|
||||
@ -110,8 +115,8 @@ var Profiler = require('../profiler');
|
||||
prof_mem.inc(
|
||||
4 * maxDateSlots + // timeIndex
|
||||
4 * maxDateSlots + // timeCount
|
||||
dates + //renderData
|
||||
dates * 4
|
||||
steps + //renderData
|
||||
steps * 4
|
||||
); //renderDataPos
|
||||
|
||||
prof_point_count.inc(rows.length);
|
||||
@ -134,6 +139,40 @@ var Profiler = require('../profiler');
|
||||
renderData[r*row.steps.length + i] = row.vals[i]
|
||||
}
|
||||
/*var lastDateSlot = dates[dates.length - 1];
|
||||
|
||||
y[r] = row.y * this.options.resolution;
|
||||
}
|
||||
|
||||
var steps = row.steps;
|
||||
var vals = row.vals;
|
||||
if (!this.options.cumulative) {
|
||||
for (var j = 0, len = steps.length; j < len; ++j) {
|
||||
var rr = rowsPerSlot[steps[j]] || (rowsPerSlot[steps[j]] = []);
|
||||
if(this.options.cumulative) {
|
||||
vals[j] += prev_val;
|
||||
}
|
||||
prev_val = vals[j];
|
||||
rr.push([r, vals[j]]);
|
||||
}
|
||||
} else {
|
||||
var valByDate = {}
|
||||
for (var j = 0, len = steps.length; j < len; ++j) {
|
||||
valByDate[steps[j]] = vals[j];
|
||||
}
|
||||
var accum = 0;
|
||||
|
||||
// extend the latest to the end
|
||||
for (var j = steps[0]; j <= maxDateSlots; ++j) {
|
||||
var rr = rowsPerSlot[j] || (rowsPerSlot[j] = []);
|
||||
var v = valByDate[j];
|
||||
if (v) {
|
||||
accum += v;
|
||||
}
|
||||
rr.push([r, accum]);
|
||||
}
|
||||
|
||||
/*var lastDateSlot = steps[steps.length - 1];
|
||||
>>>>>>> 4ad0dba547e2a57300064c484d42e196eb846356
|
||||
for (var j = lastDateSlot + 1; j <= maxDateSlots; ++j) {
|
||||
var rr = rowsPerSlot[j] || (rowsPerSlot[j] = []);
|
||||
rr.push([r, prev_val]);
|
||||
@ -163,33 +202,42 @@ var Profiler = require('../profiler');
|
||||
// maxDate: maxDateSlots
|
||||
};
|
||||
},
|
||||
|
||||
_generateFilterSQLForCat:function(name,categories){
|
||||
return name+" in "+categories;
|
||||
},
|
||||
|
||||
_generateFilterSQLForRange:function(name,range){
|
||||
var result = ""
|
||||
if(range.start){
|
||||
if (range.start) {
|
||||
result += " " + name + " > " + range.start;
|
||||
}
|
||||
if(range.end){
|
||||
if (range.end) {
|
||||
if (range.start) {
|
||||
result += " and "
|
||||
}
|
||||
result += " " + name + " < " + range.end;
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
_setFilters:function(filters){
|
||||
this.filters = filters
|
||||
},
|
||||
_generateFiltersSQL:function(){
|
||||
|
||||
_generateFiltersSQL: function() {
|
||||
var self = this;
|
||||
|
||||
return Object.keys(this._filters).map(function(filterName){
|
||||
var filter = this._filters[filterName]
|
||||
if(filter){
|
||||
if(filter.type == 'range'){
|
||||
return this._generateFilterSQLForRange(filterName, filter.range)
|
||||
var filter = self._filters[filterName]
|
||||
if (filter) {
|
||||
if (filter.type == 'range') {
|
||||
return self._generateFilterSQLForRange(filterName, filter.range)
|
||||
}
|
||||
else if(filter.type == 'cat'){
|
||||
return this._generateFilterSQLForCat(filterName, filter.categories)
|
||||
else if (filter.type == 'cat') {
|
||||
return self._generateFilterSQLForCat(filterName, filter.categories)
|
||||
}
|
||||
else{
|
||||
else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@ -198,6 +246,7 @@ var Profiler = require('../profiler');
|
||||
}
|
||||
}).join(" and ")
|
||||
},
|
||||
|
||||
_host: function() {
|
||||
var opts = this.options;
|
||||
var port = opts.sql_api_port;
|
||||
@ -307,10 +356,10 @@ var Profiler = require('../profiler');
|
||||
var numTiles = 1 << zoom;
|
||||
|
||||
var column_conv = this.options.column;
|
||||
|
||||
if(this.options.is_time) {
|
||||
column_conv = format("date_part('epoch', {column})", this.options);
|
||||
}
|
||||
//
|
||||
// if(this.options.is_time) {
|
||||
// column_conv = format("date_part('epoch', {column})", this.options);
|
||||
// }
|
||||
|
||||
// var sql = "" +
|
||||
// "WITH " +
|
||||
@ -337,12 +386,15 @@ var Profiler = require('../profiler');
|
||||
this.options.filters = this._generateFiltersSQL()
|
||||
var sql = ""+
|
||||
"SELECT * FROM torque_tile(x:={x}, y:={y}, z:={zoom}, aggr:=ARRAY['{columns}'], table_name:='{table}', where_clause:='{filters}');"
|
||||
|
||||
|
||||
var query = format(sql, this.options, {
|
||||
zoom: zoom,
|
||||
x: coord.x,
|
||||
y: coord.y,
|
||||
column_conv: column_conv,
|
||||
_sql: this.getSQL()
|
||||
column: column_conv,
|
||||
table: this.options.table,
|
||||
filters: this._generateFiltersSQL()
|
||||
});
|
||||
|
||||
|
||||
@ -380,31 +432,6 @@ var Profiler = require('../profiler');
|
||||
this.options.resolution = res;
|
||||
},
|
||||
|
||||
idForRange: function(variable){
|
||||
return this._mapping[variable].col_id
|
||||
},
|
||||
idsForCategory:function(variable){
|
||||
return this._mapping[variable].col_ids
|
||||
},
|
||||
idForCategoryOption:function(variable, option){
|
||||
return this._mapping[variable].col_ids.to_a.select(function(a){return option==a[0]})[0][1]
|
||||
},
|
||||
optionForId:function(id){
|
||||
Object.keys(this._mapping).forEach(function(varaibleName){
|
||||
var variable = this._mapping[variableName]
|
||||
if(variable.type=='range' && variable.col_id==id){
|
||||
return variableName
|
||||
}
|
||||
else if(variable.type=='cat') {
|
||||
Object.keys(variable.col_ids).forEach(function(key){
|
||||
if(variable.col_ids[key] == id){
|
||||
|
||||
}
|
||||
}.bind(this))
|
||||
}
|
||||
}.bind(this))
|
||||
return null;
|
||||
},
|
||||
// return true if tiles has been changed
|
||||
setOptions: function(opt) {
|
||||
var refresh = false;
|
||||
@ -485,134 +512,8 @@ var Profiler = require('../profiler');
|
||||
((opts.tiler_port != "") ? (":" + opts.tiler_port) : "");
|
||||
},
|
||||
|
||||
_fetchUpdateAt: function(callback) {
|
||||
var self = this;
|
||||
var layergroup = {
|
||||
"version": "1.0.1",
|
||||
"stat_tag": this.options.stat_tag || 'torque',
|
||||
"layers": [{
|
||||
"type": "cartodb",
|
||||
"options": {
|
||||
"cartocss_version": "2.1.1",
|
||||
"cartocss": "#layer {}",
|
||||
"sql": this.getSQL()
|
||||
}
|
||||
}]
|
||||
};
|
||||
var url = this._tilerHost() + "/tiles/layergroup";
|
||||
var extra = this._extraParams();
|
||||
|
||||
// tiler needs map_key instead of api_key
|
||||
// so replace it
|
||||
if (extra) {
|
||||
extra = extra.replace('api_key=', 'map_key=');
|
||||
}
|
||||
|
||||
url = url +
|
||||
"?config=" + encodeURIComponent(JSON.stringify(layergroup)) +
|
||||
"&callback=?" + (extra ? "&" + extra: '');
|
||||
|
||||
torque.net.jsonp(url, function (data) {
|
||||
var query = format("select * from ({sql}) __torque_wrap_sql limit 0", { sql: self.getSQL() });
|
||||
self.sql(query, function (queryData) {
|
||||
if (data && queryData) {
|
||||
callback({
|
||||
updated_at: data.last_updated,
|
||||
fields: queryData.fields
|
||||
});
|
||||
}
|
||||
}, { parseJSON: true });
|
||||
});
|
||||
},
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
_fetchKeySpan: function() {
|
||||
var self = this;
|
||||
var max_col, min_col, max_tmpl, min_tmpl;
|
||||
|
||||
this._fetchUpdateAt(function(data) {
|
||||
if (!data) return;
|
||||
self.options.extra_params = self.options.extra_params || {};
|
||||
self.options.extra_params.last_updated = data.updated_at || 0;
|
||||
self.options.extra_params.cache_policy = 'persist';
|
||||
self.options.is_time = data.fields[self.options.column].type === 'date';
|
||||
|
||||
var column_conv = self.options.column;
|
||||
if (self.options.is_time){
|
||||
max_tmpl = "date_part('epoch', max({column}))";
|
||||
min_tmpl = "date_part('epoch', min({column}))";
|
||||
column_conv = format("date_part('epoch', {column})", self.options);
|
||||
} else {
|
||||
max_tmpl = "max({column})";
|
||||
min_tmpl = "min({column})";
|
||||
}
|
||||
|
||||
max_col = format(max_tmpl, { column: self.options.column });
|
||||
min_col = format(min_tmpl, { column: self.options.column });
|
||||
|
||||
/*var sql_stats = "" +
|
||||
"WITH summary_groups as ( " +
|
||||
"WITH summary as ( " +
|
||||
"select (row_number() over (order by __time_col asc nulls last)+1)/2 as rownum, __time_col " +
|
||||
"from (select *, {column} as __time_col from ({sql}) __s) __torque_wrap_sql " +
|
||||
"order by __time_col asc " +
|
||||
") " +
|
||||
"SELECT " +
|
||||
"max(__time_col) OVER(PARTITION BY rownum) - " +
|
||||
"min(__time_col) OVER(PARTITION BY rownum) diff " +
|
||||
"FROM summary " +
|
||||
"), subq as ( " +
|
||||
" SELECT " +
|
||||
"st_xmax(st_envelope(st_collect(the_geom))) xmax, " +
|
||||
"st_ymax(st_envelope(st_collect(the_geom))) ymax, " +
|
||||
"st_xmin(st_envelope(st_collect(the_geom))) xmin, " +
|
||||
"st_ymin(st_envelope(st_collect(the_geom))) ymin, " +
|
||||
"{max_col} max, " +
|
||||
"{min_col} min FROM ({sql}) __torque_wrap_sql " +
|
||||
")" +
|
||||
"SELECT " +
|
||||
"xmax, xmin, ymax, ymin, a.max as max_date, a.min as min_date, " +
|
||||
"avg(diff) as diffavg," +
|
||||
"(a.max - a.min)/avg(diff) as num_steps " +
|
||||
"FROM summary_groups, subq a " +
|
||||
"WHERE diff > 0 group by xmax, xmin, ymax, ymin, max_date, min_date";
|
||||
*/
|
||||
var sql_stats = " SELECT " +
|
||||
"st_xmax(st_envelope(st_collect(the_geom))) xmax, " +
|
||||
"st_ymax(st_envelope(st_collect(the_geom))) ymax, " +
|
||||
"st_xmin(st_envelope(st_collect(the_geom))) xmin, " +
|
||||
"st_ymin(st_envelope(st_collect(the_geom))) ymin, " +
|
||||
"count(*) as num_steps, " +
|
||||
"{max_col} max_date, " +
|
||||
"{min_col} min_date FROM ({sql}) __torque_wrap_sql ";
|
||||
|
||||
var sql = format(sql_stats, {
|
||||
max_col: max_col,
|
||||
min_col: min_col,
|
||||
column: column_conv,
|
||||
sql: self.getSQL()
|
||||
});
|
||||
|
||||
self.sql(sql, function(data) {
|
||||
//TODO: manage bounds
|
||||
data = data.rows[0];
|
||||
self.options.start = data.min_date;
|
||||
self.options.end = data.max_date;
|
||||
self.options.step = (data.max_date - data.min_date)/Math.min(self.options.steps, data.num_steps>>0);
|
||||
self.options.data_steps = data.num_steps >> 0;
|
||||
// step can't be 0
|
||||
self.options.step = self.options.step || 1;
|
||||
self.options.bounds = [
|
||||
[data.ymin, data.xmin],
|
||||
[data.ymax, data.xmax]
|
||||
];
|
||||
self._setReady(true);
|
||||
}, { parseJSON: true, no_cdn: true });
|
||||
}, { parseJSON: true, no_cdn: true})
|
||||
this._setReady(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -261,19 +261,19 @@ var Filters = require('./torque_filters');
|
||||
for(var p = 0; p < activePixels; ++p) {
|
||||
if(tile.renderFlags[p]){
|
||||
var posIdx = p// tile.renderDataPos[pixelIndex + p];
|
||||
|
||||
var posIdx = tile.renderDataPos[pixelIndex + p];
|
||||
|
||||
var c = tile.renderData[pixelIndex + p];
|
||||
if (c) {
|
||||
var sp = sprites[c];
|
||||
if (sp === undefined) {
|
||||
var sp = sprites[c];
|
||||
if (sp === undefined) {
|
||||
sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
|
||||
}
|
||||
if (sp) {
|
||||
}
|
||||
if (sp) {
|
||||
var x = tile.x[posIdx]- (sp.width >> 1) + anchor;
|
||||
var y = tileMax - tile.y[posIdx] + anchor; // flip mercator
|
||||
ctx.drawImage(sp, x, y - (sp.height >> 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user