Compare commits
53 Commits
master
...
bi_provide
Author | SHA1 | Date | |
---|---|---|---|
|
2bc79e183f | ||
|
75bdbbfb80 | ||
|
419403998d | ||
|
029f08b2f9 | ||
|
f1a07e7cd9 | ||
|
1eb1344916 | ||
|
ce6ba46893 | ||
|
4421294a4e | ||
|
19e0145fee | ||
|
754ab64a9a | ||
|
a393186f9f | ||
|
c660bc8fe7 | ||
|
7c2d0b353a | ||
|
f82283ff54 | ||
|
59e533af10 | ||
|
d95f044ffc | ||
|
b210ba8b22 | ||
|
f399acb8cc | ||
|
c500a9c025 | ||
|
5299314fb4 | ||
|
3e35097496 | ||
|
880bf9870f | ||
|
c9e87f4365 | ||
|
21e28bf66b | ||
|
ea2fe75fbc | ||
|
e93c6169bd | ||
|
33c79dad0c | ||
|
b46489d8eb | ||
|
c4fa9b3351 | ||
|
a822c369c7 | ||
|
a61976727c | ||
|
1058d7ee8f | ||
|
b7f38d5996 | ||
|
55847bda56 | ||
|
164643d0f1 | ||
|
e65367e8a6 | ||
|
1fa44a8ae1 | ||
|
87b93e6f9e | ||
|
dbf48ea091 | ||
|
6dd0251be8 | ||
|
19e35ffe2c | ||
|
7a1f206d5e | ||
|
1ec2324b83 | ||
|
e0606ee295 | ||
|
695cab290a | ||
|
ff4809b08c | ||
|
4ad0dba547 | ||
|
37f4367da2 | ||
|
53d5072c4b | ||
|
71fc89a8d8 | ||
|
fd5bc0f732 | ||
|
130d72c872 | ||
|
c27b2471da |
@ -17,6 +17,31 @@ L.Mixin.TileLoader = {
|
|||||||
this._removeTiles();
|
this._removeTiles();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
visibleTiles: function() {
|
||||||
|
if (!this._map) { return []; }
|
||||||
|
var j, i, point, tiles = [];
|
||||||
|
var bounds = this._map.getPixelBounds(),
|
||||||
|
zoom = this._map.getZoom(),
|
||||||
|
tileSize = this.options.tileSize;
|
||||||
|
|
||||||
|
var nwTilePoint = new L.Point(
|
||||||
|
Math.floor(bounds.min.x / tileSize),
|
||||||
|
Math.floor(bounds.min.y / tileSize)),
|
||||||
|
|
||||||
|
seTilePoint = new L.Point(
|
||||||
|
Math.floor(bounds.max.x / tileSize),
|
||||||
|
Math.floor(bounds.max.y / tileSize)),
|
||||||
|
|
||||||
|
tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
|
||||||
|
|
||||||
|
for (j = tileBounds.min.y; j <= tileBounds.max.y; j++) {
|
||||||
|
for (i = tileBounds.min.x; i <= tileBounds.max.x; i++) {
|
||||||
|
tiles.push({ x: i, y: j, z: zoom });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tiles;
|
||||||
|
},
|
||||||
|
|
||||||
_updateTiles: function () {
|
_updateTiles: function () {
|
||||||
|
|
||||||
if (!this._map) { return; }
|
if (!this._map) { return; }
|
||||||
@ -55,11 +80,12 @@ L.Mixin.TileLoader = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_removeOtherTiles: function (bounds) {
|
_removeOtherTiles: function (bounds) {
|
||||||
|
var self = this;
|
||||||
var kArr, x, y, z, key;
|
var kArr, x, y, z, key;
|
||||||
var zoom = this._map.getZoom();
|
var zoom = this._map.getZoom();
|
||||||
|
|
||||||
for (key in this._tiles) {
|
function checkTile(c, key) {
|
||||||
if (this._tiles.hasOwnProperty(key)) {
|
if (c.hasOwnProperty(key)) {
|
||||||
kArr = key.split(':');
|
kArr = key.split(':');
|
||||||
x = parseInt(kArr[0], 10);
|
x = parseInt(kArr[0], 10);
|
||||||
y = parseInt(kArr[1], 10);
|
y = parseInt(kArr[1], 10);
|
||||||
@ -67,22 +93,41 @@ L.Mixin.TileLoader = {
|
|||||||
|
|
||||||
// remove tile if it's out of bounds
|
// remove tile if it's out of bounds
|
||||||
if (zoom !== z || 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);
|
self._removeTile(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (key in this._tiles) {
|
||||||
|
checkTile(this._tiles, key);
|
||||||
|
}
|
||||||
|
for (key in this._tilesLoading) {
|
||||||
|
checkTile(this._tilesLoading, key);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_removeTile: function (key) {
|
_removeTile: function (key) {
|
||||||
this.fire('tileRemoved', this._tiles[key]);
|
this.fire('tileRemoved', this._tiles[key]);
|
||||||
delete this._tiles[key];
|
delete this._tiles[key];
|
||||||
delete this._tilesLoading[key];
|
if (this._tilesLoading[key]) {
|
||||||
|
--this._tilesToLoad;
|
||||||
|
delete this._tilesLoading[key];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_tileKey: function(tilePoint) {
|
_tileKey: function(tilePoint) {
|
||||||
return tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom;
|
return tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_tileFromKey: function(key) {
|
||||||
|
var kArr = key.split(':');
|
||||||
|
return {
|
||||||
|
x: parseInt(kArr[0], 10),
|
||||||
|
y: parseInt(kArr[1], 10),
|
||||||
|
z: parseInt(kArr[2], 10)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_tileShouldBeLoaded: function (tilePoint) {
|
_tileShouldBeLoaded: function (tilePoint) {
|
||||||
var k = this._tileKey(tilePoint);
|
var k = this._tileKey(tilePoint);
|
||||||
return !(k in this._tiles) && !(k in this._tilesLoading);
|
return !(k in this._tiles) && !(k in this._tilesLoading);
|
||||||
|
@ -72,8 +72,8 @@ 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](this.options);
|
||||||
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
|
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), this.options);
|
||||||
|
|
||||||
options.ready = function() {
|
options.ready = function() {
|
||||||
self.fire("change:bounds", {
|
self.fire("change:bounds", {
|
||||||
@ -243,6 +243,7 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderer.applyFilters();
|
this.renderer.applyFilters();
|
||||||
|
|
||||||
// prepare caches if the animation is not running
|
// prepare caches if the animation is not running
|
||||||
@ -341,6 +342,7 @@ 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');
|
||||||
|
this.options.cartocss = cartocss;
|
||||||
var shader = new carto.RendererJS().render(cartocss);
|
var shader = new carto.RendererJS().render(cartocss);
|
||||||
this.renderer.setShader(shader);
|
this.renderer.setShader(shader);
|
||||||
|
|
||||||
@ -398,26 +400,77 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
var t, tile, pos, value = null, xx, yy;
|
var t, tile, pos, value = null, xx, yy;
|
||||||
for(t in this._tiles) {
|
for(t in this._tiles) {
|
||||||
tile = this._tiles[t];
|
tile = this._tiles[t];
|
||||||
pos = this.getTilePos(tile.coord);
|
if (tile) {
|
||||||
xx = x - pos.x;
|
pos = this.getTilePos(tile.coord);
|
||||||
yy = y - pos.y;
|
xx = x - pos.x;
|
||||||
if (xx >= 0 && yy >= 0 && xx < this.renderer.TILE_SIZE && yy <= this.renderer.TILE_SIZE) {
|
yy = y - pos.y;
|
||||||
value = this.renderer.getValueFor(tile, step, xx, yy);
|
if (xx >= 0 && yy >= 0 && xx < this.renderer.TILE_SIZE && yy <= this.renderer.TILE_SIZE) {
|
||||||
}
|
value = this.renderer.getValueFor(tile, step, xx, yy);
|
||||||
if (value !== null) {
|
}
|
||||||
return value;
|
if (value !== null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return tile pos given screen x,y coordinates
|
||||||
|
*/
|
||||||
|
getTilePosForPixel: function(x, y) {
|
||||||
|
var t, tile, pos, xx, yy;
|
||||||
|
for(t in this._tiles) {
|
||||||
|
tile = this._tiles[t];
|
||||||
|
if (tile) {
|
||||||
|
pos = this.getTilePos(tile.coord);
|
||||||
|
xx = x - pos.x;
|
||||||
|
yy = y - pos.y;
|
||||||
|
if (xx >= 0 && yy >= 0 && xx < this.renderer.TILE_SIZE && yy <= this.renderer.TILE_SIZE) {
|
||||||
|
return {
|
||||||
|
x: xx,
|
||||||
|
y: yy,
|
||||||
|
tile: tile.coord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a list of the closest values for a given coord.
|
||||||
|
* returned format is [{ x: .., y: .., value: ...}, .. ]
|
||||||
|
*/
|
||||||
|
getClosestValuesFor: function(x, y, dist, step) {
|
||||||
|
var xf = x + dist,
|
||||||
|
yf = y + dist,
|
||||||
|
_x = x;
|
||||||
|
var values = []
|
||||||
|
for(_y = y; _y < yf; _y += this.options.resolution){
|
||||||
|
for(_x = x; _x < xf; _x += this.options.resolution){
|
||||||
|
var thisValue = this.getValueForPos(_x,_y);
|
||||||
|
if (thisValue !== null) {
|
||||||
|
var bb = thisValue.bbox;
|
||||||
|
var xy = this._map.latLngToContainerPoint([bb[0].lat, bb[0].lon]);
|
||||||
|
values.push({
|
||||||
|
x: xy.x,
|
||||||
|
y: xy.y,
|
||||||
|
value: thisValue.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
|
||||||
getValueForBBox: function(x, y, w, h) {
|
getValueForBBox: function(x, y, w, h) {
|
||||||
var xf = x + w, yf = y + h, _x=x;
|
var xf = x + w, yf = y + h, _x=x;
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
for(_y = y; _y<yf; _y+=this.options.resolution){
|
for(_y = y; _y < yf; _y += this.options.resolution){
|
||||||
for(_x = x; _x<xf; _x+=this.options.resolution){
|
for(_x = x; _x < xf; _x += this.options.resolution){
|
||||||
var thisValue = this.getValueForPos(_x,_y);
|
var thisValue = this.getValueForPos(_x,_y);
|
||||||
if (thisValue){
|
if (thisValue) {
|
||||||
var bb = thisValue.bbox;
|
var bb = thisValue.bbox;
|
||||||
var xy = this._map.latLngToContainerPoint([bb[1].lat, bb[1].lon]);
|
var xy = this._map.latLngToContainerPoint([bb[1].lat, bb[1].lon]);
|
||||||
if(xy.x < xf && xy.y < yf){
|
if(xy.x < xf && xy.y < yf){
|
||||||
@ -429,6 +482,20 @@ L.TorqueLayer = L.CanvasLayer.extend({
|
|||||||
return sum;
|
return sum;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** return the number of points for a step */
|
||||||
|
pointCount: function(step) {
|
||||||
|
var t, tile;
|
||||||
|
step = step === undefined ? this.key: step;
|
||||||
|
var c = 0;
|
||||||
|
for(t in this._tiles) {
|
||||||
|
tile = this._tiles[t];
|
||||||
|
if (tile) {
|
||||||
|
c += tile.timeCount[step];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
},
|
||||||
|
|
||||||
invalidate: function() {
|
invalidate: function() {
|
||||||
this.provider.reload();
|
this.provider.reload();
|
||||||
},
|
},
|
||||||
|
@ -31,13 +31,15 @@ var Filters = require('./torque_filters');
|
|||||||
"dst-atop": 'destination-atop',
|
"dst-atop": 'destination-atop',
|
||||||
"xor": 'xor',
|
"xor": 'xor',
|
||||||
"darken": 'darken',
|
"darken": 'darken',
|
||||||
"lighten": 'lighten'
|
"lighten": 'lighten',
|
||||||
|
"screen": "screen"
|
||||||
}
|
}
|
||||||
|
|
||||||
function compop2canvas(compop) {
|
function compop2canvas(compop) {
|
||||||
return COMP_OP_TO_CANVAS[compop] || compop;
|
return COMP_OP_TO_CANVAS[compop] || compop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// this renderer just render points depending of the value
|
// this renderer just render points depending of the value
|
||||||
//
|
//
|
||||||
@ -57,7 +59,7 @@ var Filters = require('./torque_filters');
|
|||||||
this.TILE_SIZE = 256;
|
this.TILE_SIZE = 256;
|
||||||
this._style = null;
|
this._style = null;
|
||||||
this._gradients = {};
|
this._gradients = {};
|
||||||
|
|
||||||
this._forcePoints = false;
|
this._forcePoints = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,11 +112,19 @@ var Filters = require('./torque_filters');
|
|||||||
// generate sprite based on cartocss style
|
// generate sprite based on cartocss style
|
||||||
//
|
//
|
||||||
generateSprite: function(shader, value, shaderVars) {
|
generateSprite: function(shader, value, shaderVars) {
|
||||||
var self = this;
|
|
||||||
var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
|
var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
|
||||||
var st = shader.getStyle({
|
var st = shader.getStyle({
|
||||||
value: value
|
value: value
|
||||||
}, shaderVars);
|
}, shaderVars);
|
||||||
|
|
||||||
|
var ret = this.generateSpriteForStyle(st);
|
||||||
|
prof.end(true);
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
|
||||||
|
generateSpriteForStyle: function(st) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
if(this._style === null || this._style !== st){
|
if(this._style === null || this._style !== st){
|
||||||
this._style = st;
|
this._style = st;
|
||||||
}
|
}
|
||||||
@ -148,9 +158,14 @@ var Filters = require('./torque_filters');
|
|||||||
cartocss.renderSprite(ctx, img, st);
|
cartocss.renderSprite(ctx, img, st);
|
||||||
} else {
|
} else {
|
||||||
// take into account the exterior ring to calculate the size
|
// take into account the exterior ring to calculate the size
|
||||||
var canvasSize = (st['marker-line-width'] || 0) + pointSize*2;
|
var canvasSize = (st['marker-line-width'] || 0) + pointSize*2 + 2;
|
||||||
var w = ctx.width = canvas.width = ctx.height = canvas.height = Math.ceil(canvasSize);
|
canvasSize = Math.ceil(canvasSize);
|
||||||
ctx.translate(w/2, w/2);
|
// the sprite should be placed in the center of a pixel not in the middle so
|
||||||
|
// make the canvas size odd
|
||||||
|
canvasSize += canvasSize % 2 === 0 ? 1 : 0;
|
||||||
|
var w = ctx.width = canvas.width = ctx.height = canvas.height = canvasSize;
|
||||||
|
w = Math.floor(w/2) + 1;
|
||||||
|
ctx.translate(w, w);
|
||||||
|
|
||||||
var mt = st['marker-type'];
|
var mt = st['marker-type'];
|
||||||
if (mt && mt === 'rectangle') {
|
if (mt && mt === 'rectangle') {
|
||||||
@ -159,13 +174,12 @@ var Filters = require('./torque_filters');
|
|||||||
cartocss.renderPoint(ctx, st);
|
cartocss.renderPoint(ctx, st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prof.end(true);
|
|
||||||
if (torque.flags.sprites_to_images) {
|
if (torque.flags.sprites_to_images) {
|
||||||
var i = this._createImage();
|
var i = this._createImage();
|
||||||
i.src = canvas.toDataURL();
|
i.src = canvas.toDataURL();
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -193,7 +207,7 @@ var Filters = require('./torque_filters');
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prof.end(true);
|
prof.end(true);
|
||||||
|
|
||||||
return callback && callback(null);
|
return callback && callback(null);
|
||||||
@ -237,12 +251,11 @@ var Filters = require('./torque_filters');
|
|||||||
},
|
},
|
||||||
|
|
||||||
//
|
//
|
||||||
// renders a tile in the canvas for key defined in
|
// renders a tile in the canvas for key defined in
|
||||||
// the torque tile
|
// the torque tile
|
||||||
//
|
//
|
||||||
_renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
|
_renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
|
||||||
if (!this._canvas) return;
|
if (!this._canvas) return;
|
||||||
|
|
||||||
var prof = Profiler.metric('torque.renderer.point.renderTile').start();
|
var prof = Profiler.metric('torque.renderer.point.renderTile').start();
|
||||||
var ctx = this._ctx;
|
var ctx = this._ctx;
|
||||||
var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
|
var blendMode = compop2canvas(shader.eval('comp-op')) || this.options.blendmode;
|
||||||
@ -259,22 +272,20 @@ var Filters = require('./torque_filters');
|
|||||||
if (activePixels) {
|
if (activePixels) {
|
||||||
var pixelIndex = tile.timeIndex[key];
|
var pixelIndex = tile.timeIndex[key];
|
||||||
for(var p = 0; p < activePixels; ++p) {
|
for(var p = 0; p < activePixels; ++p) {
|
||||||
var posIdx = tile.renderDataPos[pixelIndex + p];
|
var posIdx = tile.renderDataPos[pixelIndex + p];
|
||||||
var c = tile.renderData[pixelIndex + p];
|
var c = tile.renderData[pixelIndex + p];
|
||||||
if (c) {
|
var sp = sprites[c];
|
||||||
var sp = sprites[c];
|
if (sp === undefined) {
|
||||||
if (sp === undefined) {
|
sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
|
||||||
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 x = tile.x[posIdx]- (sp.width >> 1) + anchor;
|
var y = tileMax - tile.y[posIdx] + anchor; // flip mercator
|
||||||
var y = tileMax - tile.y[posIdx] + anchor; // flip mercator
|
ctx.drawImage(sp, x, y - (sp.height >> 1));
|
||||||
ctx.drawImage(sp, x, y - (sp.height >> 1));
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prof.end(true);
|
prof.end(true);
|
||||||
},
|
},
|
||||||
@ -442,7 +453,7 @@ var Filters = require('./torque_filters');
|
|||||||
}
|
}
|
||||||
gradient = {};
|
gradient = {};
|
||||||
var colorize = this._style['image-filters'].args;
|
var colorize = this._style['image-filters'].args;
|
||||||
|
|
||||||
var increment = 1/colorize.length;
|
var increment = 1/colorize.length;
|
||||||
for (var i = 0; i < colorize.length; i++){
|
for (var i = 0; i < colorize.length; i++){
|
||||||
var key = increment * i + increment;
|
var key = increment * i + increment;
|
||||||
@ -459,6 +470,8 @@ var Filters = require('./torque_filters');
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
PointRenderer.COMP_OP_TO_CANVAS = COMP_OP_TO_CANVAS;
|
||||||
|
|
||||||
|
|
||||||
// exports public api
|
// exports public api
|
||||||
module.exports = PointRenderer;
|
module.exports = PointRenderer;
|
||||||
|
@ -1,160 +1,65 @@
|
|||||||
|
var torque = require('../');
|
||||||
|
var cartocss = require('./cartocss_render');
|
||||||
|
var Profiler = require('../profiler');
|
||||||
var carto = global.carto || require('carto');
|
var carto = global.carto || require('carto');
|
||||||
|
var Filters = require('./torque_filters');
|
||||||
|
var PointRenderer = require('./point')
|
||||||
|
|
||||||
var DEFAULT_CARTOCSS = [
|
var PixelRenderer = function(canvas, options) {
|
||||||
'#layer {',
|
PointRenderer.call(this, canvas, options);
|
||||||
' polygon-fill: #FFFF00;',
|
}
|
||||||
' [value > 10] { polygon-fill: #FFFF00; }',
|
|
||||||
' [value > 100] { polygon-fill: #FFCC00; }',
|
|
||||||
' [value > 1000] { polygon-fill: #FE9929; }',
|
|
||||||
' [value > 10000] { polygon-fill: #FF6600; }',
|
|
||||||
' [value > 100000] { polygon-fill: #FF3300; }',
|
|
||||||
'}'
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
var TAU = Math.PI * 2;
|
torque.extend(PixelRenderer.prototype, PointRenderer.prototype, {
|
||||||
|
|
||||||
//
|
generateSprite: function(shader, value, shaderVars) {
|
||||||
// this renderer just render points depending of the value
|
var self = this;
|
||||||
//
|
var prof = Profiler.metric('torque.renderer.point.generateSprite').start();
|
||||||
function RectanbleRenderer(canvas, options) {
|
var st = shader.getStyle({
|
||||||
this.options = options;
|
value: value
|
||||||
carto.tree.Reference.set(torque['torque-reference']);
|
}, shaderVars);
|
||||||
this.setCanvas(canvas);
|
if(this._style === null || this._style !== st){
|
||||||
this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
|
this._style = st;
|
||||||
}
|
|
||||||
|
|
||||||
RectanbleRenderer.prototype = {
|
|
||||||
|
|
||||||
//
|
|
||||||
// sets the cartocss style to render stuff
|
|
||||||
//
|
|
||||||
setCartoCSS: function(cartocss) {
|
|
||||||
this._cartoCssStyle = new carto.RendererJS().render(cartocss);
|
|
||||||
if(this._cartoCssStyle.getLayers().length > 1) {
|
|
||||||
throw new Error("only one CartoCSS layer is supported");
|
|
||||||
}
|
|
||||||
this._shader = this._cartoCssStyle.getLayers()[0].shader;
|
|
||||||
},
|
|
||||||
|
|
||||||
setCanvas: function(canvas) {
|
|
||||||
if(!canvas) return;
|
|
||||||
this._canvas = canvas;
|
|
||||||
this._ctx = canvas.getContext('2d');
|
|
||||||
},
|
|
||||||
|
|
||||||
accumulate: function(tile, keys) {
|
|
||||||
var prof = Profiler.metric('RectangleRender:accumulate').start();
|
|
||||||
var x, y, posIdx, p, k, key, activePixels, pixelIndex;
|
|
||||||
var res = this.options.resolution;
|
|
||||||
var s = 256/res;
|
|
||||||
var accum = new Float32Array(s*s);
|
|
||||||
|
|
||||||
if(typeof(keys) !== 'object') {
|
|
||||||
keys = [keys];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(k = 0; k < keys.length; ++k) {
|
return {
|
||||||
key = keys[k];
|
width: st['marker-width'],
|
||||||
activePixels = tile.timeCount[key];
|
color: st['marker-fill'],
|
||||||
if(activePixels) {
|
fill_opacity: st['marker-fill-opacity'] === undefined ? 1.0: st['marker-fill-opacity']
|
||||||
pixelIndex = tile.timeIndex[key];
|
|
||||||
for(p = 0; p < activePixels; ++p) {
|
|
||||||
posIdx = tile.renderDataPos[pixelIndex + p];
|
|
||||||
x = tile.x[posIdx]/res;
|
|
||||||
y = tile.y[posIdx]/res;
|
|
||||||
accum[x*s + y] += tile.renderData[pixelIndex + p];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prof.end();
|
|
||||||
return accum;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderTileAccum: function(accum, px, py) {
|
_renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
|
||||||
var prof = Profiler.metric('RectangleRender:renderTileAccum').start();
|
if (!this._canvas) return;
|
||||||
var color, x, y, alpha;
|
var prof = Profiler.metric('torque.renderer.point.renderTile').start();
|
||||||
var res = this.options.resolution;
|
|
||||||
var ctx = this._ctx;
|
var ctx = this._ctx;
|
||||||
var s = (256/res) | 0;
|
if (this.options.cumulative && key > tile.maxDate) {
|
||||||
var s2 = s*s;
|
//TODO: precache because this tile is not going to change
|
||||||
var colors = this._colors;
|
key = tile.maxDate;
|
||||||
if(this.options.blendmode) {
|
|
||||||
ctx.globalCompositeOperation = this.options.blendmode;
|
|
||||||
}
|
}
|
||||||
var polygon_alpha = this._shader['polygon-opacity'] || function() { return 1.0; };
|
var tileMax = this.options.resolution * (this.TILE_SIZE/this.options.resolution - 1)
|
||||||
for(var i = 0; i < s2; ++i) {
|
var activePixels = tile.x.length;
|
||||||
var xy = i;
|
var anchor = this.options.resolution/2;
|
||||||
var value = accum[i];
|
if (activePixels) {
|
||||||
if(value) {
|
|
||||||
x = (xy/s) | 0;
|
|
||||||
y = xy % s;
|
|
||||||
// by-pass the style generation for improving performance
|
|
||||||
color = this._shader['polygon-fill']({ value: value }, { zoom: 0 });
|
|
||||||
ctx.fillStyle = color;
|
|
||||||
//TODO: each function should have a default value for each
|
|
||||||
//property defined in the cartocss
|
|
||||||
alpha = polygon_alpha({ value: value }, { zoom: 0 });
|
|
||||||
if(alpha === null) {
|
|
||||||
alpha = 1.0;
|
|
||||||
}
|
|
||||||
ctx.globalAlpha = alpha;
|
|
||||||
ctx.fillRect(x * res, 256 - res - y * res, res, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prof.end();
|
|
||||||
},
|
|
||||||
|
|
||||||
//
|
|
||||||
// renders a tile in the canvas for key defined in
|
|
||||||
// the torque tile
|
|
||||||
//
|
|
||||||
renderTile: function(tile, key, callback) {
|
|
||||||
if(!this._canvas) return;
|
|
||||||
|
|
||||||
var res = this.options.resolution;
|
|
||||||
|
|
||||||
//var prof = Profiler.get('render').start();
|
|
||||||
var ctx = this._ctx;
|
|
||||||
var colors = this._colors;
|
|
||||||
var activepixels = tile.timeCount[key];
|
|
||||||
if(activepixels) {
|
|
||||||
var w = this._canvas.width;
|
|
||||||
var h = this._canvas.height;
|
|
||||||
//var imageData = ctx.getImageData(0, 0, w, h);
|
|
||||||
//var pixels = imageData.data;
|
|
||||||
var pixelIndex = tile.timeIndex[key];
|
var pixelIndex = tile.timeIndex[key];
|
||||||
for(var p = 0; p < activePixels; ++p) {
|
for(var p = 0; p < activePixels; ++p) {
|
||||||
var posIdx = tile.renderDataPos[pixelIndex + p];
|
var posIdx = tile.renderDataPos[pixelIndex + p];
|
||||||
var c = tile.renderData[pixelIndex + p];
|
var c = tile.renderData[pixelIndex + p];
|
||||||
if(c) {
|
var sp = sprites[c];
|
||||||
var color = colors[Math.min(c, colors.length - 1)];
|
if (sp === undefined) {
|
||||||
var x = tile.x[posIdx];// + px;
|
sp = sprites[c] = this.generateSprite(shader, c, torque.extend({ zoom: tile.z, 'frame-offset': frame_offset }, shaderVars));
|
||||||
var y = tile.y[posIdx]; //+ py;
|
}
|
||||||
|
if (sp) {
|
||||||
ctx.fillStyle = color;
|
var x = tile.x[posIdx]- (sp.width >> 1) + anchor;
|
||||||
ctx.fillRect(x, y, res, res);
|
var y = tileMax - tile.y[posIdx] + anchor; // flip mercator
|
||||||
/*
|
if (sp.fill_opacity > 0) {
|
||||||
|
ctx.globalAlpha = sp.fill_opacity
|
||||||
for(var xx = 0; xx < res; ++xx) {
|
ctx.fillStyle = sp.color;
|
||||||
for(var yy = 0; yy < res; ++yy) {
|
ctx.fillRect(x, y, sp.width, sp.width);
|
||||||
var idx = 4*((x+xx) + w*(y + yy));
|
}
|
||||||
pixels[idx + 0] = color[0];
|
|
||||||
pixels[idx + 1] = color[1];
|
|
||||||
pixels[idx + 2] = color[2];
|
|
||||||
pixels[idx + 3] = color[3];
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//ctx.putImageData(imageData, 0, 0);
|
|
||||||
}
|
}
|
||||||
//prof.end();
|
|
||||||
return callback && callback(null);
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
|
module.exports = PixelRenderer;
|
||||||
// exports public api
|
|
||||||
module.exports = RectanbleRenderer;
|
|
||||||
|
Loading…
Reference in New Issue
Block a user