all add
This commit is contained in:
commit
1d377496e0
BIN
data/forma_08-05-12.zip
Normal file
BIN
data/forma_08-05-12.zip
Normal file
Binary file not shown.
53
index.html
Normal file
53
index.html
Normal file
@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
||||
<title>Layer exploration app for GFW</title>
|
||||
<link rel="shortcut icon" href="http://cartodb.com/favicon/favicon_32x32.ico" />
|
||||
<link href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="stylesheet" href="lib/cartodb.css">
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
|
||||
<script type="text/javascript" src="lib/wax.g.js"></script>
|
||||
<script type="text/javascript" src="lib/cartodb-gmapsv3.js"></script>
|
||||
<script type="text/javascript" src="lib/dat.gui.min.js"></script>
|
||||
<script type="text/javascript" src="lib/underscore-min.js"></script>
|
||||
<script type="text/javascript" src="lib/backbone.js"></script>
|
||||
<script type="text/javascript" src="lib/class.js"></script>
|
||||
<script type="text/javascript" src="lib/backbone.cartodb.js"></script>
|
||||
<script type="text/javascript" src="src/wri.js"></script>
|
||||
<script type="text/javascript">
|
||||
var gui;
|
||||
function initialize() {
|
||||
|
||||
// initialise the google map
|
||||
var map = new google.maps.Map(document.getElementById('map_canvas'), {
|
||||
center: new google.maps.LatLng(0,110),
|
||||
zoom: 5,
|
||||
mapTypeId: google.maps.MapTypeId.SATELLITE,
|
||||
mapTypeControl: false
|
||||
});
|
||||
|
||||
dat.GUI.DEFAULT_WIDTH = 300;
|
||||
gui = new dat.GUI();
|
||||
|
||||
WRI(function(env) {
|
||||
WRI.app = new env.app.Instance(map, {
|
||||
user : 'wri-01',
|
||||
layerTable : 'layerinfo',
|
||||
logging : true
|
||||
});
|
||||
WRI.app.run();
|
||||
WRI.env = env;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="initialize()">
|
||||
<div id="map_canvas"></div>
|
||||
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
|
||||
</body>
|
||||
</html>
|
210
lib/backbone.cartodb.js
Normal file
210
lib/backbone.cartodb.js
Normal file
@ -0,0 +1,210 @@
|
||||
|
||||
/**
|
||||
*
|
||||
* backbone cartodb adapter
|
||||
*
|
||||
* this is a small library that allows to use Backbone with models
|
||||
* to work with data stored in CartoDB (a geospatial database on
|
||||
* the cloud, see more info at http://cartodb.com).
|
||||
*
|
||||
* it does NOT overrride Backbone.sync
|
||||
*
|
||||
*/
|
||||
|
||||
Backbone.CartoDB = function(options, query, cache) {
|
||||
|
||||
options = _.defaults(options, {
|
||||
USE_PROXY: false,
|
||||
user: ''
|
||||
});
|
||||
|
||||
function _SQL(sql) {
|
||||
this.sql = sql;
|
||||
}
|
||||
function SQL(sql) {
|
||||
return new _SQL(sql);
|
||||
}
|
||||
|
||||
// SQL("{0} is {1}").format("CartoDB", "epic!");
|
||||
_SQL.prototype.format = function() {
|
||||
var str = this.sql,
|
||||
len = arguments.length+1;
|
||||
var safe, arg;
|
||||
for (i=0; i < len; arg = arguments[i++]) {
|
||||
safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
|
||||
str = str.replace(RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
var resource_path= options.user + '.cartodb.com/api/v1/sql';
|
||||
var resource_url = 'https://' + resource_path;
|
||||
|
||||
/**
|
||||
* fetch sql from the server
|
||||
*
|
||||
* this function should be changed if you're working on node
|
||||
*
|
||||
*/
|
||||
query = query || function(sql, callback, proxy) {
|
||||
var url = resource_url;
|
||||
var crossDomain = true;
|
||||
if(proxy) {
|
||||
url = 'api/v0/proxy/' + resource_url;
|
||||
crossDomain = false;
|
||||
}
|
||||
if(sql.length > 1500) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
crossDomain: crossDomain,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: 'q=' + encodeURIComponent(sql),
|
||||
success: callback,
|
||||
error: function(){
|
||||
if(proxy) {
|
||||
callback();
|
||||
} else {
|
||||
//try fallback
|
||||
if(USE_PROXY) {
|
||||
query(sql, callback, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// TODO: add timeout
|
||||
$.getJSON(resource_url + '?q=' + encodeURIComponent(sql) + '&callback=?')
|
||||
.success(callback)
|
||||
.fail(function(){
|
||||
callback();
|
||||
}).complete(function() {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var dummy_cache = {
|
||||
setItem: function(key, value) { },
|
||||
getItem: function(key) { return null; },
|
||||
removeItem: function(key) { }
|
||||
};
|
||||
|
||||
cache = cache && dummy_cache;
|
||||
|
||||
|
||||
var CartoDBModel = Backbone.Model.extend({
|
||||
|
||||
_create_sql: function() {
|
||||
var where = SQL(" where {0} = '{1}'").format(
|
||||
this.columns[this.what],
|
||||
this.get(this.what).replace("'", "''")
|
||||
);
|
||||
var select = this._sql_select();
|
||||
var sql = 'select ' + select.join(',') + ' from ' + this.table + where;
|
||||
return sql;
|
||||
},
|
||||
|
||||
_sql_select: function() {
|
||||
var select = [];
|
||||
for(var k in this.columns) {
|
||||
var w = this.columns[k];
|
||||
if(w.indexOf('ST_') !== -1 || w === "the_geom") {
|
||||
select.push(SQL('ST_AsGeoJSON({1}) as {0}').format(k,w));
|
||||
} else {
|
||||
select.push(SQL('{1} as {0}').format(k, w));
|
||||
}
|
||||
}
|
||||
return select;
|
||||
},
|
||||
|
||||
_parse_columns: function(row) {
|
||||
var parsed = {};
|
||||
for(var k in row) {
|
||||
var v = row[k];
|
||||
var c = this.columns[k];
|
||||
if (c.indexOf('ST_') !== -1 || c === "the_geom") {
|
||||
parsed[k] = JSON.parse(v);
|
||||
} else {
|
||||
parsed[k] = row[k];
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
},
|
||||
|
||||
fetch: function() {
|
||||
var self = this;
|
||||
query(this._create_sql(), function(data) {
|
||||
self.set(self._parse_columns(data.rows[0]));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* cartodb collection created from a sql composed using 'columns' and
|
||||
* 'table' attributes defined in a child class
|
||||
*
|
||||
* var C = CartoDBCollection.extend({
|
||||
* table: 'table',
|
||||
* columns: ['c1', 'c2']
|
||||
* });
|
||||
* var c = new C();
|
||||
* c.fetch();
|
||||
*/
|
||||
var CartoDBCollection = Backbone.Collection.extend({
|
||||
|
||||
_create_sql: function() {
|
||||
var tables = this.table;
|
||||
if(!_.isArray(this.table)) {
|
||||
tables = [this.table];
|
||||
}
|
||||
tables = tables.join(',');
|
||||
var select = CartoDBModel.prototype._sql_select.call(this);
|
||||
var sql = 'select ' + select.join(',') + ' from ' + this.table;
|
||||
if (this.where) {
|
||||
sql += " WHERE " + this.where;
|
||||
}
|
||||
return sql;
|
||||
},
|
||||
|
||||
fetch: function() {
|
||||
var self = this;
|
||||
var sql = this.sql || this._create_sql();
|
||||
if(typeof(sql) === "function") {
|
||||
sql = sql.call(this);
|
||||
}
|
||||
var item = this.cache ? cache.getItem(sql): false;
|
||||
if(!item) {
|
||||
query(sql, function(data) {
|
||||
if(this.cache) {
|
||||
try {
|
||||
cache.setItem(sql, JSON.stringify(data.rows));
|
||||
} catch(e) {}
|
||||
}
|
||||
var rows;
|
||||
if(!self.sql) {
|
||||
rows = _.map(data.rows, function(r) {
|
||||
return CartoDBModel.prototype._parse_columns.call(self, r);
|
||||
});
|
||||
} else {
|
||||
rows = data.rows;
|
||||
}
|
||||
self.reset(rows);
|
||||
});
|
||||
} else {
|
||||
self.reset(JSON.parse(item));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
query: query,
|
||||
CartoDBCollection: CartoDBCollection,
|
||||
CartoDBModel: CartoDBModel,
|
||||
SQL: SQL
|
||||
};
|
||||
|
||||
};
|
1159
lib/backbone.js
Normal file
1159
lib/backbone.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
lib/blank_tile.png
Normal file
BIN
lib/blank_tile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 116 B |
2799
lib/carto.js
Normal file
2799
lib/carto.js
Normal file
File diff suppressed because it is too large
Load Diff
542
lib/cartodb-gmapsv3.js
Normal file
542
lib/cartodb-gmapsv3.js
Normal file
@ -0,0 +1,542 @@
|
||||
/**
|
||||
* @name cartodb-gmapsv3 for Google Maps V3 API
|
||||
* @version 0.2 [December 14, 2011]
|
||||
* @author: xavijam@gmail.com
|
||||
* @fileoverview <b>Author:</b> xavijam@gmail.com<br/> <b>Licence:</b>
|
||||
* Licensed under <a
|
||||
* href="http://opensource.org/licenses/mit-license.php">MIT</a>
|
||||
* license.<br/> This library lets you use CartoDB with google
|
||||
* maps v3.
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @name google
|
||||
* @class The fundamental namespace for Google APIs
|
||||
*/
|
||||
/**
|
||||
* @name google.maps
|
||||
* @class The fundamental namespace for Google Maps V3 API
|
||||
*/
|
||||
/*
|
||||
* - Map style of cartodb
|
||||
* - Infowindow of cartodb
|
||||
* - Tiles style of cartodb
|
||||
*/
|
||||
|
||||
// Namespace
|
||||
var CartoDB = CartoDB || {};
|
||||
|
||||
(function($) {
|
||||
if (typeof(google.maps.CartoDBLayer) === "undefined") {
|
||||
/**
|
||||
* @params {}
|
||||
* map_canvas - Gmapsv3 canvas id (necesary for showing the infowindow)
|
||||
* map - Your gmapsv3 map
|
||||
* user_name - CartoDB user name
|
||||
* table_name CartoDB table name
|
||||
* query If you want to apply any sql sentence to the table...
|
||||
* tile_style - If you want to add other style to the layer
|
||||
* map_style - If you want to see the map styles created on cartodb (opcional - default = false)
|
||||
* infowindow - If you want to see infowindows when click in a geometry (opcional - default = false)
|
||||
* auto_bound - Let cartodb auto-bound-zoom in the map (opcional - default = false)
|
||||
* debug - Do you want to debug the library? Set to true
|
||||
*/
|
||||
|
||||
google.maps.CartoDBLayer = function (params) {
|
||||
|
||||
this.params = params;
|
||||
this.params.feature = params.infowindow;
|
||||
|
||||
if (this.params.map_style) setCartoDBMapStyle(this.params); // Map style? ok, let's style.
|
||||
if (this.params.auto_bound) autoBound(this.params); // Bounds? CartoDB does it.
|
||||
|
||||
if (this.params.infowindow) {
|
||||
addWaxCartoDBTiles(this.params);
|
||||
} else {
|
||||
addSimpleCartoDBTiles(this.params); // Always add cartodb tiles, simple or with wax.
|
||||
}
|
||||
|
||||
this.params.visible = true;
|
||||
this.params.active = true;
|
||||
|
||||
// Zoom to cartodb geometries
|
||||
function autoBound(params) {
|
||||
// Zoom to your geometries
|
||||
// If the table is private you can't auto zoom without being authenticated
|
||||
if (!params.map_key) {
|
||||
$.ajax({
|
||||
url:'http://'+params.user_name+'.cartodb.com/api/v1/sql/?q='+escape('select ST_Extent(the_geom) from '+ params.table_name),
|
||||
dataType: 'jsonp',
|
||||
timeout: 2000,
|
||||
callbackParameter: 'callback',
|
||||
success: function(result) {
|
||||
if (result.rows[0].st_extent!=null) {
|
||||
var coordinates = result.rows[0].st_extent.replace('BOX(','').replace(')','').split(',');
|
||||
|
||||
var coor1 = coordinates[0].split(' ');
|
||||
var coor2 = coordinates[1].split(' ');
|
||||
var bounds = new google.maps.LatLngBounds();
|
||||
|
||||
// Check bounds
|
||||
if (coor1[0] > 180 || coor1[0] < -180 || coor1[1] > 90 || coor1[1] < -90
|
||||
|| coor2[0] > 180 || coor2[0] < -180 || coor2[1] > 90 || coor2[1] < -90) {
|
||||
coor1[0] = '-30';
|
||||
coor1[1] = '-50';
|
||||
coor2[0] = '110';
|
||||
coor2[1] = '80';
|
||||
}
|
||||
|
||||
bounds.extend(new google.maps.LatLng(coor1[1],coor1[0]));
|
||||
bounds.extend(new google.maps.LatLng(coor2[1],coor2[0]));
|
||||
|
||||
params.map.fitBounds(bounds);
|
||||
}
|
||||
},
|
||||
error: function(e,msg) {
|
||||
params.debug && console.debug('Error setting table bounds: ' + msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Set the map styles of your cartodb table/map
|
||||
function setCartoDBMapStyle(params) {
|
||||
$.ajax({
|
||||
url: 'http://' + params.user_name + '.cartodb.com/tiles/' + params.table_name + '/map_metadata?'+ 'map_key=' + (params.map_key || ''),
|
||||
dataType: 'jsonp',
|
||||
timeout: 2000,
|
||||
callbackParameter: 'callback',
|
||||
success: function(result) {
|
||||
var map_style = $.parseJSON(result.map_metadata);
|
||||
|
||||
if (!map_style || map_style.google_maps_base_type=="roadmap") {
|
||||
params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
|
||||
} else if (map_style.google_maps_base_type=="satellite") {
|
||||
params.map.setOptions({mapTypeId: google.maps.MapTypeId.SATELLITE});
|
||||
} else if (map_style.google_maps_base_type=="terrain") {
|
||||
params.map.setOptions({mapTypeId: google.maps.MapTypeId.TERRAIN});
|
||||
} else {
|
||||
var mapStyles = [ { stylers: [ { saturation: -65 }, { gamma: 1.52 } ] },{ featureType: "administrative", stylers: [ { saturation: -95 }, { gamma: 2.26 } ] },{ featureType: "water", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "administrative.locality", stylers: [ { visibility: "off" } ] },{ featureType: "road", stylers: [ { visibility: "simplified" }, { saturation: -99 }, { gamma: 2.22 } ] },{ featureType: "poi", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "road.arterial", stylers: [ { visibility: "off" } ] },{ featureType: "road.local", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "transit", stylers: [ { visibility: "off" } ] },{ featureType: "road", elementType: "labels", stylers: [ { visibility: "off" } ] },{ featureType: "poi", stylers: [ { saturation: -55 } ] } ];
|
||||
map_style.google_maps_customization_style = mapStyles;
|
||||
params.map.setOptions({mapTypeId: google.maps.MapTypeId.ROADMAP});
|
||||
}
|
||||
|
||||
// Custom tiles
|
||||
if (!map_style) {
|
||||
map_style = {google_maps_customization_style: []};
|
||||
}
|
||||
params.map.setOptions({styles: map_style.google_maps_customization_style});
|
||||
},
|
||||
error: function(e, msg) {
|
||||
params.debug && console.debug('Error setting map style: ' + msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add cartodb tiles to the map
|
||||
function addSimpleCartoDBTiles(params) {
|
||||
// Add the cartodb tiles
|
||||
var cartodb_layer = {
|
||||
getTileUrl: function(coord, zoom) {
|
||||
return 'http://' + params.user_name + '.cartodb.com/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query;
|
||||
},
|
||||
tileSize: new google.maps.Size(256, 256),
|
||||
name: params.query,
|
||||
description: false
|
||||
};
|
||||
params.layer = new google.maps.ImageMapType(cartodb_layer);
|
||||
params.map.overlayMapTypes.insertAt(0,params.layer);
|
||||
}
|
||||
|
||||
// Add cartodb tiles to the map
|
||||
function addWaxCartoDBTiles(params) {
|
||||
// interaction placeholder
|
||||
var currentCartoDbId;
|
||||
|
||||
params.tilejson = generateTileJson(params);
|
||||
params.infowindow = new CartoDB.Infowindow(params);
|
||||
params.cache_buster = 0;
|
||||
|
||||
params.waxOptions = {
|
||||
callbacks: {
|
||||
out: function(){
|
||||
params.map.setOptions({draggableCursor: 'default'});
|
||||
},
|
||||
over: function(feature, div, opt3, evt){
|
||||
params.map.setOptions({draggableCursor: 'pointer'});
|
||||
},
|
||||
click: function(feature, div, opt3, evt){
|
||||
// If there are more than one cartodb layer, close all possible infowindows
|
||||
params.infowindow.hideAll();
|
||||
params.infowindow.open(feature,evt.latLng);
|
||||
}
|
||||
},
|
||||
clickAction: 'full'
|
||||
};
|
||||
|
||||
params.layer = new wax.g.connector(params.tilejson);
|
||||
|
||||
params.map.overlayMapTypes.insertAt(0,params.layer);
|
||||
params.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
|
||||
}
|
||||
|
||||
// Refresh wax interaction
|
||||
function refreshWax(params,sql) {
|
||||
if (params.infowindow) {
|
||||
params.cache_buster++;
|
||||
params.query = sql;
|
||||
params.tilejson = generateTileJson(params);
|
||||
|
||||
// Remove old wax
|
||||
removeOldLayer(params.map,params.layer);
|
||||
|
||||
// Setup new wax
|
||||
params.tilejson.grids = wax.util.addUrlData(params.tilejson.grids_base, 'cache_buster=' + params.cache_buster);
|
||||
|
||||
// Add map tiles
|
||||
params.layer = new wax.g.connector(params.tilejson);
|
||||
params.map.overlayMapTypes.insertAt(0,params.layer);
|
||||
|
||||
// Add interaction
|
||||
params.interaction.remove();
|
||||
params.interaction = wax.g.interaction(params.map, params.tilejson, params.waxOptions);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh tiles
|
||||
function refreshTiles(params,sql) {
|
||||
// If you are not using interaction on the tiles... let's update your tiles
|
||||
if (!params.infowindow) {
|
||||
|
||||
// First remove previous cartodb - tiles.
|
||||
removeOldLayer(params.map,params.layer);
|
||||
|
||||
// Then add the cartodb tiles
|
||||
params.query = sql;
|
||||
var cartodb_layer = {
|
||||
getTileUrl: function(coord, zoom) {
|
||||
return 'http://' + params.user_name + '.cartodb.com/tiles/' + params.table_name + '/'+zoom+'/'+coord.x+'/'+coord.y+'.png?sql='+params.query;
|
||||
},
|
||||
tileSize: new google.maps.Size(256, 256),
|
||||
name: params.query,
|
||||
description: false
|
||||
};
|
||||
|
||||
params.layer = new google.maps.ImageMapType(cartodb_layer);
|
||||
params.map.overlayMapTypes.insertAt(0,params.layer);
|
||||
}
|
||||
}
|
||||
|
||||
function generateTileJson(params) {
|
||||
var core_url = 'http://' + params.user_name + '.cartodb.com';
|
||||
var base_url = core_url + '/tiles/' + params.table_name + '/{z}/{x}/{y}';
|
||||
var tile_url = base_url + '.png?cache_buster=0';
|
||||
var grid_url = base_url + '.grid.json';
|
||||
|
||||
// SQL?
|
||||
if (params.query) {
|
||||
var query = 'sql=' + params.query;
|
||||
tile_url = wax.util.addUrlData(tile_url, query);
|
||||
grid_url = wax.util.addUrlData(grid_url, query);
|
||||
}
|
||||
|
||||
// Map key ?
|
||||
if (params.map_key) {
|
||||
var map_key = 'map_key=' + params.map_key;
|
||||
tile_url = wax.util.addUrlData(tile_url,map_key);
|
||||
grid_url = wax.util.addUrlData(grid_url,map_key);
|
||||
}
|
||||
|
||||
// Tiles style ?
|
||||
if (params.tile_style) {
|
||||
var style = 'style=' + encodeURIComponent(params.tile_style);
|
||||
tile_url = wax.util.addUrlData(tile_url,style);
|
||||
grid_url = wax.util.addUrlData(grid_url,style);
|
||||
}
|
||||
|
||||
// Build up the tileJSON
|
||||
// TODO: make a blankImage a real 'empty tile' image
|
||||
return {
|
||||
blankImage: 'blank_tile.png',
|
||||
tilejson: '1.0.0',
|
||||
scheme: 'xyz',
|
||||
tiles: [tile_url],
|
||||
grids: [grid_url],
|
||||
tiles_base: tile_url,
|
||||
grids_base: grid_url,
|
||||
name: params.query,
|
||||
description: true,
|
||||
formatter: function(options, data) {
|
||||
currentCartoDbId = data.cartodb_id;
|
||||
return data.cartodb_id;
|
||||
},
|
||||
cache_buster: function(){
|
||||
return params.cache_buster;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Remove old cartodb layer added (wax or imagemaptype)
|
||||
function removeOldLayer(map,layer) {
|
||||
if (layer) {
|
||||
var pos = -1;
|
||||
map.overlayMapTypes.forEach(function(map_type,i){
|
||||
if (layer == map_type && map_type.name == layer.name && map_type.description == layer.description) {
|
||||
pos = i;
|
||||
}
|
||||
});
|
||||
if (pos!=-1)
|
||||
map.overlayMapTypes.removeAt(pos);
|
||||
layer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update tiles & interactivity layer;
|
||||
google.maps.CartoDBLayer.prototype.update = function(sql) {
|
||||
// Hide the infowindow
|
||||
if (this.params.infowindow)
|
||||
this.params.infowindow.hide();
|
||||
// Refresh wax
|
||||
refreshWax(this.params,sql);
|
||||
// Refresh tiles
|
||||
refreshTiles(this.params,sql);
|
||||
|
||||
this.params.active = true;
|
||||
this.params.visible = true;
|
||||
};
|
||||
|
||||
// Destroy layers from the map
|
||||
google.maps.CartoDBLayer.prototype.destroy = function() {
|
||||
// First remove previous cartodb - tiles.
|
||||
removeOldLayer(this.params.map,this.params.layer);
|
||||
|
||||
if (this.params.infowindow) {
|
||||
// Remove wax interaction
|
||||
this.params.interaction.remove();
|
||||
this.params.infowindow.hide();
|
||||
}
|
||||
|
||||
this.params.active = false;
|
||||
};
|
||||
|
||||
// Hide layers from the map
|
||||
google.maps.CartoDBLayer.prototype.hide = function() {
|
||||
this.destroy();
|
||||
this.params.visible = false;
|
||||
};
|
||||
|
||||
// Show layers from the map
|
||||
google.maps.CartoDBLayer.prototype.show = function() {
|
||||
if (!this.params.visible || !this.params.active) {
|
||||
this.update(this.params.query);
|
||||
this.params.visible = true;
|
||||
}
|
||||
};
|
||||
|
||||
// CartoDB layer visible?
|
||||
google.maps.CartoDBLayer.prototype.isVisible = function() {
|
||||
return this.params.visible;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* CartoDB.Infowindow
|
||||
* @xavijam
|
||||
**/
|
||||
CartoDB.Infowindow = function (params) {
|
||||
this.latlng_ = new google.maps.LatLng(0,0);
|
||||
this.feature_;
|
||||
this.map_ = params.map;
|
||||
this.columns_;
|
||||
this.offsetHorizontal_ = -107;
|
||||
this.width_ = 214;
|
||||
this.setMap(params.map);
|
||||
this.params_ = params;
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype = new google.maps.OverlayView();
|
||||
|
||||
CartoDB.Infowindow.prototype.draw = function() {
|
||||
var me = this;
|
||||
|
||||
var div = this.div_;
|
||||
if (!div) {
|
||||
div = this.div_ = document.createElement('DIV');
|
||||
div.className = "cartodb_infowindow";
|
||||
|
||||
div.innerHTML = '<a href="#close" class="close">x</a>'+
|
||||
'<div class="outer_top">'+
|
||||
'<div class="top">'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<div class="bottom">'+
|
||||
'<label>id:1</label>'+
|
||||
'</div>';
|
||||
|
||||
$(div).find('a.close').click(function(ev){
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
me.hide();
|
||||
});
|
||||
|
||||
google.maps.event.addDomListener(div,'click',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
|
||||
google.maps.event.addDomListener(div,'dblclick',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
|
||||
google.maps.event.addDomListener(div,'mousedown',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
|
||||
google.maps.event.addDomListener(div,'mouseup',function(ev){ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;});
|
||||
google.maps.event.addDomListener(div,'mousewheel',function(ev){ev.stopPropagation();});
|
||||
google.maps.event.addDomListener(div,'DOMMouseScroll',function(ev){ev.stopPropagation();});
|
||||
|
||||
var panes = this.getPanes();
|
||||
panes.floatPane.appendChild(div);
|
||||
|
||||
div.style.opacity = 0;
|
||||
}
|
||||
|
||||
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
|
||||
if (pixPosition) {
|
||||
div.style.width = this.width_ + 'px';
|
||||
div.style.left = (pixPosition.x - 49) + 'px';
|
||||
var actual_height = - $(div).height();
|
||||
div.style.top = (pixPosition.y + actual_height + 5) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.setPosition = function() {
|
||||
if (this.div_) {
|
||||
var div = this.div_;
|
||||
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
|
||||
if (pixPosition) {
|
||||
div.style.width = this.width_ + 'px';
|
||||
div.style.left = (pixPosition.x - 49) + 'px';
|
||||
var actual_height = - $(div).height();
|
||||
div.style.top = (pixPosition.y + actual_height + 10) + 'px';
|
||||
}
|
||||
this.show();
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.open = function(feature,latlng){
|
||||
var that = this
|
||||
, infowindow_sql = 'SELECT * FROM ' + this.params_.table_name + ' WHERE cartodb_id=' + feature;
|
||||
that.feature_ = feature;
|
||||
|
||||
// If the table is private, you can't run any api methods
|
||||
if (this.params_.feature!=true) {
|
||||
infowindow_sql = encodeURIComponent(this.params_.feature.replace('{{feature}}',feature));
|
||||
}
|
||||
|
||||
|
||||
$.ajax({
|
||||
url:'http://'+ this.params_.user_name +'.cartodb.com/api/v1/sql/?q='+infowindow_sql,
|
||||
dataType: 'jsonp',
|
||||
timeout: 2000,
|
||||
callbackParameter: 'callback',
|
||||
success: function(result) {
|
||||
positionateInfowindow(result.rows[0],latlng);
|
||||
},
|
||||
error: function(e,msg) {
|
||||
that.params_.debug && console.debug('Error retrieving infowindow variables: ' + msg);
|
||||
}
|
||||
});
|
||||
|
||||
function positionateInfowindow(variables,center) {
|
||||
if (that.div_) {
|
||||
var div = that.div_;
|
||||
// Get latlng position
|
||||
that.latlng_ = latlng;
|
||||
|
||||
// Remove the unnecessary html
|
||||
$('div.cartodb_infowindow div.outer_top div.top').html('');
|
||||
$('div.cartodb_infowindow div.outer_top div.bottom label').html('');
|
||||
|
||||
// List all the new variables
|
||||
for (p in variables) {
|
||||
if (p!='cartodb_id' && p!='cdb_centre' && p!='the_geom_webmercator') {
|
||||
$('div.cartodb_infowindow div.outer_top div.top').append('<label>'+p+'</label><p class="'+((variables[p]!=null && variables[p]!='')?'':'empty')+'">'+(variables[p] || 'empty')+'</p>');
|
||||
}
|
||||
}
|
||||
|
||||
// Show cartodb_id?
|
||||
if (variables['cartodb_id']) {
|
||||
$('div.cartodb_infowindow div.bottom label').html('id: <strong>'+feature+'</strong>');
|
||||
}
|
||||
|
||||
that.moveMaptoOpen();
|
||||
that.setPosition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.hide = function() {
|
||||
if (this.div_) {
|
||||
var div = this.div_;
|
||||
$(div).animate({
|
||||
top: '+=' + 10 + 'px',
|
||||
opacity: 0},
|
||||
100, 'swing',
|
||||
function () {
|
||||
div.style.visibility = "hidden";
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.show = function() {
|
||||
if (this.div_) {
|
||||
var div = this.div_;
|
||||
div.style.opacity = 0;
|
||||
div.style.visibility = "visible";
|
||||
$(div).animate({
|
||||
top: '-=' + 10 + 'px',
|
||||
opacity: 1},
|
||||
250
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.hideAll = function() {
|
||||
$('div.cartodb_infowindow').css('visibility','hidden');
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.isVisible = function(marker_id) {
|
||||
if (this.div_) {
|
||||
var div = this.div_;
|
||||
if (div.style.visibility == 'visible' && this.feature_!=null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.transformGeoJSON = function(str) {
|
||||
var json = $.parseJSON(str);
|
||||
return new google.maps.LatLng(json.coordinates[1],json.coordinates[0]);
|
||||
};
|
||||
|
||||
CartoDB.Infowindow.prototype.moveMaptoOpen = function() {
|
||||
var left = 0;
|
||||
var top = 0;
|
||||
var div = this.div_;
|
||||
var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.latlng_);
|
||||
|
||||
if ((pixPosition.x + this.offsetHorizontal_) < 0) {
|
||||
left = (pixPosition.x + this.offsetHorizontal_ - 20);
|
||||
}
|
||||
|
||||
if ((pixPosition.x + 180) >= ($('#'+this.params_.map_canvas).width())) {
|
||||
left = (pixPosition.x + 180 - $('#'+this.params_.map_canvas).width());
|
||||
}
|
||||
|
||||
if ((pixPosition.y - $(div).height()) < 0) {
|
||||
top = (pixPosition.y - $(div).height() - 30);
|
||||
}
|
||||
|
||||
this.map_.panBy(left,top);
|
||||
};
|
||||
|
||||
})(jQuery);
|
25
lib/cartodb.css
Normal file
25
lib/cartodb.css
Normal file
@ -0,0 +1,25 @@
|
||||
/*other stuff*/
|
||||
/*Marker infowindow*/
|
||||
div.cartodb_infowindow {position:absolute; display:block; width:214px; padding:0; visibility:hidden;}
|
||||
div.cartodb_infowindow a.close {position:absolute; right:3px; top:3px; width:22px; height:15px; padding:4px 0 3px 0; text-align:center; font:bold 15px "Helvetica",Arial; color:#666666; text-decoration:none; line-height:15px}
|
||||
div.cartodb_infowindow a.close:hover {color:#333333}
|
||||
div.cartodb_infowindow div.outer_top {width:186px; padding:25px 18px 5px 10px; background:url('sprite.png') 0 top;}
|
||||
div.cartodb_infowindow div.top {width:186px; max-height:200px; overflow-y:auto; overflow-x:hidden}
|
||||
div.cartodb_infowindow div.top .jspTrack {background: #dddddd;}
|
||||
div.cartodb_infowindow div.top .jspDrag {background: #999999;}
|
||||
div.cartodb_infowindow div.top .jspHover, div.cartodb_infowindow div.top .jspActive {background:#666666}
|
||||
div.cartodb_infowindow div.top label {display:block; width:auto; padding:0 0 0 5px; font:normal 11px Arial; color:#B3B3B3; text-shadow:0 1px white}
|
||||
div.cartodb_infowindow div.top p {display:block; width:170px; max-height:20px; padding:2px 4px; margin:2px 0 7px; font:bold 11px 'Helvetica',Arial; color:#666666; border:none; background:none; text-shadow:0 1px white;
|
||||
text-overflow:ellipsis; overflow:hidden; white-space:nowrap;}
|
||||
div.cartodb_infowindow div.top p.empty {font-weight:normal; font-style:italic; color:#b7b7b7;}
|
||||
/*div.cartodb_infowindow div.top p:focus {border:1px solid #666666; border-radius:5px; -webkit-border-radius:5px; -moz-border-radius:5px;}*/
|
||||
div.cartodb_infowindow div.bottom {width:180px; height:36px; padding:11px 16px 10px 10px; background:url('sprite.png') no-repeat right top;}
|
||||
div.cartodb_infowindow div.bottom label {float:left; margin:5px 0 0 3px; font:normal 11px Arial; color:#B3B3B3; text-shadow:0 1px white}
|
||||
div.cartodb_infowindow div.bottom label strong {font:bold 11px 'Helvetica',Arial; color:#666666; text-shadow:0 1px white;}
|
||||
div.cartodb_infowindow div.bottom a {float:right; height:12px; margin:0 5px 0 0; padding:4px 7px; border:1px solid #999; font:bold 11px "Helvetica",Arial; color:#333333; text-align:center;
|
||||
text-decoration:none; -webkit-border-radius:3px; -moz-border-radius:3px; border-radius:3px; text-shadow:0 1px white; background:linear-gradient(-90deg, #FFFFFF, #CACBCE); background:-webkit-gradient(linear, 50% 0%, 50% 100%, from(#FFFFFF), to(#CACBCE));
|
||||
background:-moz-linear-gradient(-90deg, #FFFFFF, #CACBCE); background: -o-linear-gradient(#FFFFFF,#CACBCE); filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#FFFFFF', endColorstr='#CACBCE');}
|
||||
div.cartodb_infowindow div.bottom a:hover {background:linear-gradient(-90deg, #CACBCE, #FFFFFF); background:-webkit-gradient(linear, 50% 0%, 50% 100%, from(#CACBCE), to(#FFFFFF));
|
||||
background:-moz-linear-gradient(-90deg, #CACBCE, #FFFFFF); background: -o-linear-gradient(#CACBCE,#FFFFFF); filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#CACBCE', endColorstr='#FFFFFF'); cursor:pointer;}
|
||||
a.cartodb_logo {position:absolute; bottom:8px; left:75px; display:block; width:69px; height:27px; background:url('http://cartodb.s3.amazonaws.com/embed/embed_sprite.png') no-repeat -61px 0;
|
||||
text-indent:-9999px; line-height:0; font-size:0;}
|
66
lib/class.js
Normal file
66
lib/class.js
Normal file
@ -0,0 +1,66 @@
|
||||
/* Simple JavaScript Inheritance
|
||||
* By John Resig http://ejohn.org/
|
||||
* MIT Licensed.
|
||||
*/
|
||||
// Inspired by base2 and Prototype
|
||||
(function(){
|
||||
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function(){};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Class.extend = Class.implement = function(prop) {
|
||||
var _super = this.prototype;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
var prototype = new this();
|
||||
initializing = false;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
(function(name, fn){
|
||||
return function() {
|
||||
var tmp = this._super;
|
||||
|
||||
// Add a new ._super() method that is the same method
|
||||
// but on the super-class
|
||||
this._super = _super[name];
|
||||
|
||||
// The method only need to be bound temporarily, so we
|
||||
// remove it when we're done executing
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if ( !initializing && this.init )
|
||||
this.init.apply(this, arguments);
|
||||
}
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
Class.implement = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
|
||||
|
||||
})();
|
94
lib/dat.gui.min.js
vendored
Normal file
94
lib/dat.gui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2945
lib/modestmaps.js
Executable file
2945
lib/modestmaps.js
Executable file
File diff suppressed because it is too large
Load Diff
BIN
lib/sprite.png
Normal file
BIN
lib/sprite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
31
lib/underscore-min.js
vendored
Normal file
31
lib/underscore-min.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Underscore.js 1.3.1
|
||||
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
||||
// Underscore is freely distributable under the MIT license.
|
||||
// Portions of Underscore are inspired or borrowed from Prototype,
|
||||
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
||||
// For all details and documentation:
|
||||
// http://documentcloud.github.com/underscore
|
||||
(function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
|
||||
c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,
|
||||
h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each=
|
||||
b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===n)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===n)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(x&&a.map===x)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==
|
||||
null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=
|
||||
function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e=
|
||||
e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
|
||||
function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&(e={value:a,computed:b})});
|
||||
return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){f==0?b[0]=a:(d=Math.floor(Math.random()*(f+1)),b[f]=b[d],b[d]=a)});return b};b.sortBy=function(a,c,d){return b.pluck(b.map(a,function(a,b,g){return{value:a,criteria:c.call(d,a,b,g)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,
|
||||
c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:a.toArray?a.toArray():b.isArray(a)?i.call(a):b.isArguments(a)?i.call(a):b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=b.head=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=
|
||||
b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,e=[];b.reduce(d,function(d,g,h){if(0==h||(c===true?b.last(d)!=g:!b.include(d,g)))d[d.length]=g,e[e.length]=a[h];return d},[]);
|
||||
return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,
|
||||
d){if(a==null)return-1;var e;if(d)return d=b.sortedIndex(a,c),a[d]===c?d:-1;if(p&&a.indexOf===p)return a.indexOf(c);for(d=0,e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(D&&a.lastIndexOf===D)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){arguments.length<=1&&(b=a||0,a=0);for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;)g[f++]=a,a+=d;return g};
|
||||
var F=function(){};b.bind=function(a,c){var d,e;if(a.bind===s&&s)return s.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));F.prototype=a.prototype;var b=new F,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,
|
||||
c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(a,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i=b.debounce(function(){h=g=false},c);return function(){d=this;e=arguments;var b;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);i()},c));g?h=true:
|
||||
a.apply(d,e);i();g=true}};b.debounce=function(a,b){var d;return function(){var e=this,f=arguments;clearTimeout(d);d=setTimeout(function(){d=null;a.apply(e,f)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};
|
||||
b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments,
|
||||
1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};
|
||||
b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};
|
||||
b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
|
||||
function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
|
||||
u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
|
||||
function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
|
||||
true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
|
2766
lib/wax.g.js
Normal file
2766
lib/wax.g.js
Normal file
File diff suppressed because it is too large
Load Diff
53
sql/down_sample.sql
Normal file
53
sql/down_sample.sql
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
--Run loop for each zoom 16-7, 15-6 respectively
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 15 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=16
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 14 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=15
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 13 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=14
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 12 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=13
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 11 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=12
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 10 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=11
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 9 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=10
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 8 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=9
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 7 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=8
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 6 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=7
|
||||
) foo GROUP BY x,y
|
||||
);
|
||||
|
72
sql/forma.carto
Normal file
72
sql/forma.carto
Normal file
@ -0,0 +1,72 @@
|
||||
#forma_zoom_polys{
|
||||
line-color:#FFFFFF;
|
||||
line-width:0;
|
||||
line-opacity:1;
|
||||
polygon-opacity:0;
|
||||
[zoom>=10][z=16]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=9][z=15]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=8][z=14]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=7][z=13]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=6][z=12]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=5][z=11]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=4][z=10]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=3][z=9]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=2][z=8]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=1][z=7]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=0][z=6]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
|
||||
}
|
||||
#forma_zoom_polys[alerts<=54860] {
|
||||
polygon-fill:#B10026
|
||||
}
|
||||
#forma_zoom_polys[alerts<=5000] {
|
||||
polygon-fill:#E31A1C
|
||||
}
|
||||
#forma_zoom_polys[alerts<=500] {
|
||||
polygon-fill:#FC4E2A
|
||||
}
|
||||
#forma_zoom_polys[alerts<=50] {
|
||||
polygon-fill:#FD8D3C
|
||||
}
|
||||
#forma_zoom_polys[alerts<=5] {
|
||||
polygon-fill:#FEB24C
|
||||
}
|
||||
#forma_zoom_polys[alerts<=2] {
|
||||
polygon-fill:#FED976
|
||||
}
|
||||
#forma_zoom_polys[alerts<=1] {
|
||||
polygon-fill:#FFFFB2
|
||||
}
|
72
sql/forma2.carto
Normal file
72
sql/forma2.carto
Normal file
@ -0,0 +1,72 @@
|
||||
#forma_zoom_polys{
|
||||
line-color:#FFFFFF;
|
||||
line-width:0;
|
||||
line-opacity:1;
|
||||
polygon-opacity:0;
|
||||
[zoom>=10][z=16]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=9][z=15]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=8][z=14]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=7][z=13]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=6][z=12]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=5][z=11]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=4][z=10]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=3][z=9]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=2][z=8]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=1][z=7]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
[zoom=0][z=6]{
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.8;
|
||||
}
|
||||
|
||||
}
|
||||
#forma_zoom_polys[alerts>alerts] {
|
||||
polygon-fill:#662506
|
||||
}
|
||||
#forma_zoom_polys[alerts<=5000] {
|
||||
polygon-fill:#993404
|
||||
}
|
||||
#forma_zoom_polys[alerts<=500] {
|
||||
polygon-fill:#EC7014
|
||||
}
|
||||
#forma_zoom_polys[alerts<=50] {
|
||||
polygon-fill:#FE9929
|
||||
}
|
||||
#forma_zoom_polys[alerts<=5] {
|
||||
polygon-fill:#FEC44F
|
||||
}
|
||||
#forma_zoom_polys[alerts<=2] {
|
||||
polygon-fill:#FEE391
|
||||
}
|
||||
#forma_zoom_polys[alerts<=1] {
|
||||
polygon-fill:#FFF7BC
|
||||
}
|
1
sql/junk.sql
Normal file
1
sql/junk.sql
Normal file
@ -0,0 +1 @@
|
||||
select cartodb_id,ST_Intersection(CASE WHEN ST_Dimension(ST_Snap(ST_CollectionExtract(ST_SnapToGrid(ST_CollectionExtract(ST_Simplify("the_geom", 0.0006866455078125), ST_Dimension( "the_geom") + 1 ), 0.001373291015625), ST_Dimension( "the_geom") + 1 ), ST_SnapToGrid(ST_Expand(ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326), 0.00274658203125),0.001373291015625), 0.001373291015625)) = 0 OR GeometryType(ST_Snap(ST_CollectionExtract(ST_SnapToGrid(ST_CollectionExtract(ST_Simplify("the_geom", 0.0006866455078125), ST_Dimension( "the_geom") + 1 ), 0.001373291015625), ST_Dimension( "the_geom") + 1 ), ST_SnapToGrid(ST_Expand(ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326), 0.00274658203125),0.001373291015625), 0.001373291015625)) = 'GEOMETRYCOLLECTION' THEN ST_Snap(ST_CollectionExtract(ST_SnapToGrid(ST_CollectionExtract(ST_Simplify("the_geom", 0.0006866455078125), ST_Dimension( "the_geom") + 1 ), 0.001373291015625), ST_Dimension( "the_geom") + 1 ), ST_SnapToGrid(ST_Expand(ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326), 0.00274658203125),0.001373291015625), 0.001373291015625) ELSE ST_CollectionExtract(ST_MakeValid(ST_Snap(ST_CollectionExtract(ST_SnapToGrid(ST_CollectionExtract(ST_Simplify("the_geom", 0.0006866455078125), ST_Dimension( "the_geom") + 1 ), 0.001373291015625), ST_Dimension( "the_geom") + 1 ), ST_SnapToGrid(ST_Expand(ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326), 0.00274658203125),0.001373291015625), 0.001373291015625)), ST_Dimension("the_geom") + 1 ) END, ST_SnapToGrid(ST_Expand(ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326), 0.00274658203125),0.001373291015625)) as the_geom,alerts from forma_zoom_polys WHERE the_geom && ST_MakeEnvelope(0.3515625,51.17934297928927,0.703125,51.39920565355378, 4326)&format=geojson&dp=6
|
40
sql/pixels_to_polys.sql
Normal file
40
sql/pixels_to_polys.sql
Normal file
@ -0,0 +1,40 @@
|
||||
ogr2ogr -f "PostgreSQL" PG:"user=cartodb_user_2 dbname=cartodb_user_2_db" forma_120120424-24445-iu0g79.csv -nln forma_months
|
||||
53182,32275,16,
|
||||
--Run once to merge Robins data where he has multiple events for the same polygon
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 16 as z FROM (
|
||||
SELECT x, y, period AS undate FROM forma_input WHERE z=16
|
||||
) foo GROUP BY x,y
|
||||
)
|
||||
|
||||
## SEE DOWNSAMPLE
|
||||
--Run loop for each zoom 16-7, 15-6 respectively
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 15 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=16
|
||||
) foo GROUP BY x,y
|
||||
)
|
||||
|
||||
|
||||
--update the_geom for points
|
||||
SET statement_timeout TO 0; UPDATE forma_data SET the_geom = ST_Transform(ST_SetSRId(ST_Point( ((x*256) * (156543.03392804062 / (2^z)) - 20037508.342789244), -(((y)*256) * (156543.03392804062 / (2^z)) - 20037508.342789244)), 3857), 4326) WHERE the_geom IS NULL;
|
||||
|
||||
--create polygons
|
||||
SET statement_timeout TO 0; DELETE FROM forma_zoom_polys; INSERT INTO forma_zoom_polys (the_geom,z,alerts) (SELECT st_multi(st_transform(ST_Envelope(ST_SetSRId(ST_Collect( ST_Point( ((x*256.0) * (156543.03392804062 / (2^z)) - 20037508.342789244), -(((y)*256.0) * (156543.03392804062 / (2^z)) - 20037508.342789244)), ST_Point( (((x+1.0)*256.0) * (156543.03392804062 / (2^z)) - 20037508.342789244), -(((y-1.0)*256.0) * (156543.03392804062 / (2^z)) - 20037508.342789244)) ), 3857)),4326)) as the_geom,z,array_length(date_array,1) FROM forma_data);
|
||||
|
||||
--create arrays of distinct dates
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 15 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=16
|
||||
) foo GROUP BY x,y,undate
|
||||
)
|
||||
|
||||
--create arrays of all dates
|
||||
INSERT INTO forma_data (x,y,date_array,z) (
|
||||
SELECT x, y, array_agg(undate) as date_array, 13 as z FROM (
|
||||
SELECT floor(x/2) as x, floor(y/2) as y, unnest(date_array) AS undate FROM forma_data WHERE z=14
|
||||
) foo GROUP BY x,y
|
||||
)
|
||||
|
||||
[zoom>=10][z=16]{marker-width:1;}
|
||||
[zoom=9][z=15]{marker-width:1;}
|
128
src/mapdig.js
Normal file
128
src/mapdig.js
Normal file
@ -0,0 +1,128 @@
|
||||
var MAPDIG = {};
|
||||
|
||||
MAPDIG.create = function(carto_user, table_name, ignore, default_width) {
|
||||
var me = {
|
||||
generated_sql: 'SELECT * FROM ' + table_name,
|
||||
SQL: 'SELECT * FROM ' + table_name,
|
||||
table: table_name,
|
||||
carto_user: carto_user,
|
||||
ignore: ['cartodb_id', 'the_geom', 'the_geom_webmercator', 'updated_at', 'created_at'].concat(ignore),
|
||||
numbers: {},
|
||||
strings: {},
|
||||
origin_numbers: {},
|
||||
default_width: default_width
|
||||
};
|
||||
|
||||
me.toSQL = function(){
|
||||
var sql = this.SQL;
|
||||
var filter_sql = [];
|
||||
|
||||
_.each(this.numbers, function(val,key){
|
||||
if (this.origin_numbers[key] != val){
|
||||
var root = key.split(' ')[0]
|
||||
var cap = key.split(' ')[1]
|
||||
if (cap == 'min'){
|
||||
filter_sql.push(root + '>=' + val);
|
||||
} else {
|
||||
filter_sql.push(root + '<=' + val)
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
_.each(this.strings, function(val,key){
|
||||
if (val != '*'){
|
||||
filter_sql.push(key + ' LIKE \'%25' + val + '%25\'');
|
||||
}
|
||||
}, this);
|
||||
|
||||
return ((filter_sql.length < 1) ? sql : sql + ' WHERE ' + filter_sql.join(' AND '));
|
||||
};
|
||||
|
||||
me.init = function(cartodb_layer){
|
||||
var c, n1, s1, f1, tmp_dat; // holders for event handlers and reflected columns
|
||||
var that = this;
|
||||
that.layer = cartodb_layer;
|
||||
dat.GUI.DEFAULT_WIDTH = that.default_width;
|
||||
that.gui = new dat.GUI();
|
||||
|
||||
// Direct SQL input
|
||||
c = that.gui.add(that, 'generated_sql').name('Map SQL');
|
||||
c.onFinishChange(function(value) { that.executeSQL(value); });
|
||||
|
||||
// Attempt to reflect table structure and attach controls and events for all columns found
|
||||
// Currently does this long hand as cannot access schema. dumb, but works
|
||||
$.getJSON('http://'+that.carto_user+'.cartodb.com/api/v2/sql/?q=select%20*%20from%20' + that.table +'%20limit%201', function(data){
|
||||
|
||||
// grab the top value in each col, strip ignores
|
||||
var cols = [];
|
||||
_.each(data.rows[0],function(val,key){
|
||||
if (!_.include(that.ignore, key)){
|
||||
cols.push('max("'+key+'") as ' + key);
|
||||
}
|
||||
});
|
||||
|
||||
// sample a value from each column to determine GUI element type
|
||||
$.getJSON('http://'+that.carto_user+'.cartodb.com/api/v2/sql/?q=select%20'+cols.join(',') +'%20from%20' + that.table +'%20limit%201', function(data){
|
||||
n1 = that.gui.addFolder('Numeric filter');
|
||||
s1 = that.gui.addFolder('Text filter');
|
||||
_.each(data.rows[0], function(val,key){
|
||||
if(_.isNumber(val)){
|
||||
$.getJSON('http://'+that.carto_user+'.cartodb.com/api/v2/sql/?q=select min("'+key+'"), max("'+key+'") from ' + that.table, function(data){
|
||||
if (data.rows[0].max > data.rows[0].min){
|
||||
//f1 = n1.addFolder(key);
|
||||
|
||||
that.numbers[key+' min'] = data.rows[0].min;
|
||||
that.numbers[key+' max'] = data.rows[0].max;
|
||||
that.origin_numbers[key+' min'] = data.rows[0].min;
|
||||
that.origin_numbers[key+' max'] = data.rows[0].max;
|
||||
|
||||
c = n1.add(that.numbers, key+' min', data.rows[0].min, data.rows[0].max);
|
||||
c.onFinishChange(function(value) { that.renderSQL(); });
|
||||
c = n1.add(that.numbers, key+' max', data.rows[0].min, data.rows[0].max);
|
||||
c.onFinishChange(function(value) { that.renderSQL(); });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// test if it's massive - if so, text box, else dropdown.
|
||||
if(_.isString(val)){
|
||||
$.getJSON('http://'+that.carto_user+'.cartodb.com/api/v2/sql/?q=select count(distinct("'+key+'")) from ' + that.table, function(data){
|
||||
if (data.rows[0].count <= 1000 && data.rows[0].count > 0){
|
||||
$.getJSON('http://'+that.carto_user+'.cartodb.com/api/v2/sql/?q=select distinct("'+key+'") as ele from ' + that.table + ' ORDER BY ELE ASC', function(data){
|
||||
tmp_dat = _.map(data.rows, function(r){ return r.ele; });
|
||||
tmp_dat.unshift('*');
|
||||
that.strings[key] = '*';
|
||||
c = s1.add(that.strings, key, tmp_dat );
|
||||
c.onFinishChange(function(value) { that.renderSQL(); });
|
||||
});
|
||||
} else {
|
||||
that.strings[key] = '*';
|
||||
c = s1.add(that.strings,key);
|
||||
c.onFinishChange(function(value) { that.renderSQL(); });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// disabled as buggy
|
||||
//this.gui.remember(this);
|
||||
};
|
||||
|
||||
me.executeSQL = function(sql){
|
||||
this.layer.update(sql);
|
||||
};
|
||||
|
||||
me.renderSQL = function(){
|
||||
this.generated_sql = this.toSQL();
|
||||
for (var i in this.gui.__controllers) {
|
||||
this.gui.__controllers[i].updateDisplay();
|
||||
}
|
||||
this.layer.update(this.generated_sql);
|
||||
};
|
||||
|
||||
return me;
|
||||
};
|
||||
|
||||
|
376
src/wri.js
Normal file
376
src/wri.js
Normal file
@ -0,0 +1,376 @@
|
||||
function WRI() {
|
||||
var args = Array.prototype.slice.call(arguments),
|
||||
callback = args.pop(),
|
||||
modules = (args[0] && typeof args[0] === "string") ? args : args[0],
|
||||
config,
|
||||
i;
|
||||
|
||||
if (!(this instanceof WRI)) {
|
||||
return new WRI(modules, callback);
|
||||
}
|
||||
|
||||
if (!modules || modules === '*') {
|
||||
modules = [];
|
||||
for (i in WRI.modules) {
|
||||
if (WRI.modules.hasOwnProperty(i)) {
|
||||
modules.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < modules.length; i += 1) {
|
||||
WRI.modules[modules[i]](this);
|
||||
}
|
||||
|
||||
callback(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
WRI.modules = {};
|
||||
|
||||
|
||||
|
||||
WRI.modules.app = function(wri) {
|
||||
|
||||
wri.app = {};
|
||||
|
||||
wri.app.Instance = Class.extend(
|
||||
{
|
||||
init: function(map, options) {
|
||||
this.options = _.defaults(options, {
|
||||
user : 'wri-01',
|
||||
layerTable : 'layerinfo',
|
||||
});
|
||||
|
||||
this._precision = 2;
|
||||
|
||||
wri.log.enabled = options ? options.logging: false;
|
||||
|
||||
this._map = map;
|
||||
|
||||
this._map.overlayMapTypes.push(null);
|
||||
|
||||
this.lastHash = null;
|
||||
|
||||
this._cartodb = Backbone.CartoDB({user: this.options.user});
|
||||
|
||||
this.datalayers = new wri.datalayers.Engine(this._cartodb, options.layerTable, this._map);
|
||||
|
||||
this._setHash();
|
||||
|
||||
|
||||
},
|
||||
run: function() {
|
||||
this._setupListeners();
|
||||
this.update();
|
||||
wri.log.info('App is now running!');
|
||||
},
|
||||
_setHash: function(){
|
||||
if (location.hash.split("/").length != 3){
|
||||
var hash = "#5/0/110"
|
||||
console.log("HASH RESET");
|
||||
console.log(location.hash);
|
||||
location.replace(hash);
|
||||
this.lastHash = hash;
|
||||
}
|
||||
},
|
||||
_setupListeners: function(){
|
||||
var that = this;
|
||||
//setup zoom listener
|
||||
google.maps.event.addListener(this._map, 'zoom_changed', function() {
|
||||
var hash = "#" + this.getZoom() + "/" + this.getCenter().lat().toFixed(that._precision) +"/" + this.getCenter().lng().toFixed(that._precision);
|
||||
if (that.lastHash != hash) {
|
||||
location.replace(hash);
|
||||
that.lastHash = hash;
|
||||
}
|
||||
});
|
||||
google.maps.event.addListener(this._map, 'center_changed', function() {
|
||||
var hash = "#" + this.getZoom() + "/" + this.getCenter().lat().toFixed(that._precision) +"/" + this.getCenter().lng().toFixed(that._precision);
|
||||
if (that.lastHash != hash) {
|
||||
location.replace(hash);
|
||||
that.lastHash = hash;
|
||||
}
|
||||
});
|
||||
},
|
||||
parseHash: function(hash) {
|
||||
var args = hash.split("/");
|
||||
if (args.length == 3) {
|
||||
var zoom = parseInt(args[0], 10),
|
||||
lat = parseFloat(args[1]),
|
||||
lon = parseFloat(args[2]);
|
||||
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
|
||||
return false;
|
||||
} else {
|
||||
return {
|
||||
center: new google.maps.LatLng(lat, lon),
|
||||
zoom: zoom
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
update: function() {
|
||||
var hash = location.hash;
|
||||
if (hash === this.lastHash) {
|
||||
// console.info("(no change)");
|
||||
return;
|
||||
}
|
||||
var sansHash = hash.substr(1),
|
||||
parsed = this.parseHash(sansHash);
|
||||
if (parsed) {
|
||||
this._map.setZoom(parsed.zoom);
|
||||
this._map.setCenter(parsed.center);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
WRI.modules.maplayer = function(wri) {
|
||||
wri.maplayer = {};
|
||||
wri.maplayer.Engine = Class.extend(
|
||||
{
|
||||
init: function(layer, map) {
|
||||
this.layer = layer;
|
||||
this._map = map;
|
||||
this._bindDisplay(new wri.maplayer.Display());
|
||||
this._options = this._display.getOptions(this.layer.get('tileurl'), this.layer.get('ispng'));
|
||||
// this._boundingbox = this.layer.get('the_geom');
|
||||
var sw = new google.maps.LatLng(this.layer.get('ymin'), this.layer.get('xmin'));
|
||||
var ne = new google.maps.LatLng(this.layer.get('ymax'),this.layer.get('xmax'));
|
||||
this._bounds = new google.maps.LatLngBounds(sw, ne);
|
||||
wri.log.info(this._options.getTileUrl({x: 3, y: 4},3));
|
||||
this._displayed = false;
|
||||
this._addControll();
|
||||
this._maptype = new google.maps.ImageMapType(this._options);
|
||||
|
||||
this._tileindex = this._map.overlayMapTypes.length;
|
||||
this._map.overlayMapTypes.setAt(this._tileindex, null);
|
||||
this._setupListeners();
|
||||
|
||||
this._handleLayer();
|
||||
},
|
||||
_setupListeners: function(){
|
||||
var that = this;
|
||||
//setup zoom listener
|
||||
google.maps.event.addListener(this._map, 'zoom_changed', function() {
|
||||
that._inZoom(true);
|
||||
that._handleLayer();
|
||||
});
|
||||
google.maps.event.addListener(this._map, 'center_changed', function() {
|
||||
that._inBounds(true);
|
||||
that._handleLayer();
|
||||
});
|
||||
this._inZoom(true);
|
||||
this._inBounds(true);
|
||||
},
|
||||
_inZoom: function(reset){
|
||||
if (this._inZoomVal==null){
|
||||
this._inZoomVal = true;
|
||||
}
|
||||
if(reset){
|
||||
if (this.layer.get('zmin')<=this._map.getZoom() && this._map.getZoom()<=this.layer.get('zmax')) {
|
||||
this._inZoomVal = true;
|
||||
} else {
|
||||
this._inZoomVal = false;
|
||||
}
|
||||
}
|
||||
return this._inZoomVal;
|
||||
},
|
||||
_inBounds: function(reset){
|
||||
if (this._inBoundsVal==null){
|
||||
this._inBoundsVal = true;
|
||||
}
|
||||
if(reset){
|
||||
var bounds = this._map.getBounds();
|
||||
var ne = bounds.getNorthEast();
|
||||
var sw = bounds.getSouthWest();
|
||||
if (this._bounds.intersects(bounds)){
|
||||
this._inBoundsVal = true;
|
||||
} else {
|
||||
this._inBoundsVal = false;
|
||||
}
|
||||
}
|
||||
return this._inBoundsVal;
|
||||
},
|
||||
_inView: function(){
|
||||
if (this._inZoom(false) && this._inBounds(false)) {
|
||||
return true;
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
_handleLayer: function(){
|
||||
if(this.layer.get('visible') && !this._displayed && this._inView()){
|
||||
this._displayed = true;
|
||||
this._map.overlayMapTypes.setAt(this._tileindex, this._maptype);
|
||||
wri.log.info(this.layer.get('title')+ " added at "+this._tileindex)
|
||||
} else if (this._displayed && !this._inView()){
|
||||
this._displayed = false;
|
||||
this._map.overlayMapTypes.setAt(this._tileindex, null);
|
||||
wri.log.info(this.layer.get('title')+ " removed at "+this._tileindex)
|
||||
}
|
||||
},
|
||||
_addControll: function(){
|
||||
var that = this;
|
||||
|
||||
this._opacity = {alpha: 100};
|
||||
this.toggle = gui.addFolder(this.layer.get('title'));;
|
||||
this.toggle
|
||||
.add(this.layer.attributes, 'visible')
|
||||
.onChange(function(value) {
|
||||
wri.log.info(value);
|
||||
that._toggleLayer();
|
||||
});
|
||||
this.toggle
|
||||
.add(this._opacity,'alpha').min(0).max(100).step(5)
|
||||
.name('transparency')
|
||||
.onChange(function(value) {
|
||||
that._maptype.setOpacity(value/100);
|
||||
});
|
||||
var zoomTo = function(){
|
||||
var self = that;
|
||||
this.zoomExtents = function(){
|
||||
self._map.fitBounds(self._bounds);
|
||||
}
|
||||
}
|
||||
this.toggle
|
||||
.add(new zoomTo(), 'zoomExtents')
|
||||
|
||||
|
||||
},
|
||||
_bindDisplay: function(display) {
|
||||
var that = this;
|
||||
this._display = display;
|
||||
display.setEngine(this);
|
||||
},
|
||||
_toggleLayer: function(){
|
||||
var that = this;
|
||||
if (this.layer.get('visible') == false){
|
||||
wri.log.info('LAYER OFF');
|
||||
this._map.overlayMapTypes.setAt(this._tileindex, null);
|
||||
//this._map.overlayMapTypes.setAt(this._tileindex, null);
|
||||
} else {
|
||||
wri.log.info('LAYER ON');
|
||||
if(this._inView()){
|
||||
this._displayed = true;
|
||||
this._map.overlayMapTypes.setAt(this._tileindex, this._maptype);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
wri.maplayer.Display = Class.extend(
|
||||
{
|
||||
/**
|
||||
* Constructs a new Display with the given DOM element.
|
||||
*/
|
||||
init: function() {
|
||||
wri.log.info('displayed');
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the engine for this display.
|
||||
*
|
||||
* @param engine a mol.ui.Engine subclass
|
||||
*/
|
||||
setEngine: function(engine) {
|
||||
this._engine = engine;
|
||||
},
|
||||
getTileUrl: function(tile, zoom) {
|
||||
var that = this;
|
||||
var url = that.tileurl.replace(RegExp('\\{Z}', 'g'), zoom);
|
||||
url = url.replace(RegExp('\\{X}', 'g'), tile.x);
|
||||
url = url.replace(RegExp('\\{Y}', 'g'), tile.y);
|
||||
return url;
|
||||
},
|
||||
getOptions: function(tileurl, ispng){
|
||||
var that = this;
|
||||
var options = {
|
||||
alt: "MapServer Layer",
|
||||
getTileUrl: this.getTileUrl,
|
||||
tileurl: tileurl,
|
||||
isPng: ispng,
|
||||
maxZoom: 17,
|
||||
minZoom: 1,
|
||||
name: "MapServer Layer",
|
||||
tileSize: new google.maps.Size(256, 256)
|
||||
};
|
||||
return options;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
WRI.modules.datalayers = function(wri) {
|
||||
wri.datalayers = {};
|
||||
wri.datalayers.Engine = Class.extend(
|
||||
{
|
||||
init: function(CartoDB, layerTable, map) {
|
||||
this._map = map;
|
||||
this._bycartodbid = {};
|
||||
this._bytitle = {};
|
||||
this._dataarray = [];
|
||||
this._cartodb = CartoDB;
|
||||
var LayersColl = this._cartodb.CartoDBCollection.extend({
|
||||
sql: function(){
|
||||
return "SELECT title, zmin, zmax, ST_XMAX(the_geom) as xmax,ST_XMIN(the_geom) as xmin,ST_YMAX(the_geom) as ymax,ST_YMIN(the_geom) as ymin, tileurl, true as visible FROM " + layerTable + " WHERE display = True ORDER BY displaylayer ASC"
|
||||
}
|
||||
});
|
||||
this.LayersObj = new LayersColl();
|
||||
this.LayersObj.fetch();
|
||||
this._loadLayers();
|
||||
},
|
||||
_loadLayers: function(){
|
||||
var that = this;
|
||||
this.LayersObj.bind('reset', function() {
|
||||
that.LayersObj.each(function(p){that._addLayer(p)});
|
||||
});
|
||||
},
|
||||
_addLayer: function(p){
|
||||
wri.log.warn('only showing baselayers for now');
|
||||
//if (p.get('category')=='baselayer'){
|
||||
var layer = new wri.maplayer.Engine(p, this._map);
|
||||
this._dataarray.push(layer);
|
||||
this._bycartodbid[p.get('cartodb_id')] = layer;
|
||||
this._bytitle[p.get('title')] = layer;
|
||||
//}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Logging module that writes log messages to the console and to the Speed
|
||||
* Tracer API. It contains convenience methods for info(), warn(), error(),
|
||||
* and todo().
|
||||
*
|
||||
*/
|
||||
WRI.modules.log = function(wri) {
|
||||
wri.log = {};
|
||||
|
||||
wri.log.info = function(msg) {
|
||||
wri.log._write('INFO: ' + msg);
|
||||
};
|
||||
|
||||
wri.log.warn = function(msg) {
|
||||
wri.log._write('WARN: ' + msg);
|
||||
};
|
||||
|
||||
wri.log.error = function(msg) {
|
||||
wri.log._write('ERROR: ' + msg);
|
||||
};
|
||||
|
||||
wri.log.todo = function(msg) {
|
||||
wri.log._write('TODO: '+ msg);
|
||||
};
|
||||
|
||||
wri.log._write = function(msg) {
|
||||
var logger = window.console;
|
||||
if (wri.log.enabled) {
|
||||
if (logger && logger.markTimeline) {
|
||||
logger.markTimeline(msg);
|
||||
}
|
||||
console.log(msg);
|
||||
}
|
||||
};
|
||||
};
|
174
styler/index.html
Normal file
174
styler/index.html
Normal file
@ -0,0 +1,174 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Styling tool for GFW</title>
|
||||
|
||||
<script type="text/javascript" src="src/core.js"></script>
|
||||
<script type="text/javascript" src="src/settings.js"></script>
|
||||
<script type="text/javascript" src="src/mercator.js"></script>
|
||||
<script type="text/javascript" src="src/geometry.js"></script>
|
||||
<script type="text/javascript" src="src/model.js"></script>
|
||||
<script type="text/javascript" src="src/renderer.js"></script>
|
||||
<script type="text/javascript" src="src/shader.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="src/cartodb.sql.js"></script>
|
||||
<script type="text/javascript" src="src/cartodb.provider.js"></script>
|
||||
|
||||
<!-- carto -->
|
||||
<script src='../lib/underscore-min.js' type='text/javascript'></script>
|
||||
<script src='../lib/carto.js' type='text/javascript'></script>
|
||||
|
||||
<script type="text/javascript" src="../lib/modestmaps.js"></script>
|
||||
<script type="text/javascript" src="src/vecnik.modestmaps.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/carto.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var map;
|
||||
function initMap() {
|
||||
VECNIK.Carto.init(function(carto) {
|
||||
VECNIK.Carto.compile(
|
||||
"#world { line-width: 2; line-color: #f00; [TYPEY='test']{ line-width: 2; } [ZOOM = 0]{ line-width: 2; } }"
|
||||
, function() {});
|
||||
});
|
||||
|
||||
var template = 'http://b.tiles.mapbox.com/v3/mapbox.mapbox-streets/{Z}/{X}/{Y}.png';
|
||||
// template = 'http://b.tiles.mapbox.com/v3/mapbox.mapbox-light/{Z}/{X}/{Y}.png64';
|
||||
// template = 'http://b.tile.stamen.com/terrain-background/{Z}/{X}/{Y}.jpg';
|
||||
|
||||
template = "http://oatile1.mqcdn.com/tiles/1.0.0/sat/{Z}/{X}/{Y}.jpg"
|
||||
var subdomains = [ 'oatile1', 'oatile2.', 'oatile3.', 'oatile4.' ];
|
||||
var provider = new MM.TemplatedLayer(template, subdomains);
|
||||
|
||||
var dataSource = new VECNIK.CartoDB.API({
|
||||
user: 'wri-01',
|
||||
table: 'forma_zoom_polys',
|
||||
columns: ['alerts'], //do not include the_geom or cartodb_id, are implicit
|
||||
ENABLE_CLIPPING: true,
|
||||
ENABLE_SIMPLIFY: true,
|
||||
ENABLE_FIXING: true,
|
||||
ENABLE_SNAPPING: true,
|
||||
debug: true
|
||||
});
|
||||
|
||||
var shader = new VECNIK.CartoShader({
|
||||
'point-color': '#fff',
|
||||
'line-color': '#fff',
|
||||
'line-width': function(data) {
|
||||
if(data.type === 'primary') {
|
||||
return '3';
|
||||
}
|
||||
return '1';
|
||||
},
|
||||
'polygon-fill': function(data) {
|
||||
return "rgba(200, 200, 200, 0.8)";
|
||||
}
|
||||
});
|
||||
|
||||
var vector_layer = new VECNIK.MM.CanvasProvider(dataSource, shader);
|
||||
fg = new MM.Layer(vector_layer);
|
||||
|
||||
map = new MM.Map(document.getElementById('map'), [provider, fg])
|
||||
|
||||
if(!location.hash) {
|
||||
map.setCenterZoom(new MM.Location(3.7, 102.8), 4);
|
||||
}
|
||||
var hash = new MM.Hash(map);
|
||||
|
||||
|
||||
var code = document.getElementById('code')
|
||||
var codeOld= '';
|
||||
var compileShader = _.debounce(function() {
|
||||
VECNIK.Carto.compile(code.value , function(shaderData) {
|
||||
if(shaderData) {
|
||||
//console.log(code.value);
|
||||
shader.compile(shaderData);
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
code.onkeyup = function() {
|
||||
if(code.value != codeOld) {
|
||||
compileShader();
|
||||
codeOld = code.value;
|
||||
}
|
||||
}
|
||||
compileShader(code.value);
|
||||
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
html, body, #map {
|
||||
width: 100%; height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#livecode {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 450px;
|
||||
padding-left: 10px;
|
||||
box-shadow: 0px 0px 5px 6px #ccc;
|
||||
}
|
||||
textarea {
|
||||
color: rgba(0,0,0,0.9);
|
||||
background-color:rgba(255,255,255,0.92);
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
width: 350px;
|
||||
border: 0;
|
||||
outline: none;
|
||||
|
||||
}
|
||||
/* code */
|
||||
.highlight {
|
||||
font-family: monospace;
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body onload="initMap()">
|
||||
<div id="map"></div>
|
||||
<!--<div id="livecode" class="highlight">-->
|
||||
</div>
|
||||
<textarea id="code">
|
||||
#forma_zoom_polys{
|
||||
line-color:#FFFFFF;
|
||||
line-width:0;
|
||||
line-opacity:1;
|
||||
line-width:0.1;
|
||||
polygon-opacity:0.9;
|
||||
polygon-fill:#B10026
|
||||
[alerts<=5000] {
|
||||
polygon-fill:#E31A1C
|
||||
}
|
||||
[alerts<=500] {
|
||||
polygon-fill:#FC4E2A
|
||||
}
|
||||
[alerts<=50] {
|
||||
polygon-fill:#FD8D3C
|
||||
}
|
||||
[alerts<=5] {
|
||||
polygon-fill:#FEB24C
|
||||
}
|
||||
[alerts<=2] {
|
||||
polygon-fill:#FED976
|
||||
}
|
||||
[alerts<=1] {
|
||||
polygon-fill:#FFFFB2
|
||||
}
|
||||
}
|
||||
</textarea>
|
||||
</body>
|
||||
</html>
|
132
styler/src/carto.js
Normal file
132
styler/src/carto.js
Normal file
@ -0,0 +1,132 @@
|
||||
//========================================
|
||||
// Carto stylesheets support
|
||||
//
|
||||
// this is basically a hack on top of branch browser of carto
|
||||
// repository: Compiles carto to javascript shader
|
||||
//========================================
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
// monkey patch less classes
|
||||
tree.Value.prototype.toJS = function() {
|
||||
var v = this.value[0].value[0];
|
||||
val = v.toString();
|
||||
if(v.is === "color") {
|
||||
val = "'" + val + "'";
|
||||
}
|
||||
return "_value = " + val + ";"
|
||||
}
|
||||
|
||||
tree.Selector.prototype.toJS = function() {
|
||||
var self = this;
|
||||
var opMap = {
|
||||
'=': '==='
|
||||
};
|
||||
var zoom = "(" + self.zoom + " & (1 << ctx.zoom))";
|
||||
return [zoom].concat(
|
||||
_.map(this.filters, function(filter) {
|
||||
var op = filter.op;
|
||||
if(op in opMap) {
|
||||
op = opMap[op];
|
||||
}
|
||||
var val = filter.val;
|
||||
if(filter._val !== undefined) {
|
||||
val = filter._val.toString(true);
|
||||
}
|
||||
|
||||
var attrs = "data";
|
||||
return attrs + "." + filter.key + " " + op + " " + val;
|
||||
})
|
||||
).join(" && ");
|
||||
}
|
||||
|
||||
tree.Ruleset.prototype.toJS = function() {
|
||||
var shaderAttrs = {};
|
||||
var _if = this.selectors[0].toJS();
|
||||
_.each(this.rules, function(rule) {
|
||||
if(rule instanceof tree.Rule) {
|
||||
shaderAttrs[rule.name] = shaderAttrs[rule.name] || [];
|
||||
if (_if) {
|
||||
shaderAttrs[rule.name].push(
|
||||
"if(" + _if + "){" + rule.value.toJS() + "}"
|
||||
);
|
||||
} else {
|
||||
shaderAttrs[rule.name].push(rule.value.toJS());
|
||||
}
|
||||
} else {
|
||||
if (rule instanceof tree.Ruleset) {
|
||||
var sh = rule.toJS();
|
||||
for(var v in sh) {
|
||||
shaderAttrs[v] = shaderAttrs[v] || [];
|
||||
for(var attr in sh[v]) {
|
||||
shaderAttrs[v].push(sh[v][attr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return shaderAttrs;
|
||||
}
|
||||
|
||||
function createFn(ops) {
|
||||
var body = ops.join('\n');
|
||||
return Function("data","ctx", "var _value = null; " + body + "; return _value; ");
|
||||
}
|
||||
|
||||
function toCartoShader(ruleset) {
|
||||
var shaderAttrs = {};
|
||||
shaderAttrs = ruleset.rules[0].toJS();
|
||||
try {
|
||||
for(var attr in shaderAttrs) {
|
||||
shaderAttrs[attr] = createFn(shaderAttrs[attr]);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
console.log("error creating shader");
|
||||
console.log(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return shaderAttrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* compile from Carto style to javascript shader
|
||||
*/
|
||||
var compile = function(style, callback) {
|
||||
|
||||
var parse_env = {
|
||||
error: function(obj) {
|
||||
console.log("ERROR");
|
||||
}
|
||||
};
|
||||
|
||||
var parser = new carto.Parser(parse_env);
|
||||
|
||||
parser.parse(style, function(err, ruleset) {
|
||||
if(!err) {
|
||||
var shader = toCartoShader(ruleset);
|
||||
callback(shader);
|
||||
} else {
|
||||
callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var init = function(callback) {
|
||||
carto_initialize(carto, './reference.json', function(carto) {
|
||||
VECNIK.Carto._carto = carto;
|
||||
if(callback) callback(carto);
|
||||
});
|
||||
}
|
||||
|
||||
VECNIK.Carto = {
|
||||
init: init,
|
||||
compile: compile
|
||||
};
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
}
|
49
styler/src/cartodb.provider.js
Normal file
49
styler/src/cartodb.provider.js
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
//========================================
|
||||
// CartoDB data provider
|
||||
//========================================
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
function CartoDBSQLAPI(opts) {
|
||||
this.projection = new VECNIK.MercatorProjection();
|
||||
this.opts = opts;
|
||||
this.base_url = 'http://' + opts.user + ".cartodb.com/api/v2/sql";
|
||||
|
||||
//set defaults
|
||||
this.opts.ENABLE_SIMPLIFY = VECNIK.settings.get('ENABLE_SIMPLIFY');
|
||||
this.opts.ENABLE_SNAPPING = VECNIK.settings.get('ENABLE_SNAPPING');
|
||||
this.opts.ENABLE_CLIPPING = VECNIK.settings.get('ENABLE_CLIPPING');
|
||||
this.opts.ENABLE_FIXING = VECNIK.settings.get('ENABLE_FIXING');
|
||||
}
|
||||
|
||||
CartoDBSQLAPI.prototype.debug = function(w) {
|
||||
if(this.opts.debug) {
|
||||
//console.log(w);
|
||||
}
|
||||
}
|
||||
|
||||
CartoDBSQLAPI.prototype._sql_url = function(sql) {
|
||||
var self = this;
|
||||
this.debug(sql);
|
||||
return this.base_url + "?q=" + encodeURIComponent(sql) + "&format=geojson&dp=6";
|
||||
}
|
||||
|
||||
CartoDBSQLAPI.prototype.get_tile_data_sql = function(projection, table, x, y, zoom) {
|
||||
return VECNIK.CartoDB.SQL(projection, table, x, y, zoom, this.opts);
|
||||
};
|
||||
|
||||
CartoDBSQLAPI.prototype.url = function(coordinates) {
|
||||
var projection = this.projection;
|
||||
var opts = this.opts;
|
||||
var table = opts.table;
|
||||
var prj = this.projection;
|
||||
var sql = this.get_tile_data_sql(prj, table, coordinates.column, coordinates.row, coordinates.zoom);
|
||||
var sql_url = this._sql_url(sql);
|
||||
return sql_url;
|
||||
}
|
||||
|
||||
VECNIK.CartoDB = VECNIK.CartoDB || {};
|
||||
VECNIK.CartoDB.API = CartoDBSQLAPI;
|
||||
|
||||
})(VECNIK);
|
135
styler/src/cartodb.sql.js
Normal file
135
styler/src/cartodb.sql.js
Normal file
@ -0,0 +1,135 @@
|
||||
//========================================
|
||||
// sql generator for cartodb
|
||||
//========================================
|
||||
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
var sql = function(projection, table, x, y, zoom, opts) {
|
||||
|
||||
opts = opts || {
|
||||
ENABLE_CLIPPING: false,
|
||||
ENABLE_SIMPLIFY: false,
|
||||
ENABLE_FIXING: false,
|
||||
ENABLE_SNAPPING: false
|
||||
};
|
||||
var bbox = projection.tileBBox(x, y, zoom);
|
||||
var geom_column = '"the_geom"';
|
||||
var geom_column_orig = '"the_geom"';
|
||||
var id_column = 'cartodb_id';
|
||||
var TILE_SIZE = 256;
|
||||
var tile_pixel_width = TILE_SIZE;
|
||||
var tile_pixel_height = TILE_SIZE;
|
||||
|
||||
//console.log('-- ZOOM: ' + zoom);
|
||||
|
||||
var tile_geo_width = bbox[1].lng() - bbox[0].lng();
|
||||
var tile_geo_height = bbox[1].lat() - bbox[0].lat();
|
||||
|
||||
var pixel_geo_width = tile_geo_width / tile_pixel_width;
|
||||
var pixel_geo_height = tile_geo_height / tile_pixel_height;
|
||||
|
||||
//console.log('-- PIXEL_GEO_SIZE: '
|
||||
// + pixel_geo_width + ' x ' + pixel_geo_height);
|
||||
|
||||
var pixel_geo_maxsize = Math.max(pixel_geo_width, pixel_geo_height);
|
||||
//console.log('-- MAX_SIZE: ' + pixel_geo_maxsize);
|
||||
|
||||
var tolerance = pixel_geo_maxsize / 2;
|
||||
//console.log('-- TOLERANCE: ' + tolerance);
|
||||
|
||||
// simplify
|
||||
var ENABLE_SIMPLIFY = opts.ENABLE_SIMPLIFY;
|
||||
if ( ENABLE_SIMPLIFY ) {
|
||||
geom_column = 'ST_Simplify(' + geom_column + ', ' + tolerance + ')';
|
||||
// may change type
|
||||
geom_column = 'ST_CollectionExtract(' + geom_column + ', ST_Dimension( '
|
||||
+ geom_column_orig + ') + 1 )';
|
||||
}
|
||||
|
||||
// snap to a pixel grid
|
||||
var ENABLE_SNAPPING = opts.ENABLE_SNAPPING;
|
||||
if ( ENABLE_SNAPPING ) {
|
||||
geom_column = 'ST_SnapToGrid(' + geom_column + ', '
|
||||
+ pixel_geo_maxsize + ')';
|
||||
// may change type
|
||||
geom_column = 'ST_CollectionExtract(' + geom_column + ', ST_Dimension( '
|
||||
+ geom_column_orig + ') + 1 )';
|
||||
}
|
||||
|
||||
// This is the query bounding box
|
||||
var sql_env = "ST_MakeEnvelope("
|
||||
+ bbox[0].lng() + "," + bbox[0].lat() + ","
|
||||
+ bbox[1].lng() + "," + bbox[1].lat() + ", 4326)";
|
||||
|
||||
// clip
|
||||
var ENABLE_CLIPPING = opts.ENABLE_CLIPPING;
|
||||
if ( ENABLE_CLIPPING ) {
|
||||
|
||||
// This is a slightly enlarged version of the query bounding box
|
||||
var sql_env_exp = 'ST_Expand(' + sql_env + ', '
|
||||
+ ( pixel_geo_maxsize * 2 ) + ')';
|
||||
// Also must be snapped to the grid ...
|
||||
sql_env_exp = 'ST_SnapToGrid(' + sql_env_exp + ','
|
||||
+ pixel_geo_maxsize + ')';
|
||||
|
||||
// snap to box
|
||||
geom_column = 'ST_Snap(' + geom_column + ', ' + sql_env_exp
|
||||
+ ', ' + pixel_geo_maxsize + ')';
|
||||
|
||||
// Make valid (both ST_Snap and ST_SnapToGrid and ST_Expand
|
||||
var ENABLE_FIXING = opts.ENABLE_FIXING;
|
||||
if ( ENABLE_FIXING ) {
|
||||
// NOTE: up to PostGIS-2.0.0 beta5 ST_MakeValid did not accept
|
||||
// points nor GeometryCollection objects
|
||||
geom_column = 'CASE WHEN ST_Dimension('
|
||||
+ geom_column + ') = 0 OR GeometryType('
|
||||
+ geom_column + ") = 'GEOMETRYCOLLECTION' THEN "
|
||||
+ geom_column + ' ELSE ST_CollectionExtract(ST_MakeValid('
|
||||
+ geom_column + '), ST_Dimension(' + geom_column_orig
|
||||
+ ') + 1 ) END';
|
||||
}
|
||||
|
||||
// clip by box
|
||||
geom_column = 'ST_Intersection(' + geom_column
|
||||
+ ', ' + sql_env_exp + ')';
|
||||
}
|
||||
|
||||
var columns = id_column + ',' + geom_column + ' as the_geom';
|
||||
if(opts.columns) {
|
||||
columns += ',';
|
||||
columns += opts.columns.join(',')
|
||||
columns += ' ';
|
||||
}
|
||||
|
||||
// profiling only
|
||||
var COUNT_ONLY = opts.COUNT_ONLY || false;
|
||||
if ( COUNT_ONLY ) {
|
||||
columns = x + ' as x, ' + y + ' as y, sum(st_npoints('
|
||||
+ geom_column + ')) as the_geom';
|
||||
}
|
||||
|
||||
var sql = "select " + columns +" from " + table;
|
||||
sql += " WHERE the_geom && " + sql_env;
|
||||
if (parseInt(zoom) < 11){
|
||||
sql += " AND z = " + zoom + "+6 "
|
||||
} else {
|
||||
sql += " AND z = 16 "
|
||||
}
|
||||
//sql += " LIMIT 100";
|
||||
|
||||
//console.log('-- SQL: ' + sql);
|
||||
|
||||
return sql;
|
||||
};
|
||||
|
||||
VECNIK.CartoDB = VECNIK.CartoDB || {};
|
||||
VECNIK.CartoDB.SQL = sql;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.CartoDBSQL = VECNIK.CartoDB.SQL;
|
||||
}
|
||||
|
110
styler/src/core.js
Normal file
110
styler/src/core.js
Normal file
@ -0,0 +1,110 @@
|
||||
//========================================
|
||||
// Core
|
||||
//
|
||||
// base classes
|
||||
//========================================
|
||||
|
||||
// create root scope if not exists
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
//========================================
|
||||
// Events
|
||||
//
|
||||
// event management
|
||||
//========================================
|
||||
|
||||
function Event() {}
|
||||
Event.prototype.on = function(evt, callback) {
|
||||
var cb = this.callbacks = this.callbacks || {};
|
||||
var l = cb[evt] || (cb[evt] = []);
|
||||
l.push(callback);
|
||||
};
|
||||
|
||||
Event.prototype.emit = function(evt) {
|
||||
var c = this.callbacks && this.callbacks[evt];
|
||||
for(var i = 0; c && i < c.length; ++i) {
|
||||
c[i].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// http get
|
||||
// should be improved
|
||||
function get(url, callback) {
|
||||
var mygetrequest= new XMLHttpRequest();
|
||||
mygetrequest.onreadystatechange=function() {
|
||||
if (mygetrequest.readyState == 4){
|
||||
if (mygetrequest.status == 200){
|
||||
callback(JSON.parse(mygetrequest.responseText));
|
||||
}
|
||||
else {
|
||||
//error
|
||||
}
|
||||
}
|
||||
};
|
||||
mygetrequest.open("GET", url, true)
|
||||
mygetrequest.send(null)
|
||||
}
|
||||
|
||||
//========================================
|
||||
// model
|
||||
//
|
||||
// pretty basic model funcionallity
|
||||
//========================================
|
||||
|
||||
function Model() {
|
||||
//this.data = {}; // serializable data
|
||||
}
|
||||
|
||||
Model.prototype = new Event();
|
||||
|
||||
Model.prototype.set = function(data, silent) {
|
||||
this.data = this.data || {};
|
||||
for(var v in data) {
|
||||
if(data.hasOwnProperty(v)) {
|
||||
this.data[v] = data[v];
|
||||
}
|
||||
}
|
||||
if(!silent) {
|
||||
this.emit('change', this.data);
|
||||
}
|
||||
};
|
||||
|
||||
Model.prototype.get = function(attr, def) {
|
||||
if(this.data) {
|
||||
if(attr in this.data) {
|
||||
return this.data[attr];
|
||||
}
|
||||
return def;
|
||||
}
|
||||
return def;
|
||||
};
|
||||
|
||||
/**
|
||||
* delete the attribute
|
||||
*/
|
||||
Model.prototype.unset = function(attr, silent) {
|
||||
delete this.data[attr];
|
||||
if(!silent) {
|
||||
this.emit('change', this.data);
|
||||
}
|
||||
};
|
||||
|
||||
Model.prototype.destroy = function() {
|
||||
this.emit('destroy');
|
||||
delete this.data;
|
||||
};
|
||||
|
||||
|
||||
VECNIK.Event = Event;
|
||||
VECNIK.Model = Model;
|
||||
VECNIK.get = get;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.Event = VECNIK.Event;
|
||||
module.exports.Model = VECNIK.Model;
|
||||
}
|
95
styler/src/geometry.js
Normal file
95
styler/src/geometry.js
Normal file
@ -0,0 +1,95 @@
|
||||
|
||||
//========================================
|
||||
// geometry conversion
|
||||
//========================================
|
||||
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
var LatLng = VECNIK.LatLng;
|
||||
var Point = VECNIK.Point;
|
||||
|
||||
//stats
|
||||
var stats = {
|
||||
vertices: 0
|
||||
};
|
||||
|
||||
var latlng = new LatLng(0, 0);
|
||||
var prj = new VECNIK.MercatorProjection();
|
||||
|
||||
function map_latlon(ll, x, y, zoom) {
|
||||
latlng.latitude = ll[1];
|
||||
latlng.longitude = ll[0];
|
||||
stats.vertices++;
|
||||
var point = prj.latLngToTilePoint(latlng, x, y, zoom);
|
||||
//point.x = point.x >> 0;
|
||||
//point.y = point.y >> 0;
|
||||
return point;
|
||||
}
|
||||
|
||||
var primitive_conversion = {
|
||||
'LineString': function(x, y, zoom, coordinates) {
|
||||
var converted = [];
|
||||
var pc = primitive_conversion['Point'];
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
converted.push(pc(x, y, zoom, coordinates[i]));
|
||||
}
|
||||
return converted;
|
||||
},
|
||||
|
||||
'Point': function(x, y, zoom, coordinates) {
|
||||
return map_latlon(coordinates, x, y, zoom);
|
||||
},
|
||||
|
||||
'MultiPoint': function(x, y, zoom, coordinates) {
|
||||
var converted = [];
|
||||
var pc = primitive_conversion['Point'];
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
converted.push(pc(x, y, zoom, coordinates[i]));
|
||||
}
|
||||
return converted;
|
||||
},
|
||||
//do not manage inner polygons!
|
||||
'Polygon': function(x, y, zoom, coordinates) {
|
||||
if(coordinates[0]) {
|
||||
var coords = [];
|
||||
for(var i=0; i < coordinates[0].length; ++i) {
|
||||
coords.push(map_latlon(coordinates[0][i], x, y, zoom));
|
||||
}
|
||||
return [coords];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
'MultiPolygon': function(x, y, zoom, coordinates) {
|
||||
var polys = [];
|
||||
var poly;
|
||||
var pc = primitive_conversion['Polygon'];
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
poly = pc(x, y, zoom, coordinates[i]);
|
||||
if(poly)
|
||||
polys.push(poly);
|
||||
}
|
||||
return polys;
|
||||
}
|
||||
};
|
||||
|
||||
var project_geometry = function(geometry, zoom, x, y) {
|
||||
var conversor = primitive_conversion[geometry.type];
|
||||
if(conversor) {
|
||||
return conversor(x, y , zoom, geometry.coordinates);
|
||||
}
|
||||
};
|
||||
|
||||
VECNIK.project_geometry = project_geometry;
|
||||
VECNIK.geometry_stats = stats;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.project_geometry = VECNIK.project_geometry;
|
||||
}
|
||||
if (typeof self !== 'undefined') {
|
||||
self.VECNIK = VECNIK;
|
||||
}
|
||||
|
135
styler/src/mercator.js
Normal file
135
styler/src/mercator.js
Normal file
@ -0,0 +1,135 @@
|
||||
|
||||
//========================================
|
||||
// Mercator projection
|
||||
//========================================
|
||||
//
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
var TILE_SIZE = 256;
|
||||
|
||||
// todo: move outside
|
||||
function Point(x, y) {
|
||||
this.x = x || 0;
|
||||
this.y = y || 0;
|
||||
}
|
||||
|
||||
function LatLng(lat, lon) {
|
||||
this.latitude = lat || 0;
|
||||
this.longitude = lon || 0;
|
||||
}
|
||||
|
||||
LatLng.prototype.lat = function() {
|
||||
return this.latitude;
|
||||
}
|
||||
|
||||
LatLng.prototype.lng = function() {
|
||||
return this.longitude;
|
||||
}
|
||||
|
||||
function bound(value, opt_min, opt_max) {
|
||||
if (opt_min != null) value = Math.max(value, opt_min);
|
||||
if (opt_max != null) value = Math.min(value, opt_max);
|
||||
return value;
|
||||
}
|
||||
|
||||
function degreesToRadians(deg) {
|
||||
return deg * (Math.PI / 180);
|
||||
}
|
||||
|
||||
function radiansToDegrees(rad) {
|
||||
return rad / (Math.PI / 180);
|
||||
}
|
||||
|
||||
function MercatorProjection() {
|
||||
this.pixelOrigin_ = new Point(TILE_SIZE / 2, TILE_SIZE / 2);
|
||||
this.pixelsPerLonDegree_ = TILE_SIZE / 360;
|
||||
this.pixelsPerLonRadian_ = TILE_SIZE / (2 * Math.PI);
|
||||
}
|
||||
|
||||
MercatorProjection.prototype.fromLatLngToPoint = function (latLng, opt_point) {
|
||||
var me = this;
|
||||
var point = opt_point || new Point(0, 0);
|
||||
var origin = me.pixelOrigin_;
|
||||
|
||||
point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
|
||||
|
||||
// NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
|
||||
// 89.189. This is about a third of a tile past the edge of the world
|
||||
// tile.
|
||||
var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999,
|
||||
0.9999);
|
||||
point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) *
|
||||
-me.pixelsPerLonRadian_;
|
||||
return point;
|
||||
};
|
||||
|
||||
MercatorProjection.prototype.fromPointToLatLng = function (point) {
|
||||
var me = this;
|
||||
var origin = me.pixelOrigin_;
|
||||
var lng = (point.x - origin.x) / me.pixelsPerLonDegree_;
|
||||
var latRadians = (point.y - origin.y) / -me.pixelsPerLonRadian_;
|
||||
var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) -
|
||||
Math.PI / 2);
|
||||
return new LatLng(lat, lng);
|
||||
};
|
||||
|
||||
MercatorProjection.prototype.tileBBox = function(x, y, zoom) {
|
||||
var numTiles = 1 << zoom;
|
||||
var inc = TILE_SIZE/numTiles;
|
||||
var px = x*TILE_SIZE/numTiles;
|
||||
var py = y*TILE_SIZE/numTiles;
|
||||
return [
|
||||
this.fromPointToLatLng(new Point(px, py + inc)),
|
||||
this.fromPointToLatLng(new Point(px + inc, py))
|
||||
];
|
||||
};
|
||||
|
||||
MercatorProjection.prototype.tilePoint = function(x, y, zoom) {
|
||||
var numTiles = 1 << zoom;
|
||||
var px = x*TILE_SIZE;
|
||||
var py = y*TILE_SIZE;
|
||||
return [px, py];
|
||||
};
|
||||
|
||||
MercatorProjection.prototype.latLngToTilePoint = function(latLng, x, y, zoom) {
|
||||
var numTiles = 1 << zoom;
|
||||
var projection = this;
|
||||
var worldCoordinate = projection.fromLatLngToPoint(latLng);
|
||||
var pixelCoordinate = new Point(
|
||||
worldCoordinate.x * numTiles,
|
||||
worldCoordinate.y * numTiles);
|
||||
var tp = this.tilePoint(x, y, zoom);
|
||||
return new Point(
|
||||
Math.floor(pixelCoordinate.x - tp[0]),
|
||||
Math.floor(pixelCoordinate.y - tp[1]));
|
||||
};
|
||||
|
||||
MercatorProjection.prototype.latLngToTile = function(latLng, zoom) {
|
||||
var numTiles = 1 << zoom;
|
||||
var projection = this;
|
||||
var worldCoordinate = projection.fromLatLngToPoint(latLng);
|
||||
var pixelCoordinate = new Point(
|
||||
worldCoordinate.x * numTiles,
|
||||
worldCoordinate.y * numTiles);
|
||||
return new Point(
|
||||
Math.floor(pixelCoordinate.x / TILE_SIZE),
|
||||
Math.floor(pixelCoordinate.y / TILE_SIZE));
|
||||
};
|
||||
|
||||
VECNIK.LatLng = LatLng;
|
||||
VECNIK.Point = Point;
|
||||
VECNIK.MercatorProjection = MercatorProjection;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.MercatorProjection = VECNIK.MercatorProjection;
|
||||
module.exports.LatLng = VECNIK.LatLng;
|
||||
module.exports.Point = VECNIK.Point;
|
||||
}
|
||||
|
||||
if (typeof self !== 'undefined') {
|
||||
self.VECNIK = VECNIK;
|
||||
}
|
145
styler/src/model.js
Normal file
145
styler/src/model.js
Normal file
@ -0,0 +1,145 @@
|
||||
//========================================
|
||||
// vecnik models
|
||||
//========================================
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
// utility
|
||||
function Profiler(name){
|
||||
this.t0 = 0;
|
||||
this.unit = '';
|
||||
}
|
||||
Profiler.prototype.start = function(unit) {
|
||||
this.t0 = new Date().getTime();
|
||||
this.unit = unit || '';
|
||||
}
|
||||
Profiler.prototype.end= function() {
|
||||
var t = new Date().getTime() - this.t0;
|
||||
//console.log("PROFILE - " + this.unit + ":" + t);
|
||||
return t;
|
||||
}
|
||||
|
||||
//========================================
|
||||
// tile model
|
||||
//========================================
|
||||
function Tile(x, y, zoom) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.zoom = zoom;
|
||||
this.on('change', this.precache.bind(this))
|
||||
this.stats = {
|
||||
conversion_time: 0,
|
||||
vertices: 0,
|
||||
primitive_count: 0
|
||||
};
|
||||
this.profiler = new Profiler('tile');
|
||||
}
|
||||
|
||||
Tile.prototype = new VECNIK.Model();
|
||||
|
||||
Tile.prototype.key = function() {
|
||||
return [this.x, this.y, this.zoom].join('-');
|
||||
}
|
||||
|
||||
Tile.prototype.geometry = function() {
|
||||
return this.get('geometry');
|
||||
}
|
||||
|
||||
Tile.prototype.precache = function() {
|
||||
var self = this;
|
||||
var geometry = [];
|
||||
this.profiler.start('conversion_time');
|
||||
var primitives = this.data.features;
|
||||
var vertex_count = VECNIK.geometry_stats.vertices;
|
||||
if(VECNIK.settings.get('WEBWORKERS') && typeof Worker !== undefined) {
|
||||
var worker = new Worker('../js/projector.worker.js');
|
||||
worker.onmessage = function(ev) {
|
||||
self.set({geometry: ev.data.geometry}, true);
|
||||
self.unset('features', true);
|
||||
self.emit('geometry_ready');
|
||||
};
|
||||
worker.postMessage({
|
||||
primitives: primitives,
|
||||
zoom: this.zoom,
|
||||
x: this.x,
|
||||
y: this.y
|
||||
});
|
||||
|
||||
} else {
|
||||
for(var i = 0; i < primitives.length; ++i) {
|
||||
var p = primitives[i];
|
||||
if(p.geometry) {
|
||||
var converted = VECNIK.project_geometry(p.geometry, this.zoom, this.x, this.y);
|
||||
if(converted && converted.length !== 0) {
|
||||
geometry.push({
|
||||
vertexBuffer: converted,
|
||||
type: p.geometry.type,
|
||||
metadata: p.properties
|
||||
});
|
||||
} else {
|
||||
delete p.geometry.coordinates;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.set({geometry: geometry}, true);
|
||||
this.unset('features', true);
|
||||
this.emit('geometry_ready');
|
||||
}
|
||||
this.stats.vertices = VECNIK.geometry_stats.vertices - vertex_count;
|
||||
this.stats.primitive_count = primitives.length;
|
||||
this.stats.conversion_time = this.profiler.end();
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// tile manager
|
||||
//========================================
|
||||
|
||||
function TileManager(dataProvider) {
|
||||
this.tiles = {};
|
||||
this.dataProvider = dataProvider;
|
||||
}
|
||||
|
||||
TileManager.prototype.tileIndex= function(coordinates) {
|
||||
return coordinates.toKey();
|
||||
}
|
||||
|
||||
TileManager.prototype.get = function(coordinates) {
|
||||
return this.tiles[this.tileIndex(coordinates)];
|
||||
}
|
||||
|
||||
TileManager.prototype.destroy= function(coordinates) {
|
||||
var tile = this.tiles[this.tileIndex(coordinates)];
|
||||
if(tile) {
|
||||
tile.destroy();
|
||||
//console.log("removing " + this.tileIndex(coordinates));
|
||||
delete this.tiles[this.tileIndex(coordinates)];
|
||||
}
|
||||
}
|
||||
|
||||
TileManager.prototype.add = function(coordinates) {
|
||||
//console.log("adding" + this.tileIndex(coordinates));
|
||||
var tile = this.tiles[this.tileIndex(coordinates)] = new Tile(
|
||||
coordinates.column,
|
||||
coordinates.row,
|
||||
coordinates.zoom
|
||||
);
|
||||
|
||||
VECNIK.get(this.dataProvider.url(coordinates), function(data) {
|
||||
tile.set(data);
|
||||
});
|
||||
return tile;
|
||||
}
|
||||
|
||||
VECNIK.Tile = Tile;
|
||||
VECNIK.TileManager = TileManager;
|
||||
VECNIK.Profiler = Profiler;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.Tile = VECNIK.Tile;
|
||||
module.exports.TileManager = VECNIK.TileManager;
|
||||
}
|
||||
|
||||
|
23
styler/src/projector.worker.js
Normal file
23
styler/src/projector.worker.js
Normal file
@ -0,0 +1,23 @@
|
||||
importScripts('../js/mercator.js');
|
||||
importScripts('../js/geometry.js');
|
||||
|
||||
self.onmessage = function(event) {
|
||||
var data = event.data;
|
||||
var primitives = data.primitives;
|
||||
var geometry = [];
|
||||
for(var i = 0; i < primitives.length; ++i) {
|
||||
var p = primitives[i];
|
||||
if(p.geometry) {
|
||||
var converted = VECNIK.project_geometry(p.geometry,
|
||||
data.zoom, data.x, data.y);
|
||||
if(converted && converted.length !== 0) {
|
||||
geometry.push({
|
||||
vertexBuffer: converted,
|
||||
type: p.geometry.type,
|
||||
metadata: p.properties
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
self.postMessage({geometry: geometry});
|
||||
};
|
175
styler/src/renderer.js
Normal file
175
styler/src/renderer.js
Normal file
@ -0,0 +1,175 @@
|
||||
//========================================
|
||||
// vecnik views
|
||||
//========================================
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
function Renderer() {
|
||||
var self = this;
|
||||
var primitive_render = this.primitive_render = {
|
||||
'Point': function(ctx, coordinates) {
|
||||
ctx.save();
|
||||
var radius = 2;
|
||||
var p = coordinates;
|
||||
ctx.translate(p.x, p.y);
|
||||
ctx.beginPath();
|
||||
ctx.arc(radius, radius, radius, 0, Math.PI * 2, true);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
},
|
||||
'MultiPoint': function(ctx, coordinates) {
|
||||
var prender = primitive_render['Point'];
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
prender(ctx, coordinates[i]);
|
||||
}
|
||||
},
|
||||
'Polygon': function(ctx, coordinates) {
|
||||
ctx.beginPath();
|
||||
var p = coordinates[0][0];
|
||||
ctx.moveTo(p.x, p.y);
|
||||
for(var i=0; i < coordinates[0].length; ++i) {
|
||||
p = coordinates[0][i];
|
||||
ctx.lineTo(p.x, p.y);
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
//ctx.stroke();
|
||||
},
|
||||
'MultiPolygon': function(ctx, coordinates) {
|
||||
var prender = primitive_render['Polygon'];
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
prender(ctx, coordinates[i]);
|
||||
}
|
||||
},
|
||||
'LineString': function(ctx, coordinates) {
|
||||
ctx.beginPath();
|
||||
var p = coordinates[0];
|
||||
ctx.moveTo(p.x, p.y);
|
||||
for(var i=0; i < coordinates.length; ++i) {
|
||||
p = coordinates[i];
|
||||
ctx.lineTo(p.x, p.y);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Renderer.prototype.render = function(ctx, geometry, zoom, shader) {
|
||||
var primitive_render = this.primitive_render;
|
||||
ctx.canvas.width = ctx.canvas.width;
|
||||
var primitive_type;
|
||||
if(geometry && geometry.length) {
|
||||
for(var i = 0; i < geometry.length; ++i) {
|
||||
var geo = geometry[i];
|
||||
var primitive_type = geo.type;
|
||||
var renderer = primitive_render[primitive_type];
|
||||
if(renderer) {
|
||||
// render visible tile
|
||||
var render_context = {
|
||||
zoom: zoom,
|
||||
id: i
|
||||
};
|
||||
var is_active = true;
|
||||
if(shader) {
|
||||
is_active = shader.needs_render(geo.metadata, render_context, primitive_type);
|
||||
if(is_active) {
|
||||
shader.reset(ctx, primitive_type);
|
||||
shader.apply(ctx, geo.metadata, render_context);
|
||||
}
|
||||
}
|
||||
if (is_active) {
|
||||
renderer(ctx, geo.vertexBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//========================================
|
||||
// Canvas tile view
|
||||
//========================================
|
||||
function CanvasTileView(tile, shader, renderer) {
|
||||
this.tileSize = new VECNIK.Point(256, 256);
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = this.tileSize.x;
|
||||
canvas.height = this.tileSize.y;
|
||||
this.ctx = canvas.getContext('2d');
|
||||
this.canvas = canvas;
|
||||
|
||||
var backCanvas = document.createElement('canvas');
|
||||
backCanvas.width = this.tileSize.x;
|
||||
backCanvas.height = this.tileSize.y;
|
||||
this.backCtx = backCanvas.getContext('2d');
|
||||
this.backCanvas = backCanvas;
|
||||
|
||||
this.el = canvas;
|
||||
this.id = tile.key();
|
||||
this.el.setAttribute('id', tile.key());
|
||||
var self = this;
|
||||
this.tile = tile;
|
||||
var render = function(){self.render();};
|
||||
tile.on('geometry_ready', render);
|
||||
|
||||
// shader
|
||||
this.shader = shader;
|
||||
if(shader) {
|
||||
shader.on('change', render);
|
||||
}
|
||||
this.renderer = renderer || new Renderer();
|
||||
|
||||
this.profiler = new VECNIK.Profiler('tile_render');
|
||||
this.stats = {
|
||||
rendering_time: 0
|
||||
}
|
||||
}
|
||||
|
||||
CanvasTileView.prototype.remove = function() {
|
||||
}
|
||||
|
||||
CanvasTileView.prototype.render = function() {
|
||||
var ctx = this.ctx;
|
||||
|
||||
this.profiler.start('render');
|
||||
var BACKBUFFER = true;
|
||||
if(BACKBUFFER) {
|
||||
this.backCanvas.width = this.backCanvas.width;
|
||||
this.renderer.render(this.backCtx, this.tile.geometry(), this.tile.zoom, this.shader);
|
||||
this.canvas.width = this.canvas.width;
|
||||
this.ctx.drawImage(this.backCanvas, 0, 0);
|
||||
} else {
|
||||
this.renderer.render(ctx, this.tile.geometry(), this.tile.zoom, this.shader);
|
||||
}
|
||||
|
||||
this.stats.rendering_time = this.profiler.end();
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Map view
|
||||
// manages the list of tiles
|
||||
//========================================
|
||||
function CanvasMapView() {
|
||||
this.tile_views = {};
|
||||
}
|
||||
|
||||
CanvasMapView.prototype.add = function(canvasview) {
|
||||
this.tile_views[canvasview.id] = canvasview;
|
||||
}
|
||||
|
||||
CanvasMapView.prototype.getByElement = function(el) {
|
||||
return this.tile_views[el.getAttribute('id')];
|
||||
}
|
||||
|
||||
|
||||
VECNIK.Renderer = Renderer;
|
||||
VECNIK.CanvasTileView = CanvasTileView;
|
||||
VECNIK.CanvasMapView = CanvasMapView;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
}
|
||||
|
||||
|
33
styler/src/settings.js
Normal file
33
styler/src/settings.js
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
//========================================
|
||||
// Global settings
|
||||
//========================================
|
||||
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
function Settings(defaults) {
|
||||
this.set(defaults);
|
||||
}
|
||||
|
||||
Settings.prototype = new VECNIK.Model();
|
||||
|
||||
// default settings
|
||||
VECNIK.settings = new Settings({
|
||||
WEBWORKERS: false,
|
||||
BACKBUFFER: true,
|
||||
ENABLE_SIMPLIFY: true,
|
||||
ENABLE_SNAPPING: true,
|
||||
ENABLE_CLIPPING: true,
|
||||
ENABLE_FIXING: true
|
||||
});
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.settings = VECNIK.settings;
|
||||
}
|
||||
if (typeof self !== 'undefined') {
|
||||
self.VECNIK = VECNIK;
|
||||
}
|
120
styler/src/shader.js
Normal file
120
styler/src/shader.js
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
//========================================
|
||||
// shader
|
||||
//========================================
|
||||
|
||||
(function(VECNIK) {
|
||||
|
||||
var mapper = {
|
||||
'point-color': 'fillStyle',
|
||||
'line-color': 'strokeStyle',
|
||||
'line-width': 'lineWidth',
|
||||
'line-opacity': 'globalAlpha',
|
||||
'polygon-fill': 'fillStyle',
|
||||
'polygon-opacity': 'globalAlpha'
|
||||
};
|
||||
|
||||
function CartoShader(shader) {
|
||||
this.compiled = {};
|
||||
this.shader_src = null;
|
||||
this.compile(shader)
|
||||
}
|
||||
|
||||
CartoShader.prototype = new VECNIK.Event();
|
||||
|
||||
CartoShader.prototype.compile = function(shader) {
|
||||
if(typeof shader === 'string') {
|
||||
shader = eval("(function() { return " + shader +"; })()");
|
||||
}
|
||||
this.shader_src = shader;
|
||||
for(var attr in shader) {
|
||||
var c = mapper[attr];
|
||||
if(c) {
|
||||
this.compiled[c] = eval("(function() { return shader[attr]; })();");
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('change');
|
||||
};
|
||||
|
||||
var needed_settings = {
|
||||
'LineString': [
|
||||
'line-color',
|
||||
'line-width',
|
||||
'line-opacity'
|
||||
],
|
||||
'Polygon': [
|
||||
'polygon-fill'
|
||||
],
|
||||
'MultiPolygon': [
|
||||
'polygon-fill'
|
||||
]
|
||||
};
|
||||
var defaults = {
|
||||
'LineString': {
|
||||
'strokeStyle': '#000',
|
||||
'lineWidth': 1,
|
||||
'globalAlpha': 1.0,
|
||||
'lineCap': 'round'
|
||||
},
|
||||
'Polygon': {
|
||||
'strokeStyle': '#000',
|
||||
'lineWidth': 1,
|
||||
'globalAlpha': 1.0
|
||||
},
|
||||
'MultiPolygon': {
|
||||
'strokeStyle': '#000',
|
||||
'lineWidth': 1,
|
||||
'globalAlpha': 1.0
|
||||
}
|
||||
};
|
||||
|
||||
CartoShader.prototype.needs_render = function(data, render_context, primitive_type) {
|
||||
var variables = needed_settings[primitive_type];
|
||||
var shader = this.compiled;
|
||||
for(var attr in variables) {
|
||||
var style_attr = variables[attr];
|
||||
var attr_present = this.shader_src[style_attr];
|
||||
if(attr_present !== undefined) {
|
||||
var fn = shader[mapper[style_attr]];
|
||||
if(typeof fn === 'function') {
|
||||
fn = fn(data, render_context);
|
||||
}
|
||||
if(fn !== null && fn !== undefined) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
CartoShader.prototype.reset = function(ctx, primitive_type) {
|
||||
var def = defaults[primitive_type];
|
||||
for(var attr in def) {
|
||||
ctx[attr] = def[attr];
|
||||
}
|
||||
}
|
||||
|
||||
CartoShader.prototype.apply = function(canvas_ctx, data, render_context) {
|
||||
var shader = this.compiled;
|
||||
for(var attr in shader) {
|
||||
var fn = shader[attr];
|
||||
if(typeof fn === 'function') {
|
||||
fn = fn(data, render_context);
|
||||
}
|
||||
if(fn !== null && canvas_ctx[attr] != fn) {
|
||||
canvas_ctx[attr] = fn;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VECNIK.CartoShader = CartoShader;
|
||||
|
||||
})(VECNIK);
|
||||
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports.CartoShader = CartoShader;
|
||||
}
|
||||
|
||||
|
55
styler/src/vecnik.leatlet.js
Normal file
55
styler/src/vecnik.leatlet.js
Normal file
@ -0,0 +1,55 @@
|
||||
L.TileLayer.Canvas = L.TileLayer.extend({
|
||||
options: {
|
||||
async: false
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.tileSize = tileSize || new MM.Point(256, 256)
|
||||
this.tiles = new CartoDBSQLAPI({
|
||||
user: 'vizzuality',
|
||||
table: 'countries_final',
|
||||
columns: ['admin'],
|
||||
});
|
||||
this.views = new CanvasMapView();
|
||||
},
|
||||
|
||||
redraw: function () {
|
||||
},
|
||||
|
||||
|
||||
_createTileProto: function () {
|
||||
var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
|
||||
|
||||
var tileSize = this.options.tileSize;
|
||||
proto.width = tileSize;
|
||||
proto.height = tileSize;
|
||||
},
|
||||
|
||||
_createTile: function () {
|
||||
var tile = this._canvasProto.cloneNode(false);
|
||||
tile.onselectstart = tile.onmousemove = L.Util.falseFn;
|
||||
return tile;
|
||||
},
|
||||
|
||||
_loadTile: function (tile, tilePoint, zoom) {
|
||||
tile._layer = this;
|
||||
tile._tilePoint = tilePoint;
|
||||
tile._zoom = zoom;
|
||||
|
||||
this.drawTile(tile, tilePoint, zoom);
|
||||
|
||||
if (!this.options.async) {
|
||||
this.tileDrawn(tile);
|
||||
}
|
||||
},
|
||||
_resetTile: function (tile) {
|
||||
},
|
||||
|
||||
drawTile: function (tile, tilePoint, zoom) {
|
||||
// override with rendering code
|
||||
},
|
||||
|
||||
tileDrawn: function (tile) {
|
||||
this._tileOnLoad.call(tile);
|
||||
}
|
||||
});
|
55
styler/src/vecnik.modestmaps.js
Normal file
55
styler/src/vecnik.modestmaps.js
Normal file
@ -0,0 +1,55 @@
|
||||
//========================================
|
||||
// Core
|
||||
//
|
||||
// base classes
|
||||
//========================================
|
||||
|
||||
// create root scope if not exists
|
||||
var VECNIK = VECNIK || {};
|
||||
|
||||
(function(VECNIK) {
|
||||
var MM = com.modestmaps;
|
||||
|
||||
|
||||
//========================================
|
||||
// testing provider with mapbox tile layer
|
||||
//========================================
|
||||
function TileManagerMapBox() {
|
||||
}
|
||||
TileManagerMapBox.prototype = new VECNIK.TileManager();
|
||||
TileManagerMapBox.prototype.url = function(coordinates) {
|
||||
return 'http://b.tiles.mapbox.com/v3/mapbox.mapbox-streets/' + coordinates.zoom + '/' + coordinates.row + '/' + coordinates.column + ".png";
|
||||
}
|
||||
|
||||
|
||||
//========================================
|
||||
// Canvas provider
|
||||
//========================================
|
||||
function CanvasProvider(dataSource, shader, renderer, tileSize) {
|
||||
this.tileSize = tileSize || new MM.Point(256, 256)
|
||||
this.renderer = renderer;
|
||||
this.tiles = new VECNIK.TileManager(dataSource)
|
||||
this.views = new VECNIK.CanvasMapView(shader);
|
||||
this.shader = shader;
|
||||
}
|
||||
|
||||
CanvasProvider.prototype.getTile = function(coord) {
|
||||
var tile = this.tiles.add(coord);
|
||||
var canvas = new VECNIK.CanvasTileView(tile, this.shader, this.renderer);
|
||||
this.views.add(canvas);
|
||||
return canvas.el;
|
||||
}
|
||||
|
||||
CanvasProvider.prototype.releaseTile = function(coordinates) {
|
||||
this.tiles.destroy(coordinates);
|
||||
};
|
||||
|
||||
MM.extend(CanvasProvider, MM.MapProvider);
|
||||
|
||||
VECNIK.MM = {
|
||||
CanvasProvider: CanvasProvider,
|
||||
TileManagerMapBox: TileManagerMapBox
|
||||
};
|
||||
|
||||
})(VECNIK);
|
||||
|
Loading…
Reference in New Issue
Block a user