Merge branch 'master' into gh-pages

This commit is contained in:
javi 2013-09-30 17:00:46 +02:00
commit 2690dfacc7
69 changed files with 32489 additions and 12904 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
.idea/
.DS_Store
.DS_Store
*.swp
node_modules

28
Makefile Normal file
View File

@ -0,0 +1,28 @@
UGLIFYJS=./node_modules/.bin/uglifyjs
JS_CLIENT_FILES= lib/torque/*.js \
lib/torque/renderer/*.js \
lib/torque/gmaps/*.js \
lib/torque/leaflet/leaflet_tileloader_mixin.js \
lib/torque/leaflet/canvas_layer.js \
lib/torque/leaflet/torque.js
all: dist/torque.js
dist/torque.uncompressed.js: dist_folder $(JS_CLIENT_FILES)
cat $(JS_CLIENT_FILES) > dist/torque.uncompressed.js
dist/torque.js: dist_folder dist/torque.uncompressed.js
$(UGLIFYJS) dist/torque.uncompressed.js > dist/torque.js
dist_folder:
mkdir -p dist
dist: dist_folder dist/torque.js
clean:
rm -rf dist
.PHONY: clean dist_folder

View File

@ -7,6 +7,71 @@ CartoDB users can use this code right away. Specify your username/tablename and
Have fun!
* USPO creation over time: http://cartodb.github.com/torque/examples/uspo.html
* OpenStreetMap edits in Madrid over time: http://cartodb.github.com/torque/examples/osm.html
* A car in Nürburgring track: http://cartodb.github.com/torque/examples/car.html
* The Guardian's Data Blog write-up of Royal Navy ships in WWI: http://www.guardian.co.uk/news/datablog/interactive/2012/oct/01/first-world-war-royal-navy-ships-mapped
## Torque library reference
Torque lets you render big, timeseries or categorical data in the client. This is useful for many modern applications that need more than just a static map. Early versions of Torque have been used to visualize human movement, Twitter activity, biodiversity data, and many more large-scale datasets.
The library uses CartoDB to generate a [layercube]() format. For a brief introduction to the format and methods, see our [presentation slides](http://gijs.github.com/images/cartodb_datacubes.pdf). If you are not using CartoDB to host your data, you can modify the input parameters to point toward any layercube service.
### Getting started
The simplest way to use a visualization with Torque is...
<div class="margin20"></div>
<div class="code_title">Create a simple Torque visualization</div>
``` javascript
...
<body>
<div id="map"></div>
</body>
...
<script>
window.onload = function() {
// Create a Leaflet map
var map = new L.Map('map', {
zoomControl: true,
center: [40, 0],
//center: [36.60670888641815, 38.627929687],
zoom: 3
});
// Add a basemap, here we use one provided by Stamen
L.tileLayer('http://tile.stamen.com/toner/{z}/{x}/{y}.png', {
attribution: 'Stamen'
}).addTo(map);
// Add Torque visualization
// - create the torqueLayer object
// - add the torqueLayer to the map
var torqueLayer = new L.TorqueLayer({
provider: 'sql_api',
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution: 1,
is_time: true,
steps: 750,
pixel_size: 4,
blendmode : 'lighter'
});
torqueLayer.addTo(map);
var t = 0;
setInterval(function() {
torqueLayer.setKey((t++%750));
}, 100);
}
</script>
```
[Grab the complete example source code](https://github.com/CartoDB/torque/blob/master/examples/navy_leaflet.html)
<div class="margin20"></div>
### API
[see reference](https://github.com/CartoDB/torque/blob/master/doc/API.md)

2
dist/torque.js vendored Normal file

File diff suppressed because one or more lines are too long

3088
dist/torque.uncompressed.js vendored Normal file

File diff suppressed because it is too large Load Diff

193
doc/API.md Normal file
View File

@ -0,0 +1,193 @@
# Torque API
Torque provides two kinds of visualizations.
- static: provides a way to create heatmap like visualizations (note for Andrew: fon). see ``TorqueLayer``
- dynamic: animate points over a map (note for Andrew: Navy) see ``TiledTorqueLayer``
depending on the map provider you are using you need to use different layer type. Currently we provide layers for Google Maps and Leaflet.
## L.TorqueLayer(options)
One of two core classes for the Torque library - it is used to create an animated torque layer with custom settings.
### Usage example
```js
// initialize a torque layer that uses the CartoDB account details and SQL API to pull in data
var torqueLayer = new L.TorqueLayer({
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution : 1,
is_time : true,
steps : 750,
pixel_size : 3,
blendmode : 'lighter'
});
```
### Options
##### Provider options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| provider | string | ```sql_api``` | Where is the data coming from? Alternative is 'url_template'|
##### CartoDB data options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| user | string | ```null``` | CartoDB account name. Found as, accountname.cartodb.com|
| table | string | ```null``` | CartoDB table name where data is found |
| column | string | ```null``` | CartoDB table's column name where date information is found (for dynamic type torque layer only)|
| countby | string | ```null``` | The aggregation method to use for each pixel displayed where multiple data are found. Any valid PostgreSQL aggregate function |
##### Dynamic/static options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| is_time | boolean | ```true``` | Determines if the drawing is static or dynamic/animated |
##### Display options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| resolution| numeric | ```2``` | The x and y dimensions of each pixel as returned by the data|
| blendmode | boolean | ```source-over``` | The HTML5 Canvas composite operation for when multiple pixels overlap on the canvas |
##### Time options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| steps | integer | ```100``` | The number of steps to divide the data into for animated renderings |
| animationDuration | integer | ```null``` | time in seconds the animation last |
### Time methods
| Method | options | returns | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| ```setStep(step)``` | ```time numeric``` | ```this``` | sets the animation to the step indicated by ```step```, must be between 0 and ```steps```|
| ```play```| | ```this```| starts the animation
| ```stop```| | ```this```| stops the animation and set time to step 0
| ```pause```| | ```this```| stops the animation but keep the current time (play enables the animation again)
### Style methods
| Method | options | returns | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| ```setCartoCSS(cartocss)``` | ```cartocss string``` | ```this``` | style the map rendering using client-side cartocss |
The full CartoCSS spec is not supported by Torque but instead only a limited subset with some additions related to torque rendering. To see the full list of supported parameters, read the [Torque CartoCSS documentation here](CartoCSS.md). ``value`` and ``zoom`` variables can be used. ``value`` is the value of aggregation (see ``countby`` constructor option). ``zoom`` is the current zoom being rendered
TorqueLayer currently expects ```marker``` styling
##### CartoCSS Example
This should be ```string``` encoded in Javascript
```css
#layer {,
marker-fill: #662506;
marker-width: 20;
[value > 1] { marker-fill: #FEE391; }
[value > 2] { marker-fill: #FEC44F; }
[value > 3] { marker-fill: #FE9929; }
[value > 4] { marker-fill: #EC7014; }
[value > 5] { marker-fill: #CC4C02; }
[value > 6] { marker-fill: #993404; }
[value > 7] { marker-fill: #662506; }
[frame-offset = 1] { marker-width: 20; marker-fill-opacity: 0.05;}', // renders the previos frame
[frame-offset = 2] { marker-fill: red; marker-width: 30; marker-fill-opacity: 0.02;}', // renders two frames ago from the current being rendered
}
```
## L.TiledTorqueLayer(options)
One of two core classes for the Torque library - it is used to create a static torque layer with client side filtering.
##### Provider options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| provider | string | ```sql_api``` | Where is the data coming from? Alternative is 'url_template'|
| url | string | ```null``` | Tile template URL for fetching data e.g 'http://host.com/{z}/{x}/{y}.json'|
##### CartoDB data options (Note to Santana: are these really here?)
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| user | string | ```null``` | CartoDB account name. Found as, accountname.cartodb.com|
| table | string | ```null``` | CartoDB table name where data is found |
| column | string | ```null``` | CartoDB table's column name where date information is found (for dynamic type torque layer only)|
| countby | string | ```null``` | The aggregation method to use for each pixel displayed where multiple data are found. Any valid PostgreSQL aggregate function |
##### Display options (Note to Santana: is blendmode here? or above even?)
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| resolution| numeric | ```2``` | The x and y dimensions of each pixel as returned by the data|
| blendmode | boolean | ```source-over``` | The HTML5 Canvas composite operation for when multiple pixels overlap on the canvas |
### Filtering options
| Method | options | returns | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| ```setKey(keys)``` | ```keys numeric/array``` | ```this``` | which data categories to display on the map |
### Style options
| Method | options | returns | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| ```setCartoCSS(cartocss)``` | ```cartocss string``` | ```this``` | style the map rendering using client-side cartocss |
``value`` and ``zoom`` variables can be used. only ``polygon-fill`` and ``polygon-opacity`` properties are supported currently. To see the full list of supported parameters, read the [Torque CartoCSS documentation here](CartoCSS.md).
TorqueLayer currently expects ```polygon``` styling
##### CartoCSS Example
This should be ```string``` encoded in Javascript
```css
#layer {
polygon-fill: #FFFF00;
[value >= 10] { polygon-fill: #FFCC00; }
[value >= 100] { polygon-fill: #FF9900; }
[value >= 1000] { polygon-fill: #FF6600; }
[value >= 10000] { polygon-fill: #FF3300; }
[value > 100000] { polygon-fill: #C00; }
}
```
# Google Maps Layers
## GMapsTorqueLayer(options)
This class does exactly the same than ``L.TorqueLayer`` but using Google Maps. The main difference is that this class
is not a layer is a overlay so in order to add it to the map use ``layer.setMap`` instead of ``overlayMapTypes``. See [Overlay view](https://developers.google.com/maps/documentation/javascript/reference#OverlayView) reference in Google Maps API doc.
### Options
##### options
| Option | type | Default | Description |
|-----------|:-----------|:----------|:---------------------------------------|
| map | google.maps.Map | | google.maps.Map instance |
see ``L.TorqueLayer`` for the rest of the options.
## GMapsTiledTorqueLayer(options)
creates a static _overlay_ to use it with google maps.
```js
var torqueLayer = new torque.GMapsTiledTorqueLayer({
provider: 'url_template',
url: GBIF_URL,
resolution: 4,
});
torqueLayer.setMap(map);
torqueLayer.setKey([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
```
see ``L.TiledTorqueLayer`` for options reference

View File

@ -1,99 +0,0 @@
<!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>Cebu example map</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(10.315699,123.885437),
zoom: 12,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "osm2",
table: "cebu_locations",
column: "_timestamp_",
cumulative: false,
resolution: 2,
steps: 750,
fps: 24,
fitbounds: false,
clock: false,
blendmode: 'lighter',
trails: true,
point_type:'circle'
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -1,102 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(-34.6036, -58.3817),
zoom: 12,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "gcbadata",
table: "torque_expiration",
column: "start_ts",
expiration_column: "end_ts",
cumulative: true,
cumulative_expires: true,
resolution: 2,
steps: 30,
fps: 12,
fitbounds: false,
clock: true,
blendmode: 'source-over',
trails: false,
point_type:'circle',
cellsize:2
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

67
examples/leaflet.html Normal file
View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html>
<link rel="stylesheet" href="../vendor/leaflet.css" />
<style>
#map, html, body {
width: 100%; height: 100%; padding: 0; margin: 0;
}
</style>
<body>
<div id="map"></div>
<script src="../vendor/leaflet.js"></script>
<script src="../vendor/underscore.js"></script>
<script src="../vendor/carto.js"></script>
<script src="../lib/torque/cartocss_reference.js"></script>
<script src="../lib/torque/profiler.js"></script>
<script src="../lib/torque/request.js"></script>
<script src="../lib/torque/leaflet/leaflet_tileloader_mixin.js"></script>
<script src="../lib/torque/leaflet/canvas_layer.js"></script>
<script src="../lib/torque/renderer/point.js"></script>
<script src="../lib/torque/renderer/rectangle.js"></script>
<script src="../lib/torque/provider.json.js"></script>
<script src="../lib/torque/provider.jsonarray.js"></script>
<script src="../lib/torque/leaflet/torque.js"></script>
<script>
var map = new L.Map('map', {
zoomControl: true,
//center: [0, 0],
center: [36.60670888641815, 38.627929687],
zoom: 6
});
L.tileLayer('http://b.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/999/256/{z}/{x}/{y}.png', {
attribution: 'Stamen'
}).addTo(map);
//type=DATASET
//var GBIF_URL = 'http://apidev.gbif.org/map/density/tile.tcjson?key=8575f23e-f762-11e1-a439-00145eb45e9a&x={x}&y={y}&z={z}&type=DATASET'
var GBIF_URL = 'http://apidev.gbif.org/map/density/tile/density/tile.tcjson?key=1&x={x}&y={y}&z={z}&type=TAXON'
var torqueLayer = new L.TiledTorqueLayer({
//url: 'http://development.localhost.lan:8080/api/v1/sql',
provider: 'url_template',
url: GBIF_URL,
resolution: 4,
cummulative: true,
start_date: 0,
end_date: 220,
step: 1,
table: 'importing_1369045322_helsinki_manydays_live',
column: 'ac',
countby: 'count(mm)',
pixel_size: 3
});
torqueLayer.addTo(map);
torqueLayer.setKey([11, 2]);
var t = 0;
setInterval(function() {
//torqueLayer.setKey(2 + (t++%11));
}, 1000);
</script>
</body>
</html>

113
examples/navy_gmaps.html Normal file
View File

@ -0,0 +1,113 @@
<html>
<link rel="stylesheet" href="../vendor/leaflet.css" />
<style>
#map, html, body {
width: 100%; height: 100%; padding: 0; margin: 0;
}
</style>
<body>
<div id="map"></div>
<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script src="../vendor/underscore.js"></script>
<script src="../vendor/carto.js"></script>
<script src="../dist/torque.js"></script>
<!--
<script src="../lib/torque/cartocss_reference.js"></script>
<script src="../lib/torque/profiler.js"></script>
<script src="../lib/torque/request.js"></script>
<script src="../lib/torque/animator.js"></script>
<script src="../lib/torque/leaflet/leaflet_tileloader_mixin.js"></script>
<script src="../lib/torque/leaflet/canvas_layer.js"></script>
<script src="../lib/torque/renderer/cartocss_render.js"></script>
<script src="../lib/torque/renderer/point.js"></script>
<script src="../lib/torque/renderer/rectangle.js"></script>
<script src="../lib/torque/provider.json.js"></script>
<script src="../lib/torque/provider.jsonarray.js"></script>
<script src="../lib/torque/leaflet/torque.js"></script>
<script src="../lib/torque/gmaps/canvas_tile_layer.js"></script>
<script src="../lib/torque/gmaps/CanvasLayer.js"></script>
<script src="../lib/torque/gmaps/gmaps_tileloader_mixin.js"></script>
<script src="../lib/torque/gmaps/torque.js"></script>
-->
<script>
function initialize() {
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(40.4166909, -3.7003454),
zoom: 2,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var torqueLayer = new torque.GMapsTorqueLayer({
provider: 'sql_api',
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution: 2,
is_time: true,
steps: 750,
blendmode : 'lighter',
animationDuration: 60,
map: map
});
var DEFAULT_CARTOCSS = [
'#layer {',
" marker-width: 3; ",
' marker-fill: #FEE391; ',
' [value > 2] { marker-fill: #FEC44F; }',
' [value > 3] { marker-fill: #FE9929; }',
' [value > 4] { marker-fill: #EC7014; }',
' [value > 5] { marker-fill: #CC4C02; }',
' [value > 6] { marker-fill: #993404; }',
' [value > 7] { marker-fill: #662506; }',
' [frame-offset = 1] { marker-width: 8;marker-fill-opacity: 0.05;}',
' [frame-offset = 2] { marker-width: 20;marker-fill-opacity: 0.02;}',
//' [frame-offset = 1] { marker-width: 25;marker-fill-opacity: 0.01;}',
'}'
].join('\n');
torqueLayer.setCartoCSS(DEFAULT_CARTOCSS);
torqueLayer.setMap(map);
torqueLayer.play()
}
window.onload = initialize;
</script>
</body>
</html>

View File

@ -0,0 +1,79 @@
<html>
<link rel="stylesheet" href="../vendor/leaflet.css" />
<style>
#map, html, body {
width: 100%; height: 100%; padding: 0; margin: 0;
}
</style>
<body>
<div id="map"></div>
<script src="../vendor/leaflet.js"></script>
<script src="../vendor/underscore.js"></script>
<script src="../vendor/carto.js"></script>
<script src="../dist/torque.uncompressed.js"></script>
<!--
<script src="../lib/torque/cartocss_reference.js"></script>
<script src="../lib/torque/profiler.js"></script>
<script src="../lib/torque/request.js"></script>
<script src="../lib/torque/animator.js"></script>
<script src="../lib/torque/leaflet/leaflet_tileloader_mixin.js"></script>
<script src="../lib/torque/leaflet/canvas_layer.js"></script>
<script src="../lib/torque/renderer/cartocss_render.js"></script>
<script src="../lib/torque/renderer/point.js"></script>
<script src="../lib/torque/renderer/rectangle.js"></script>
<script src="../lib/torque/provider.json.js"></script>
<script src="../lib/torque/provider.jsonarray.js"></script>
<script src="../lib/torque/leaflet/torque.js"></script>
-->
<script>
var map = new L.Map('map', {
zoomControl: true,
center: [40, 0],
//center: [36.60670888641815, 38.627929687],
zoom: 2
});
L.tileLayer('http://tile.stamen.com/toner/{z}/{x}/{y}.png', {
attribution: 'Stamen'
}).addTo(map);
var torqueLayer = new L.TorqueLayer({
provider: 'sql_api',
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution: 2,
is_time: true,
steps: 750,
blendmode : 'lighter',
animationDuration: 60
});
var DEFAULT_CARTOCSS = [
'#layer {',
' marker-width: 2;',
' marker-fill: #FEE391; ',
' [value > 2] { marker-fill: #FEC44F; }',
' [value > 3] { marker-fill: #FE9929; }',
' [value > 4] { marker-fill: #EC7014; }',
' [value > 5] { marker-fill: #CC4C02; }',
' [value > 6] { marker-fill: #993404; }',
' [value > 7] { marker-fill: #662506; }',
' [frame-offset = 1] { marker-width: 20; marker-fill-opacity: 0.05;}',
' [frame-offset = 2] { marker-fill: red; marker-width: 30; marker-fill-opacity: 0.02;}',
'}'
].join('\n');
torqueLayer.setCartoCSS(DEFAULT_CARTOCSS);
torqueLayer.addTo(map);
torqueLayer.play()
</script>
</body>
</html>

View File

@ -1,100 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(40.4166909, -3.7003454),
zoom: 10,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "viz2",
table: "madrid_osm_line",
column: "osm_id",
istime: false,
cumulative: false,
resolution: 2,
steps: 750,
fps: 24,
fitbounds: false,
clock: false,
blendmode: 'lighter',
trails: true,
point_type:'circle'
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -6,16 +6,15 @@
<title>CartoDB + Time</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">
<link rel="stylesheet" href="../css/jqueryui-smoothness/jquery-ui-1.10.2.custom.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<style>
#torque-slider{
#torque-slider {
position:absolute;
bottom:18px;
right:25px;
width:300px;
}
#torque-pause{
#torque-pause {
position:absolute;
bottom:12px;
right:345px;
@ -25,140 +24,132 @@
z-index: 1000;
border-radius: 3px;
cursor: pointer;
background-color: white;
background-image: url(../img/play.png);
background-repeat:no-repeat;
background-position:center;
}
.playing {background-color: white; background-image: url(../img/pause.png); background-repeat:no-repeat; background-position:center; }
.paused { background-color: white; background-image: url(../img/play.png);background-repeat:no-repeat; background-position:center;}
/* #torque-pause .playing {
background-image: url('../img/pause.png');
#torque-pause.playing {
background-color: white; background-image: url(../img/pause.png); background-repeat:no-repeat; background-position:center;
}
#torque-time {
position: absolute;
top: 100px;
left: 50%;
color: white;
font-size: 31px;
font-family: Georgia, serif;
}
#torque-pause .paused{
background-image: url('../img/play.png');
}*/
</style>
</head>
<body>
<div id="map_canvas"></div>
<div id="torque-slider"></div>
<a id="torque-pause" class="playing"></a>
<div id="torque-time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="../lib/jquery-ui-1.10.2.custom.min.js"></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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.js"></script>
<script src="../vendor/leaflet.js"></script>
<script src="../vendor/underscore.js"></script>
<script src="../vendor/carto.js"></script>
<script src="../dist/torque.uncompressed.js"></script>
<script type="text/javascript">
var gui;
/**
* inits slider and a small play/pause button
*/
function init_slider(torqueLayer) {
var torqueTime = $('#torque-time');
$("#torque-slider").slider({
min: 0,
max: torqueLayer.options.steps,
value: 0,
step: 1,
slide: function(event, ui){
var step = ui.value;
torqueLayer.setStep(step);
}
});
// each time time changes, move the slider
torqueLayer.on('change:time', function(changes) {
$("#torque-slider" ).slider({ value: changes.step });
var month_year = changes.time.toString().substr(4).split(' ');
torqueTime.text(month_year[0] + " - " + month_year[2]);
console.log(torqueLayer.getTime());
});
// play-pause toggle
$("#torque-pause").click(function(){
torqueLayer.toggle();
$(this).toggleClass('playing');
});
};
function initialize() {
// initialise the google map
var map = new google.maps.Map(document.getElementById('map_canvas'), {
center:new google.maps.LatLng(30.95940879245423, -0.609375),
zoom:2,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
// initialise the google map
var map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(30.95940879245423, -0.609375),
zoom: 2,
mapTypeId: google.maps.MapTypeId.SATELLITE,
mapTypeControl: false,
minZoom: 1
});
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
// dark map style
var gmaps_style = [{ stylers:[ { invert_lightness: true }, { weight:1 }, { saturation:-100 }, { lightness:-40 } ]
}, {
elementType:"labels",
stylers:[ { visibility:"simplified" } ]
}
];
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({ styles: gmaps_style });
// init torque layer
var torqueLayer = new torque.GMapsTorqueLayer({
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
steps: 750,
blendmode : 'lighter',
animationDuration: 60,
map: map
});
function init_slider( that ){
var that_opts = that.options;
$('body').append('<div id="torque-slider"></div>');
// Init jQuery UI options
$("#torque-slider").slider({
min: Math.round(that_opts.start),
max: Math.floor(that_opts.end),
value: Math.round(that_opts.start),
step: that._step,
slide: function(event, ui){
that._current = ui.value;
var date = new Date(that._current * 1000);
var date_arry = date.toString().substr(4).split(' ');
that._display.set_time((that._current - that.start) / that._step);
}
});
};
function on_move (that) {
$( "#torque-slider" ).slider({ value: that._current });
}
var DEFAULT_CARTOCSS = [
'#layer {',
" marker-width: 3; ",
' marker-fill: #FEE391; ',
' [value > 2] { marker-fill: #FEC44F; }',
' [value > 3] { marker-fill: #FE9929; }',
' [value > 4] { marker-fill: #EC7014; }',
' [value > 5] { marker-fill: #CC4C02; }',
' [value > 6] { marker-fill: #993404; }',
' [value > 7] { marker-fill: #662506; }',
' [frame-offset = 1] { marker-width: 8;marker-fill-opacity: 0.05;}',
' [frame-offset = 2] { marker-width: 20;marker-fill-opacity: 0.02;}',
//' [frame-offset = 1] { marker-width: 25;marker-fill-opacity: 0.01;}',
'}'
].join('\n');
var TorqueOptions = {
user:'viz2',
table:'ow',
column:'date',
steps:750,
resolution:2,
cumulative:false,
clock:true,
fps:20,
fitbounds:false,
blendmode:'lighter',
trails:true,
point_type:'circle',
cellsize:1,
scrub: init_slider,
scrub_move: on_move
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
// TODO pause method needs to be added to Torque UI options
var pause = $('<a></a>');
$(pause).attr('id','torque-pause')
$(pause).addClass("playing");
$('body').append(pause);
$(pause).click(function(){
if($(this).hasClass('paused')){
torque.pause();
$(this).removeClass("paused");
$(this).addClass("playing");
} else {
$(this).removeClass("playing");
$(this).addClass("paused");
torque.pause();
}
});
});
torqueLayer.setMap(map);
torqueLayer.setCartoCSS(DEFAULT_CARTOCSS);
init_slider(torqueLayer);
torqueLayer.play();
}
window.onload = initialize;
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>
</body>
</html>

View File

@ -1,169 +0,0 @@
<!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>CartoDB + Time</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">
<link rel="stylesheet" href="../css/jqueryui-smoothness/jquery-ui-1.10.2.custom.min.css">
<style>
#torque-slider{
position:absolute;
bottom:18px;
right:25px;
width:300px;
}
#torque-pause{
position:absolute;
bottom:12px;
right:345px;
width:28px;
height: 26px;
padding: 1px 2px 2px 2px;
z-index: 1000;
border-radius: 3px;
cursor: pointer;
}
.playing {background-color: white; background-image: url(../img/pause.png); background-repeat:no-repeat; background-position:center; }
.paused { background-color: white; background-image: url(../img/play.png);background-repeat:no-repeat; background-position:center;}
/* #torque-pause .playing {
background-image: url('../img/pause.png');
}
#torque-pause .paused{
background-image: url('../img/play.png');
}*/
</style>
<script type="text/javascript" src="http://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/jquery-ui-1.10.2.custom.min.js"></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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(30.95940879245423, -0.609375),
zoom:2,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
disableDefaultUI: true,
minZoom:1,
zoomControl: true,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL
}
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
function init_slider( that ){
var that_opts = that.options;
$('body').append('<div id="torque-slider"></div>');
// Init jQuery UI options
$("#torque-slider").slider({
min: Math.round(that_opts.start),
max: Math.floor(that_opts.end),
value: Math.round(that_opts.start),
step: that._step,
slide: function(event, ui){
that._current = ui.value;
var date = new Date(that._current * 1000);
var date_arry = date.toString().substr(4).split(' ');
that._display.set_time((that._current - that.start) / that._step);
}
});
};
function on_move (that) {
$( "#torque-slider" ).slider({ value: that._current });
}
var TorqueOptions = {
user:'viz2',
table:'ow',
column:'date',
steps:750,
resolution:2,
cumulative:false,
clock:true,
fps:20,
fitbounds:false,
blendmode:'lighter',
trails:true,
point_type:'circle',
cellsize:1,
//scrub: init_slider,
scrub_move: on_move
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
// TODO pause method needs to be added to Torque UI options
var pause = $('<a></a>');
$(pause).attr('id','torque-pause')
$(pause).addClass("playing");
$('body').append(pause);
$(pause).click(function(){
if($(this).hasClass('paused')){
torque.pause();
$(this).removeClass("paused");
$(this).addClass("playing");
} else {
$(this).removeClass("playing");
$(this).addClass("paused");
torque.pause();
}
});
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

221
examples/playground.html Normal file
View File

@ -0,0 +1,221 @@
<!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>CartoDB + Time</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="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<style>
#torque-slider {
position:absolute;
bottom:18px;
right:25px;
width:300px;
}
#torque-pause {
position:absolute;
bottom:12px;
right:345px;
width:28px;
height: 26px;
padding: 1px 2px 2px 2px;
z-index: 1000;
border-radius: 3px;
cursor: pointer;
background-color: white;
background-image: url(../img/play.png);
background-repeat:no-repeat;
background-position:center;
}
#torque-pause.playing {
background-color: white; background-image: url(../img/pause.png); background-repeat:no-repeat; background-position:center;
}
#torque-time {
position: absolute;
top: 100px;
left: 50%;
color: white;
font-size: 31px;
font-family: Georgia, serif;
}
#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;
padding: 40px;
}
.highlight {
font-family: monospace;
font-size: 19px;
color: #000;
}
#credits a { color: #06c; }
#credits {
position: absolute;
bottom: 50px;
left: 40px;
font-size: 17px;
font-family: Helvetica;
}
</style>
</head>
<body>
<div id="map_canvas"></div>
<textarea id="code">
</textarea>
<div id="credits">
<p>Copy the url to share this visualization</p>
<p>Made with <a href="https://github.com/cartodb/torque">Torque</a> and <a href="http://cartodb.com">CartoDB</a></p></div>
<div id="torque-slider"></div>
<a id="torque-pause" class="playing"></a>
<div id="torque-time"></div>
<!--<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script src="../vendor/leaflet.js"></script>
<script src="../vendor/underscore.js"></script>
<script src="../vendor/carto.js"></script>
<script src="../dist/torque.uncompressed.js"></script>
<script type="text/javascript">
/**
* inits slider and a small play/pause button
*/
function init_slider(torqueLayer) {
var torqueTime = $('#torque-time');
$("#torque-slider").slider({
min: 0,
max: torqueLayer.options.steps,
value: 0,
step: 1,
slide: function(event, ui){
var step = ui.value;
torqueLayer.setStep(step);
}
});
// each time time changes, move the slider
torqueLayer.on('change:time', function(changes) {
$("#torque-slider" ).slider({ value: changes.step });
var month_year = changes.time.toString().substr(4).split(' ');
torqueTime.text(month_year[0] + " - " + month_year[2]);
console.log(torqueLayer.getTime());
});
// play-pause toggle
$("#torque-pause").click(function(){
torqueLayer.toggle();
$(this).toggleClass('playing');
});
};
function initialize() {
// initialise the google map
var map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(30.95940879245423, -0.609375),
zoom: 2,
mapTypeId: google.maps.MapTypeId.SATELLITE,
mapTypeControl: false,
minZoom: 1
});
// dark map style
var gmaps_style = [{ stylers:[ { invert_lightness: true }, { weight:1 }, { saturation:-100 }, { lightness:-40 } ]
}, {
elementType:"labels",
stylers:[ { visibility:"simplified" } ]
}
];
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({ styles: gmaps_style });
// init torque layer
var torqueLayer = new torque.GMapsTorqueLayer({
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution: 1,
steps: 750,
blendmode : 'lighter',
animationDuration: 60,
map: map
});
var DEFAULT_CARTOCSS = [
'#layer {',
' marker-width: 2; ',
' marker-fill: #FEE391; ',
' [value > 2] { marker-fill: #FEC44F; }',
' [value > 3] { marker-fill: #FE9929; }',
' [value > 4] { marker-fill: #EC7014; }',
' [value > 5] { marker-fill: #CC4C02; }',
' [value > 6] { marker-fill: #993404; }',
' [value > 7] { marker-fill: #662506; }',
'',
'}',
'',
'#layer [frame-offset = 1] { ',
' marker-fill: #FEE391; ',
' marker-width: 8;',
' marker-fill-opacity: 0.05;',
'}',
'',
'#layer [frame-offset = 2] { ',
' marker-fill: #FEE391; ',
' marker-width: 20;',
' marker-fill-opacity: 0.02;',
'}'
].join('\n');
var code = $('#code')
code.on('keyup', function() {
torqueLayer.setCartoCSS(code.val());
location.hash = btoa(code.val());
});
torqueLayer.setMap(map);
var css = location.hash ? atob(location.hash.substring(1)): DEFAULT_CARTOCSS;
torqueLayer.setCartoCSS(css)
code.val(css);
init_slider(torqueLayer);
torqueLayer.play();
}
window.onload = initialize;
</script>
</body>
</html>

View File

@ -1,100 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(38.27268853598097,-88.2421875),
zoom: 3,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "viz2",
table: "allstorms",
column: "iso_time",
cumulative: false,
resolution: 8,
steps: 10000,
fps: 32,
fitbounds: false,
clock: true,
blendmode: 'lighter',
trails: true,
point_type:'circle',
cellsize:16
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -1,132 +0,0 @@
<!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>CartoDB + Time</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">
<link rel="stylesheet" href="../css/jqueryui-smoothness/jquery-ui-1.10.2.custom.min.css">
<style>
#torque-slider{
position:absolute;
top:5px;
right:25px;
width:300px;
}
</style>
<script type="text/javascript" src="http://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/jquery-ui-1.10.2.custom.min.js"></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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(38.27268853598097,-88.2421875),
zoom: 5,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
function init_slider( that ){
var that_opts = that.options;
$('body').append('<div id="torque-slider"></div>');
// Init jQuery UI options
$("#torque-slider").slider({
min: Math.round(that_opts.start),
max: Math.floor(that_opts.end),
value: Math.round(that_opts.start),
step: that._step,
slide: function(event, ui){
that._current = ui.value;
var date = new Date(that._current * 1000);
var date_arry = date.toString().substr(4).split(' ');
that._display.set_time((that._current - that.start) / that._step);
}
});
};
var TorqueOptions = {
user: "viz2",
table: "us_po_offices",
column: "built",
cumulative: true,
resolution: 2,
steps: 250,
fps: 24,
fitbounds: false,
clock: true,
blendmode: 'source-over',
trails: false,
point_type:'circle',
cellsize:2,
autoplay: false,
scrub: init_slider
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -1,100 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(38.27268853598097,-88.2421875),
zoom: 5,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: false,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "viz2",
table: "us_po_offices",
column: "built",
cumulative: true,
resolution: 2,
steps: 250,
fps: 24,
fitbounds: false,
clock: true,
blendmode: 'source-over',
trails: true,
point_type:'circle',
cellsize:2
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

263
examples/vendor/codemirror.css vendored Normal file
View File

@ -0,0 +1,263 @@
/* BASICS */
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}
/* PADDING */
.CodeMirror-lines {
padding: 4px 0; /* Vertical padding around content */
}
.CodeMirror pre {
padding: 0 4px; /* Horizontal padding of content */
}
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
background-color: white; /* The little square between H and V scrollbars */
}
/* GUTTER */
.CodeMirror-gutters {
border-right: 1px solid #ddd;
background-color: #f7f7f7;
white-space: nowrap;
}
.CodeMirror-linenumbers {}
.CodeMirror-linenumber {
padding: 0 3px 0 5px;
min-width: 20px;
text-align: right;
color: #999;
}
/* CURSOR */
.CodeMirror div.CodeMirror-cursor {
border-left: 1px solid black;
z-index: 3;
}
/* Shown when moving in bi-directional text */
.CodeMirror div.CodeMirror-secondarycursor {
border-left: 1px solid silver;
}
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
width: auto;
border: 0;
background: #7e7;
z-index: 1;
}
/* Can style cursor different in overwrite (non-insert) mode */
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {}
.cm-tab { display: inline-block; }
/* DEFAULT THEME */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}
.cm-negative {color: #d44;}
.cm-positive {color: #292;}
.cm-header, .cm-strong {font-weight: bold;}
.cm-em {font-style: italic;}
.cm-link {text-decoration: underline;}
.cm-invalidchar {color: #f00;}
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-activeline-background {background: #e8f2ff;}
/* STOP */
/* The rest of this file contains styles related to the mechanics of
the editor. You probably shouldn't touch them. */
.CodeMirror {
line-height: 1;
position: relative;
overflow: hidden;
background: white;
color: black;
}
.CodeMirror-scroll {
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
padding-bottom: 30px; padding-right: 30px;
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.CodeMirror-sizer {
position: relative;
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
before actuall scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
z-index: 6;
display: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
overflow-x: hidden;
overflow-y: scroll;
}
.CodeMirror-hscrollbar {
bottom: 0; left: 0;
overflow-y: hidden;
overflow-x: scroll;
}
.CodeMirror-scrollbar-filler {
right: 0; bottom: 0;
}
.CodeMirror-gutter-filler {
left: 0; bottom: 0;
}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
-moz-box-sizing: content-box;
box-sizing: content-box;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
}
.CodeMirror-gutter-elt {
position: absolute;
cursor: default;
z-index: 4;
}
.CodeMirror-lines {
cursor: text;
}
.CodeMirror pre {
/* Reset some styles that the rest of the page might have set */
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
border-width: 0;
background: transparent;
font-family: inherit;
font-size: inherit;
margin: 0;
white-space: pre;
word-wrap: normal;
line-height: inherit;
color: inherit;
z-index: 2;
position: relative;
overflow: visible;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
white-space: pre-wrap;
word-break: normal;
}
.CodeMirror-code pre {
border-right: 30px solid transparent;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.CodeMirror-wrap .CodeMirror-code pre {
border-right: none;
width: auto;
}
.CodeMirror-linebackground {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
z-index: 0;
}
.CodeMirror-linewidget {
position: relative;
z-index: 2;
overflow: auto;
}
.CodeMirror-widget {}
.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}
.CodeMirror-measure {
position: absolute;
width: 100%;
height: 0;
overflow: hidden;
visibility: hidden;
}
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor {
position: absolute;
visibility: hidden;
border-right: none;
width: 0;
}
.CodeMirror-focused div.CodeMirror-cursor {
visibility: visible;
}
.CodeMirror-selected { background: #d9d9d9; }
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
.cm-searching {
background: #ffa;
background: rgba(255, 255, 0, .4);
}
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
.CodeMirror span { *vertical-align: text-bottom; }
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursor {
visibility: hidden;
}
}

5887
examples/vendor/codemirror.js vendored Normal file

File diff suppressed because it is too large Load Diff

639
examples/vendor/css.js vendored Normal file
View File

@ -0,0 +1,639 @@
CodeMirror.defineMode("css", function(config, parserConfig) {
"use strict";
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit || config.tabSize || 2,
hooks = parserConfig.hooks || {},
atMediaTypes = parserConfig.atMediaTypes || {},
atMediaFeatures = parserConfig.atMediaFeatures || {},
propertyKeywords = parserConfig.propertyKeywords || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = !!parserConfig.allowNested,
type = null;
function ret(style, tp) { type = tp; return style; }
function tokenBase(stream, state) {
var ch = stream.next();
if (hooks[ch]) {
// result[0] is style and result[1] is type
var result = hooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
else if (ch == "=") ret(null, "compare");
else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
}
else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
}
else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
}
else if (ch === "-") {
if (/\d/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^[^-]+-/)) {
return ret("meta", "meta");
}
}
else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
}
else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
}
else if (ch == ":") {
return ret("operator", ch);
}
else if (/[;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
}
else if (ch == "u" && stream.match("rl(")) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "variable");
}
else {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "variable");
}
}
function tokenString(quote, nonInclusive) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped)
break;
escaped = !escaped && ch == "\\";
}
if (!escaped) {
if (nonInclusive) stream.backUp(1);
state.tokenize = tokenBase;
}
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\']/, false))
state.tokenize = tokenString(")", true);
else
state.tokenize = tokenBase;
return ret(null, "(");
}
return {
startState: function(base) {
return {tokenize: tokenBase,
baseIndent: base || 0,
stack: [],
lastToken: null};
},
token: function(stream, state) {
// Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
//
// rule** or **ruleset:
// A selector + braces combo, or an at-rule.
//
// declaration block:
// A sequence of declarations.
//
// declaration:
// A property + colon + value combo.
//
// property value:
// The entire value of a property.
//
// component value:
// A single piece of a property value. Like the 5px in
// text-shadow: 0 0 5px blue;. Can also refer to things that are
// multiple terms, like the 1-4 terms that make up the background-size
// portion of the background shorthand.
//
// term:
// The basic unit of author-facing CSS, like a single number (5),
// dimension (5px), string ("foo"), or function. Officially defined
// by the CSS 2.1 grammar (look for the 'term' production)
//
//
// simple selector:
// A single atomic selector, like a type selector, an attr selector, a
// class selector, etc.
//
// compound selector:
// One or more simple selectors without a combinator. div.example is
// compound, div > .example is not.
//
// complex selector:
// One or more compound selectors chained with combinators.
//
// combinator:
// The parts of selectors that express relationships. There are four
// currently - the space (descendant combinator), the greater-than
// bracket (child combinator), the plus sign (next sibling combinator),
// and the tilda (following sibling combinator).
//
// sequence of selectors:
// One or more of the named type of selector chained with commas.
state.tokenize = state.tokenize || tokenBase;
if (state.tokenize == tokenBase && stream.eatSpace()) return null;
var style = state.tokenize(stream, state);
if (style && typeof style != "string") style = ret(style[0], style[1]);
// Changing style returned based on context
var context = state.stack[state.stack.length-1];
if (style == "variable") {
if (type == "variable-definition") state.stack.push("propertyValue");
return state.lastToken = "variable-2";
} else if (style == "property") {
var word = stream.current().toLowerCase();
if (context == "propertyValue") {
if (valueKeywords.hasOwnProperty(word)) {
style = "string-2";
} else if (colorKeywords.hasOwnProperty(word)) {
style = "keyword";
} else {
style = "variable-2";
}
} else if (context == "rule") {
if (!propertyKeywords.hasOwnProperty(word)) {
style += " error";
}
} else if (context == "block") {
// if a value is present in both property, value, or color, the order
// of preference is property -> color -> value
if (propertyKeywords.hasOwnProperty(word)) {
style = "property";
} else if (colorKeywords.hasOwnProperty(word)) {
style = "keyword";
} else if (valueKeywords.hasOwnProperty(word)) {
style = "string-2";
} else {
style = "tag";
}
} else if (!context || context == "@media{") {
style = "tag";
} else if (context == "@media") {
if (atMediaTypes[stream.current()]) {
style = "attribute"; // Known attribute
} else if (/^(only|not)$/.test(word)) {
style = "keyword";
} else if (word == "and") {
style = "error"; // "and" is only allowed in @mediaType
} else if (atMediaFeatures.hasOwnProperty(word)) {
style = "error"; // Known property, should be in @mediaType(
} else {
// Unknown, expecting keyword or attribute, assuming attribute
style = "attribute error";
}
} else if (context == "@mediaType") {
if (atMediaTypes.hasOwnProperty(word)) {
style = "attribute";
} else if (word == "and") {
style = "operator";
} else if (/^(only|not)$/.test(word)) {
style = "error"; // Only allowed in @media
} else {
// Unknown attribute or property, but expecting property (preceded
// by "and"). Should be in parentheses
style = "error";
}
} else if (context == "@mediaType(") {
if (propertyKeywords.hasOwnProperty(word)) {
// do nothing, remains "property"
} else if (atMediaTypes.hasOwnProperty(word)) {
style = "error"; // Known property, should be in parentheses
} else if (word == "and") {
style = "operator";
} else if (/^(only|not)$/.test(word)) {
style = "error"; // Only allowed in @media
} else {
style += " error";
}
} else if (context == "@import") {
style = "tag";
} else {
style = "error";
}
} else if (style == "atom") {
if(!context || context == "@media{" || context == "block") {
style = "builtin";
} else if (context == "propertyValue") {
if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
style += " error";
}
} else {
style = "error";
}
} else if (context == "@media" && type == "{") {
style = "error";
}
// Push/pop context stack
if (type == "{") {
if (context == "@media" || context == "@mediaType") {
state.stack[state.stack.length-1] = "@media{";
}
else {
var newContext = allowNested ? "block" : "rule";
state.stack.push(newContext);
}
}
else if (type == "}") {
if (context == "interpolation") style = "operator";
// Pop off end of array until { is reached
while(state.stack.length){
var removed = state.stack.pop();
if(removed.indexOf("{") > -1){
break;
}
}
}
else if (type == "interpolation") state.stack.push("interpolation");
else if (type == "@media") state.stack.push("@media");
else if (type == "@import") state.stack.push("@import");
else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
state.stack[state.stack.length-1] = "@mediaType";
else if (context == "@mediaType" && stream.current() == ",")
state.stack[state.stack.length-1] = "@media";
else if (type == "(") {
if (context == "@media" || context == "@mediaType") {
// Make sure @mediaType is used to avoid error on {
state.stack[state.stack.length-1] = "@mediaType";
state.stack.push("@mediaType(");
}
else state.stack.push("(");
}
else if (type == ")") {
// Pop off end of array until ( is reached
while(state.stack.length){
var removed = state.stack.pop();
if(removed.indexOf("(") > -1){
break;
}
}
}
else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue");
else if (context == "propertyValue" && type == ";") state.stack.pop();
else if (context == "@import" && type == ";") state.stack.pop();
return state.lastToken = style;
},
indent: function(state, textAfter) {
var n = state.stack.length;
if (/^\}/.test(textAfter))
n -= state.stack[n-1] == "propertyValue" ? 2 : 1;
return state.baseIndent + n * indentUnit;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
fold: "brace"
};
});
(function() {
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i]] = true;
}
return keys;
}
var atMediaTypes = keySet([
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
]);
var atMediaFeatures = keySet([
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid"
]);
var propertyKeywords = keySet([
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-iteration-count",
"animation-name", "animation-play-state", "animation-timing-function",
"appearance", "azimuth", "backface-visibility", "background",
"background-attachment", "background-clip", "background-color",
"background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid-cell", "grid-column", "grid-column-align",
"grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
"grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
"grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marker-offset", "marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
"region-break-before", "region-break-inside", "region-fragment",
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "shape-inside", "shape-outside", "size",
"speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "word-break",
"word-spacing", "word-wrap", "z-index", "zoom",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters", "color-profile",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
]);
var colorKeywords = keySet([
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
"sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
]);
var valueKeywords = keySet([
"above", "absolute", "activeborder", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "column", "compact", "condensed", "contain", "content",
"content-box", "context-menu", "continuous", "copy", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari",
"disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
"double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
"ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer",
"landscape", "lao", "large", "larger", "left", "level", "lighter",
"line-through", "linear", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "malayalam", "match",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer",
"polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button",
"radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region",
"relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba",
"ridge", "right", "round", "row-resize", "rtl", "run-in", "running",
"s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"single", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke",
"sub", "subpixel-antialiased", "super", "sw-resize", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "x-large", "x-small", "xor",
"xx-large", "xx-small"
]);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
atMediaTypes: atMediaTypes,
atMediaFeatures: atMediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
hooks: {
"<": function(stream, state) {
function tokenSGMLComment(stream, state) {
var dashes = 0, ch;
while ((ch = stream.next()) != null) {
if (dashes >= 2 && ch == ">") {
state.tokenize = null;
break;
}
dashes = (ch == "-") ? dashes + 1 : 0;
}
return ["comment", "comment"];
}
if (stream.eat("!")) {
state.tokenize = tokenSGMLComment;
return tokenSGMLComment(stream, state);
}
},
"/": function(stream, state) {
if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
return false;
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
atMediaTypes: atMediaTypes,
atMediaFeatures: atMediaFeatures,
propertyKeywords: propertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
allowNested: true,
hooks: {
":": function(stream) {
if (stream.match(/\s*{/)) {
return [null, "{"];
}
return false;
},
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.peek() == ":") {
return ["variable", "variable-definition"];
}
return ["variable", "variable"];
},
",": function(_stream, state) {
if (state.stack[state.stack.length - 1] == "propertyValue") {
return ["operator", ";"];
}
},
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"#": function(stream) {
if (stream.eat("{")) {
return ["operator", "interpolation"];
} else {
stream.eatWhile(/[\w\\\-]/);
return ["atom", "hash"];
}
}
},
name: "css"
});
})();

View File

@ -1,100 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(38.27268853598097,-88.2421875),
zoom: 4,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: true,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "viz2",
table: "vertnet",
column: "eventdate",
cumulative: true,
resolution: 2,
steps: 400,
fps: 24,
fitbounds: false,
clock: true,
blendmode: 'source-over',
trails: false,
point_type:'square',
cellsize:2
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -1,100 +0,0 @@
<!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>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="../src/grid_layer.js"></script>
<script type="text/javascript" src="../src/torque.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(38.27268853598097,-88.2421875),
zoom: 4,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1,
scrollwheel: false,
panControl: false,
zoomControl: true,
scaleControl: false,
streetViewControl: false,
overviewMapControl: false,
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user: "viz2",
table: "vertnet",
column: "eventdate",
cumulative: true,
resolution: 0.5,
steps: 1,
fps: 0,
fitbounds: false,
clock: false,
blendmode: 'source-over',
trails: false,
point_type:'square',
cellsize:0.5
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas"></div>
<div class="torque_time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
</html>

View File

@ -6,311 +6,285 @@
<title>CartoDB + Time</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="http://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/canvas_tile_layer.js"></script>
<script type="text/javascript" src="src/grid_layer.js"></script>
<script type="text/javascript" src="src/torque.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(30.95940879245423, -0.609375),
zoom:2,
mapTypeId:google.maps.MapTypeId.SATELLITE,
mapTypeControl:false,
minZoom:1
});
var map_style = {};
map_style.google_maps_customization_style = [
{
stylers:[
{ invert_lightness:true },
{ weight:1 },
{ saturation:-100 },
{ lightness:-40 }
]
},
{
elementType:"labels",
stylers:[
{ visibility:"simplified" }
]
}
];
var Soft = function () {
this.Soft = function () {
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
}
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="examples/vendor/codemirror.css">
<style>
#torque-slider {
position:absolute;
bottom:18px;
right:25px;
width:300px;
}
#torque-pause {
position:absolute;
bottom:12px;
right:345px;
width:28px;
height: 26px;
padding: 1px 2px 2px 2px;
z-index: 1000;
border-radius: 3px;
cursor: pointer;
background-color: white;
background-image: url(../img/play.png);
background-repeat:no-repeat;
background-position:center;
}
#torque-pause.playing {
background-color: white; background-image: url(img/pause.png); background-repeat:no-repeat; background-position:center;
}
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({styles:map_style.google_maps_customization_style});
var TorqueOptions = {
user:'viz2',
table:'ow',
column:'date',
steps:750,
resolution:2,
cumulative:false,
clock:true,
fps:20,
fitbounds:false,
blendmode:'lighter',
trails:true,
point_type:'circle',
cellsize:1
#torque-time {
position: absolute;
top: 100px;
left: 50%;
color: white;
font-size: 31px;
font-family: Georgia, serif;
}
var torque = null;
Torque(function (env) {
Torque.app = new env.app.Instance();
torque = new Torque.app.addLayer(map, TorqueOptions);
Torque.env = env;
});
var blend_modes = [
"lighter",
"source-over",
"copy",
"destination-atop",
"destination-in",
"destination-out",
"destination-over",
"source-atop",
"source-in",
"source-out",
"xor"
];
var tablename = 'ow';
dat.GUI.DEFAULT_WIDTH = 300;
var toggle = new dat.GUI();
toggle.add(TorqueOptions, 'user').listen();
toggle.add(TorqueOptions, 'table').listen();
toggle.add(TorqueOptions, 'column').listen();
toggle.add(TorqueOptions, 'resolution', [1, 2, 4, 8, 16, 32]).listen();
toggle.add(TorqueOptions, 'cellsize', 0, 50).listen();
toggle.add(TorqueOptions, 'cumulative').listen();
toggle.add(TorqueOptions, 'trails').listen();
toggle.add(TorqueOptions, 'steps', 10, 750).listen();
toggle.add(TorqueOptions, 'fps', 0.05, 48, false).listen();
toggle.add(TorqueOptions, 'blendmode', blend_modes).listen();
toggle.add(TorqueOptions, 'point_type', ['circle', 'square']).listen();
var that = this;
var updateTorque = function () {
this.updateTorque = function () {
if (TorqueOptions.table != tablename) {
tablename = TorqueOptions.table;
TorqueOptions.fitbounds = true;
} else {
TorqueOptions.fitbounds = false;
}
torque.setOptions(TorqueOptions);
}
.CodeMirror {
top: 0;
bottom: 0;
position:absolute;
height: auto;
width: 380;
padding-left: 20px;
}
toggle.add(new updateTorque(), 'updateTorque');
var pause = function () {
this.pause = function () {
torque.pause();
}
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;
padding: 40px;
}
toggle.add(new pause(), 'pause');
</style>
</head>
var PresetOptions = function () {
this.old_weather_agg = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "ow";
TorqueOptions.column = "date";
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 2;
TorqueOptions.steps = 750;
TorqueOptions.fps = 30;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.old_weather_live = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "ow";
TorqueOptions.column = "date";
TorqueOptions.cumulative = false;
TorqueOptions.resolution = 2;
TorqueOptions.steps = 750;
TorqueOptions.fps = 30;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.blendmode = 'lighter';
TorqueOptions.trails = true;
TorqueOptions.point_type = 'circle';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.ny_bus = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "ny_bus";
TorqueOptions.column = "timestamp";
TorqueOptions.cumulative = false;
TorqueOptions.resolution = 4;
TorqueOptions.steps = 500;
TorqueOptions.fps = 4;
TorqueOptions.fitbounds = 2;
TorqueOptions.clock = true;
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.us_postoffices = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "us_po_offices";
TorqueOptions.column = "built";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 2;
TorqueOptions.steps = 250;
TorqueOptions.fps = 32;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.stop_frisk = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "sfrisk_dates";
TorqueOptions.column = "datestop";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 4;
TorqueOptions.steps = 200;
TorqueOptions.fps = 16;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.stop_frisk_live = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "sfrisk_dates";
TorqueOptions.column = "datestop";
TorqueOptions.cumulative = false;
TorqueOptions.blendmode = 'lighter';
TorqueOptions.trails = true;
TorqueOptions.point_type = 'circle';
TorqueOptions.resolution = 2;
TorqueOptions.steps = 200;
TorqueOptions.fps = 50;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
this.jatorre_flights = function () {
TorqueOptions.user = "osm2";
TorqueOptions.table = "openpaths_segments";
TorqueOptions.column = "end_timestamp";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 2;
TorqueOptions.steps = 500;
TorqueOptions.fps = 24;
TorqueOptions.fitbounds = -1;
TorqueOptions.clock = true;
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions);
}
this.quake_total = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "quksigx020";
TorqueOptions.column = "quakedate";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 8;
TorqueOptions.steps = 441;
TorqueOptions.fps = 21;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.countby = 'sum(mmio)';
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions);
}
this.quake_size = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "quakesize";
TorqueOptions.column = "quakedate";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 1;
TorqueOptions.steps = 441;
TorqueOptions.fps = 21;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
//TorqueOptions.countby = 'sum(mmio)';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions);
}
this.african_honey_bee = function () {
TorqueOptions.user = "viz2";
TorqueOptions.table = "africanhoneybee";
TorqueOptions.column = "first_year";
TorqueOptions.cumulative = true;
TorqueOptions.resolution = 1;
TorqueOptions.steps = 29;
TorqueOptions.fps = 2;
TorqueOptions.fitbounds = 1;
TorqueOptions.clock = true;
TorqueOptions.blendmode = 'source-over';
TorqueOptions.trails = false;
TorqueOptions.point_type = 'square';
tablename = TorqueOptions.table;
torque.setOptions(TorqueOptions)
}
}
var ps = new PresetOptions();
var presets = toggle.addFolder("Other examples", false);
presets.add(ps, 'us_postoffices');
//presets.add(ps, 'african_honey_bee');
presets.add(ps, 'quake_total');
//presets.add(ps, 'quake_size');
presets.add(ps, 'stop_frisk');
presets.add(ps, 'stop_frisk_live');
presets.add(ps, 'jatorre_flights');
presets.add(ps, 'ny_bus');
presets.add(ps, 'old_weather_agg');
presets.add(ps, 'old_weather_live');
}
</script>
</head>
<body onload="initialize()">
<body>
<div id="map_canvas"></div>
<div class="torque_time"></div>
<textarea id="code"></textarea>
<div id="torque-slider"></div>
<a id="torque-pause" class="playing"></a>
<div id="torque-time"></div>
<a class="cartodb_logo" href="http://www.cartodb.com" target="_blank">CartoDB</a>
</body>
<script id="default-style" type="text/torque-cartocss">
#layer {
marker-width: 3;
marker-fill: #FEE391;
[value > 2] { marker-fill: #FEC44F; }
[value > 3] { marker-fill: #FE9929; }
[value > 4] { marker-fill: #EC7014; }
[value > 5] { marker-fill: #CC4C02; }
[value > 6] { marker-fill: #993404; }
[value > 7] { marker-fill: #662506; }
[frame-offset = 1] {
marker-width: 8;
marker-fill-opacity: 0.05;
}
[frame-offset = 2] {
marker-width: 20;
marker-fill-opacity: 0.02;
}
}
</script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script src="vendor/leaflet.js"></script>
<script src="vendor/underscore.js"></script>
<script src="vendor/carto.js"></script>
<script src="examples/vendor/codemirror.js"></script>
<script src="examples/vendor/css.js"></script>
<script src="dist/torque.uncompressed.js"></script>
<script type="text/javascript" src="examples/vendor/dat.gui.min.js"></script>
<script type="text/javascript">
var torqueLayer;
var ui;
var editor;
var state = location.hash ? JSON.parse(atob(location.hash.substring(1))): {};
var DEFAULT_CARTOCSS = state.cartocss || $('#default-style').html();
function saveState() {
location.hash = btoa(JSON.stringify({
cartocss: editor.getValue(),
options: _.pick(torqueLayer.options,
'user',
'table',
'column',
'is_time',
'countby',
'resolution',
'steps',
'animationDuration'
)
}))
}
function init_torque(map, options) {
// init torque layer
torqueLayer = new torque.GMapsTorqueLayer(_.extend({
user : 'viz2',
table : 'ow',
column : 'date',
countby : 'count(cartodb_id)',
resolution: 1,
is_time: true,
steps: 800,
blendmode : 'lighter',
animationDuration: 30,
map: map
}, options));
torqueLayer.setMap(map);
torqueLayer.setCartoCSS(DEFAULT_CARTOCSS);
init_slider(torqueLayer);
init_ui(map, torqueLayer);
torqueLayer.on('change:bounds', function(changes) {
var bounds = changes.bounds;
var b = new google.maps.LatLngBounds(
new google.maps.LatLng(
bounds[0][0],
bounds[0][1]
),
new google.maps.LatLng(
bounds[1][0],
bounds[1][1]
)
)
map.fitBounds(b);
});
torqueLayer.play();
}
function toggle_editor() {
$(editor.getWrapperElement()).toggle()
}
function init_ui(map, torqueLayer) {
var TorqueOptions = _.clone(torqueLayer.options);
dat.GUI.DEFAULT_WIDTH = 300;
if (ui) {
ui.destroy();
ui = null;
}
ui = new dat.GUI();
ui.remember(TorqueOptions);
ui.add(TorqueOptions, 'user')
ui.add(TorqueOptions, 'table')
ui.add(TorqueOptions, 'column')
ui.add(TorqueOptions, 'is_time')
ui.add(TorqueOptions, 'countby')
ui.add(TorqueOptions, 'resolution', [1, 2, 4, 8, 16, 32])
ui.add(TorqueOptions, 'steps', 10, 1024).listen()
ui.add(TorqueOptions, 'animationDuration', 5, 120);
ui.add({ cartocss_editor: toggle_editor }, 'cartocss_editor');
//ui.remember(TorqueOptions);
//ui.add(TorqueOptions, 'blendmode', blend_modes);
ui.add({
update: function() {
if (torqueLayer) {
torqueLayer.setMap(null);
torqueLayer.off('change:time');
torqueLayer.off('change:bounds');
torqueLayer = null;
}
init_torque(map, TorqueOptions);
saveState();
}
}, 'update');
if (!editor) {
var textarea = document.getElementById('code')
textarea.value = DEFAULT_CARTOCSS;
editor = CodeMirror.fromTextArea(textarea, { mode: "text/css" });
editor.on('change', _.debounce(function() {
window.torqueLayer.setCartoCSS(editor.getValue());
saveState();
}, 500))
}
editor
}
/**
* inits slider and a small play/pause button
*/
function init_slider(torqueLayer) {
var torqueTime = $('#torque-time');
$("#torque-slider").slider({
min: 0,
max: torqueLayer.options.steps,
value: 0,
step: 1,
slide: function(event, ui){
var step = ui.value;
torqueLayer.setStep(step);
}
});
// each time time changes, move the slider
torqueLayer.on('change:time', function(changes) {
$("#torque-slider" ).slider({ value: changes.step });
var month_year = changes.time.toString().substr(4).split(' ');
torqueTime.text(month_year[0] + " - " + month_year[2]);
});
// play-pause toggle
$("#torque-pause").click(function(){
torqueLayer.toggle();
$(this).toggleClass('playing');
});
};
function initialize() {
// initialise the google map
var map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(37.82070064677705, -122.42739200592041),
zoom: 13,
mapTypeId: google.maps.MapTypeId.SATELLITE,
mapTypeControl: false,
minZoom: 2
});
// dark map style
var gmaps_style = [{ stylers:[ { invert_lightness: true }, { weight:1 }, { saturation:-100 }, { lightness:-40 } ]
}, {
elementType:"labels",
stylers:[ { visibility:"simplified" } ]
}
];
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
map.setOptions({ styles: gmaps_style });
init_torque(map, state.options);
}
window.onload = initialize;
</script>
</body>
</html>

View File

@ -1,210 +0,0 @@
/**
*
* 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/v2/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
};
};

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

File diff suppressed because it is too large Load Diff

View File

@ -1,542 +0,0 @@
/**
* @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/v2/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/v2/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);

View File

@ -1,26 +0,0 @@
/*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;}
div.torque_time {position:absolute; bottom:28px; right:15px; display:block; width:189px; height:27px;color:white;}

View File

@ -1,66 +0,0 @@
/* 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;
};
})();

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

93
lib/torque/animator.js Normal file
View File

@ -0,0 +1,93 @@
(function(exports) {
exports.torque = exports.torque || {};
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(c) { setTimeout(c, 16); }
var cancelAnimationFrame = window.requestAnimationFrame || window.mozCancelAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(c) { cancelTimeout(c); };
/**
* options:
* animationDuration in seconds
* animationDelay in seconds
*/
function Animator(callback, options) {
if(!options.steps) {
throw new Error("steps option missing")
}
this.options = options;
this.running = false;
this._tick = this._tick.bind(this);
this._t0 = +new Date();
this.callback = callback;
this._time = 0.0;
_.defaults(this.options, {
animationDelay: 0,
maxDelta: 0.2,
loop: true
});
this.domainInv = torque.math.linear(this.options.animationDelay, this.options.animationDelay + this.options.animationDuration);
this.domain = this.domainInv.invert();
this.range = torque.math.linear(0, this.options.steps);
this.rangeInv = this.range.invert();
}
Animator.prototype = {
start: function() {
this.running = true;
requestAnimationFrame(this._tick);
},
stop: function() {
this.pause();
this._time = 0;
var t = this.range(this.domain(this._time));
this.callback(t);
},
toggle: function() {
if (this.running) {
this.pause()
} else {
this.start()
}
},
step: function(s) {
if(arguments.length === 0) return this.range(this.domain(this._time));
this._time = this.domainInv(this.rangeInv(s));
},
pause: function() {
this.running = false;
cancelAnimationFrame(this._tick);
},
_tick: function() {
var t1 = +new Date();
var delta = (t1 - this._t0)*0.001;
// if delta is really big means the tab lost the focus
// at some point, so limit delta change
delta = Math.min(this.options.maxDelta, delta);
this._t0 = t1;
this._time += delta;
var t = this.range(this.domain(this._time));
this.callback(t);
if(t >= this.options.steps) {
this._time = 0;
}
if(this.running) {
requestAnimationFrame(this._tick);
}
}
};
exports.torque.Animator = Animator;
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,348 @@
(function(exports) {
exports.torque = exports.torque || {};
var _torque_reference_latest = {
"version": "1.0.0",
"style": {
"comp-op": {
"css": "comp-op",
"default-value": "src-over",
"default-meaning": "add the current layer on top of other layers",
"doc": "Composite operation. This defines how this layer should behave relative to layers atop or below it.",
"type": [
"src", //
"src-over", //
"dst-over", //
"src-in", //
"dst-in", //
"src-out", //
"dst-out", //
"src-atop", //
"dst-atop", //
"xor", //
"darken", //
"lighten" //
]
}
},
"symbolizers" : {
"*": {
"comp-op": {
"css": "comp-op",
"default-value": "src-over",
"default-meaning": "add the current layer on top of other layers",
"doc": "Composite operation. This defines how this layer should behave relative to layers atop or below it.",
"type": [
"src", //
"src-over", //
"dst-over", //
"src-in", //
"dst-in", //
"src-out", //
"dst-out", //
"src-atop", //
"dst-atop", //
"xor", //
"darken", //
"lighten" //
]
},
"opacity": {
"css": "opacity",
"type": "float",
"doc": "An alpha value for the style (which means an alpha applied to all features in separate buffer and then composited back to main buffer)",
"default-value": 1,
"default-meaning": "no separate buffer will be used and no alpha will be applied to the style after rendering"
}
},
"trail": {
"steps": {
"css": "trail-steps",
"type": "float",
"default-value": 1,
"default-meaning": "no trail steps",
"doc": "How many steps of trails are going to be rendered"
}
},
"polygon": {
"fill": {
"css": "polygon-fill",
"type": "color",
"default-value": "rgba(128,128,128,1)",
"default-meaning": "gray and fully opaque (alpha = 1), same as rgb(128,128,128)",
"doc": "Fill color to assign to a polygon"
},
"fill-opacity": {
"css": "polygon-opacity",
"type": "float",
"doc": "The opacity of the polygon",
"default-value": 1,
"default-meaning": "opaque"
}
},
"line": {
"stroke": {
"css": "line-color",
"default-value": "rgba(0,0,0,1)",
"type": "color",
"default-meaning": "black and fully opaque (alpha = 1), same as rgb(0,0,0)",
"doc": "The color of a drawn line"
},
"stroke-width": {
"css": "line-width",
"default-value": 1,
"type": "float",
"doc": "The width of a line in pixels"
},
"stroke-opacity": {
"css": "line-opacity",
"default-value": 1,
"type": "float",
"default-meaning": "opaque",
"doc": "The opacity of a line"
},
"stroke-linejoin": {
"css": "line-join",
"default-value": "miter",
"type": [
"miter",
"round",
"bevel"
],
"doc": "The behavior of lines when joining"
},
"stroke-linecap": {
"css": "line-cap",
"default-value": "butt",
"type": [
"butt",
"round",
"square"
],
"doc": "The display of line endings"
}
},
"markers": {
"file": {
"css": "marker-file",
"doc": "An SVG file that this marker shows at each placement. If no file is given, the marker will show an ellipse.",
"default-value": "",
"default-meaning": "An ellipse or circle, if width equals height",
"type": "uri"
},
"opacity": {
"css": "marker-opacity",
"doc": "The overall opacity of the marker, if set, overrides both the opacity of both the fill and stroke",
"default-value": 1,
"default-meaning": "The stroke-opacity and fill-opacity will be used",
"type": "float"
},
"fill-opacity": {
"css": "marker-fill-opacity",
"doc": "The fill opacity of the marker",
"default-value": 1,
"default-meaning": "opaque",
"type": "float"
},
"stroke": {
"css": "marker-line-color",
"doc": "The color of the stroke around a marker shape.",
"default-value": "black",
"type": "color"
},
"stroke-width": {
"css": "marker-line-width",
"doc": "The width of the stroke around a marker shape, in pixels. This is positioned on the boundary, so high values can cover the area itself.",
"type": "float"
},
"stroke-opacity": {
"css": "marker-line-opacity",
"default-value": 1,
"default-meaning": "opaque",
"doc": "The opacity of a line",
"type": "float"
},
"fill": {
"css": "marker-fill",
"default-value": "blue",
"doc": "The color of the area of the marker.",
"type": "color"
}
},
"point": {
"file": {
"css": "point-file",
"type": "uri",
"required": false,
"default-value": "none",
"doc": "Image file to represent a point"
},
"opacity": {
"css": "point-opacity",
"type": "float",
"default-value": 1.0,
"default-meaning": "Fully opaque",
"doc": "A value from 0 to 1 to control the opacity of the point"
}
}
},
"colors": {
"aliceblue": [240, 248, 255],
"antiquewhite": [250, 235, 215],
"aqua": [0, 255, 255],
"aquamarine": [127, 255, 212],
"azure": [240, 255, 255],
"beige": [245, 245, 220],
"bisque": [255, 228, 196],
"black": [0, 0, 0],
"blanchedalmond": [255,235,205],
"blue": [0, 0, 255],
"blueviolet": [138, 43, 226],
"brown": [165, 42, 42],
"burlywood": [222, 184, 135],
"cadetblue": [95, 158, 160],
"chartreuse": [127, 255, 0],
"chocolate": [210, 105, 30],
"coral": [255, 127, 80],
"cornflowerblue": [100, 149, 237],
"cornsilk": [255, 248, 220],
"crimson": [220, 20, 60],
"cyan": [0, 255, 255],
"darkblue": [0, 0, 139],
"darkcyan": [0, 139, 139],
"darkgoldenrod": [184, 134, 11],
"darkgray": [169, 169, 169],
"darkgreen": [0, 100, 0],
"darkgrey": [169, 169, 169],
"darkkhaki": [189, 183, 107],
"darkmagenta": [139, 0, 139],
"darkolivegreen": [85, 107, 47],
"darkorange": [255, 140, 0],
"darkorchid": [153, 50, 204],
"darkred": [139, 0, 0],
"darksalmon": [233, 150, 122],
"darkseagreen": [143, 188, 143],
"darkslateblue": [72, 61, 139],
"darkslategrey": [47, 79, 79],
"darkturquoise": [0, 206, 209],
"darkviolet": [148, 0, 211],
"deeppink": [255, 20, 147],
"deepskyblue": [0, 191, 255],
"dimgray": [105, 105, 105],
"dimgrey": [105, 105, 105],
"dodgerblue": [30, 144, 255],
"firebrick": [178, 34, 34],
"floralwhite": [255, 250, 240],
"forestgreen": [34, 139, 34],
"fuchsia": [255, 0, 255],
"gainsboro": [220, 220, 220],
"ghostwhite": [248, 248, 255],
"gold": [255, 215, 0],
"goldenrod": [218, 165, 32],
"gray": [128, 128, 128],
"grey": [128, 128, 128],
"green": [0, 128, 0],
"greenyellow": [173, 255, 47],
"honeydew": [240, 255, 240],
"hotpink": [255, 105, 180],
"indianred": [205, 92, 92],
"indigo": [75, 0, 130],
"ivory": [255, 255, 240],
"khaki": [240, 230, 140],
"lavender": [230, 230, 250],
"lavenderblush": [255, 240, 245],
"lawngreen": [124, 252, 0],
"lemonchiffon": [255, 250, 205],
"lightblue": [173, 216, 230],
"lightcoral": [240, 128, 128],
"lightcyan": [224, 255, 255],
"lightgoldenrodyellow": [250, 250, 210],
"lightgray": [211, 211, 211],
"lightgreen": [144, 238, 144],
"lightgrey": [211, 211, 211],
"lightpink": [255, 182, 193],
"lightsalmon": [255, 160, 122],
"lightseagreen": [32, 178, 170],
"lightskyblue": [135, 206, 250],
"lightslategray": [119, 136, 153],
"lightslategrey": [119, 136, 153],
"lightsteelblue": [176, 196, 222],
"lightyellow": [255, 255, 224],
"lime": [0, 255, 0],
"limegreen": [50, 205, 50],
"linen": [250, 240, 230],
"magenta": [255, 0, 255],
"maroon": [128, 0, 0],
"mediumaquamarine": [102, 205, 170],
"mediumblue": [0, 0, 205],
"mediumorchid": [186, 85, 211],
"mediumpurple": [147, 112, 219],
"mediumseagreen": [60, 179, 113],
"mediumslateblue": [123, 104, 238],
"mediumspringgreen": [0, 250, 154],
"mediumturquoise": [72, 209, 204],
"mediumvioletred": [199, 21, 133],
"midnightblue": [25, 25, 112],
"mintcream": [245, 255, 250],
"mistyrose": [255, 228, 225],
"moccasin": [255, 228, 181],
"navajowhite": [255, 222, 173],
"navy": [0, 0, 128],
"oldlace": [253, 245, 230],
"olive": [128, 128, 0],
"olivedrab": [107, 142, 35],
"orange": [255, 165, 0],
"orangered": [255, 69, 0],
"orchid": [218, 112, 214],
"palegoldenrod": [238, 232, 170],
"palegreen": [152, 251, 152],
"paleturquoise": [175, 238, 238],
"palevioletred": [219, 112, 147],
"papayawhip": [255, 239, 213],
"peachpuff": [255, 218, 185],
"peru": [205, 133, 63],
"pink": [255, 192, 203],
"plum": [221, 160, 221],
"powderblue": [176, 224, 230],
"purple": [128, 0, 128],
"red": [255, 0, 0],
"rosybrown": [188, 143, 143],
"royalblue": [65, 105, 225],
"saddlebrown": [139, 69, 19],
"salmon": [250, 128, 114],
"sandybrown": [244, 164, 96],
"seagreen": [46, 139, 87],
"seashell": [255, 245, 238],
"sienna": [160, 82, 45],
"silver": [192, 192, 192],
"skyblue": [135, 206, 235],
"slateblue": [106, 90, 205],
"slategray": [112, 128, 144],
"slategrey": [112, 128, 144],
"snow": [255, 250, 250],
"springgreen": [0, 255, 127],
"steelblue": [70, 130, 180],
"tan": [210, 180, 140],
"teal": [0, 128, 128],
"thistle": [216, 191, 216],
"tomato": [255, 99, 71],
"turquoise": [64, 224, 208],
"violet": [238, 130, 238],
"wheat": [245, 222, 179],
"white": [255, 255, 255],
"whitesmoke": [245, 245, 245],
"yellow": [255, 255, 0],
"yellowgreen": [154, 205, 50],
"transparent": [0, 0, 0, 0]
}
};
exports.torque['torque-reference'] = {
version: {
latest: _torque_reference_latest,
'1.0.0': _torque_reference_latest
}
}
})(typeof exports === "undefined" ? this : exports);

44
lib/torque/core.js Normal file
View File

@ -0,0 +1,44 @@
(function(exports) {
exports.torque = exports.torque || {};
var Event = {};
Event.on = function(evt, callback) {
var cb = this._evt_callbacks = this._evt_callbacks || {};
var l = cb[evt] || (cb[evt] = []);
l.push(callback);
};
Event.trigger = function(evt) {
var c = this._evt_callbacks && this._evt_callbacks[evt];
for(var i = 0; c && i < c.length; ++i) {
c[i].apply(this, Array.prototype.slice.call(arguments, 1));
}
};
Event.fire = Event.trigger;
Event.off = function (evt, callback) {
var c = this._evt_callbacks && this._evt_callbacks[evt];
if (c && !callback) {
delete this._evt_callbacks[evt];
return this;
}
var remove = [];
for(var i = 0; c && i < c.length; ++i) {
if(c[i] === callback) remove.push(i);
}
while(i = remove.pop()) c.splice(i, 1);
};
exports.torque.Event = Event;
// types
exports.torque.types = {
Uint8Array: typeof(window['Uint8Array']) !== 'undefined' ? window.Uint8Array : Array,
Uint32Array: typeof(window['Uint32Array']) !== 'undefined' ? window.Uint32Array : Array,
Int32Array: typeof(window['Int32Array']) !== 'undefined' ? window.Int32Array: Array,
};
})(typeof exports === "undefined" ? this : exports);

506
lib/torque/gmaps/CanvasLayer.js Executable file
View File

@ -0,0 +1,506 @@
/**
* @license
* Copyright 2013 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Extends OverlayView to provide a canvas "Layer".
* @author Brendan Kenny
*/
/**
* A map layer that provides a canvas over the slippy map and a callback
* system for efficient animation. Requires canvas and CSS 2D transform
* support.
* @constructor
* @extends google.maps.OverlayView
* @param {CanvasLayerOptions=} opt_options Options to set in this CanvasLayer.
*/
if(typeof(google) !== 'undefined' && typeof(google.maps) !== 'undefined') {
function CanvasLayer(opt_options) {
/**
* If true, canvas is in a map pane and the OverlayView is fully functional.
* See google.maps.OverlayView.onAdd for more information.
* @type {boolean}
* @private
*/
this.isAdded_ = false;
/**
* If true, each update will immediately schedule the next.
* @type {boolean}
* @private
*/
this.isAnimated_ = false;
/**
* The name of the MapPane in which this layer will be displayed.
* @type {string}
* @private
*/
this.paneName_ = CanvasLayer.DEFAULT_PANE_NAME_;
/**
* A user-supplied function called whenever an update is required. Null or
* undefined if a callback is not provided.
* @type {?function=}
* @private
*/
this.updateHandler_ = null;
/**
* A user-supplied function called whenever an update is required and the
* map has been resized since the last update. Null or undefined if a
* callback is not provided.
* @type {?function}
* @private
*/
this.resizeHandler_ = null;
/**
* The LatLng coordinate of the top left of the current view of the map. Will
* be null when this.isAdded_ is false.
* @type {google.maps.LatLng}
* @private
*/
this.topLeft_ = null;
/**
* The map-pan event listener. Will be null when this.isAdded_ is false. Will
* be null when this.isAdded_ is false.
* @type {?function}
* @private
*/
this.centerListener_ = null;
/**
* The map-resize event listener. Will be null when this.isAdded_ is false.
* @type {?function}
* @private
*/
this.resizeListener_ = null;
/**
* If true, the map size has changed and this.resizeHandler_ must be called
* on the next update.
* @type {boolean}
* @private
*/
this.needsResize_ = true;
/**
* A browser-defined id for the currently requested callback. Null when no
* callback is queued.
* @type {?number}
* @private
*/
this.requestAnimationFrameId_ = null;
var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.top = 0;
canvas.style.left = 0;
canvas.style.pointerEvents = 'none';
/**
* The canvas element.
* @type {!HTMLCanvasElement}
*/
this.canvas = canvas;
/**
* Simple bind for functions with no args for bind-less browsers (Safari).
* @param {Object} thisArg The this value used for the target function.
* @param {function} func The function to be bound.
*/
function simpleBindShim(thisArg, func) {
return function() { func.apply(thisArg); };
}
/**
* A reference to this.repositionCanvas_ with this bound as its this value.
* @type {function}
* @private
*/
this.repositionFunction_ = simpleBindShim(this, this.repositionCanvas_);
/**
* A reference to this.resize_ with this bound as its this value.
* @type {function}
* @private
*/
this.resizeFunction_ = simpleBindShim(this, this.resize_);
/**
* A reference to this.update_ with this bound as its this value.
* @type {function}
* @private
*/
this.requestUpdateFunction_ = simpleBindShim(this, this.update_);
// set provided options, if any
if (opt_options) {
this.setOptions(opt_options);
}
}
CanvasLayer.prototype = new google.maps.OverlayView();
/**
* The default MapPane to contain the canvas.
* @type {string}
* @const
* @private
*/
CanvasLayer.DEFAULT_PANE_NAME_ = 'overlayLayer';
/**
* Transform CSS property name, with vendor prefix if required. If browser
* does not support transforms, property will be ignored.
* @type {string}
* @const
* @private
*/
CanvasLayer.CSS_TRANSFORM_ = (function() {
var div = document.createElement('div');
var transformProps = [
'transform',
'WebkitTransform',
'MozTransform',
'OTransform',
'msTransform'
];
for (var i = 0; i < transformProps.length; i++) {
var prop = transformProps[i];
if (div.style[prop] !== undefined) {
return prop;
}
}
// return unprefixed version by default
return transformProps[0];
})();
/**
* The requestAnimationFrame function, with vendor-prefixed or setTimeout-based
* fallbacks. MUST be called with window as thisArg.
* @type {function}
* @param {function} callback The function to add to the frame request queue.
* @return {number} The browser-defined id for the requested callback.
* @private
*/
CanvasLayer.prototype.requestAnimFrame_ =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
/**
* The cancelAnimationFrame function, with vendor-prefixed fallback. Does not
* fall back to clearTimeout as some platforms implement requestAnimationFrame
* but not cancelAnimationFrame, and the cost is an extra frame on onRemove.
* MUST be called with window as thisArg.
* @type {function}
* @param {number=} requestId The id of the frame request to cancel.
* @private
*/
CanvasLayer.prototype.cancelAnimFrame_ =
window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
window.msCancelAnimationFrame ||
function(requestId) {};
/**
* Sets any options provided. See CanvasLayerOptions for more information.
* @param {CanvasLayerOptions} options The options to set.
*/
CanvasLayer.prototype.setOptions = function(options) {
if (options.animate !== undefined) {
this.setAnimate(options.animate);
}
if (options.paneName !== undefined) {
this.setPane(options.paneName);
}
if (options.updateHandler !== undefined) {
this.setUpdateHandler(options.updateHandler);
}
if (options.resizeHandler !== undefined) {
this.setResizeHandler(options.resizeHandler);
}
if(options.readyHandler) {
this.readyHandler = options.readyHandler;
}
};
/**
* Set the animated state of the layer. If true, updateHandler will be called
* repeatedly, once per frame. If false, updateHandler will only be called when
* a map property changes that could require the canvas content to be redrawn.
* @param {boolean} animate Whether the canvas is animated.
*/
CanvasLayer.prototype.setAnimate = function(animate) {
this.isAnimated_ = !!animate;
if (this.isAnimated_) {
this.scheduleUpdate();
}
};
/**
* @return {boolean} Whether the canvas is animated.
*/
CanvasLayer.prototype.isAnimated = function() {
return this.isAnimated_;
};
/**
* Set the MapPane in which this layer will be displayed, by name. See
* {@code google.maps.MapPanes} for the panes available.
* @param {string} paneName The name of the desired MapPane.
*/
CanvasLayer.prototype.setPaneName = function(paneName) {
this.paneName_ = paneName;
this.setPane_();
};
/**
* @return {string} The name of the current container pane.
*/
CanvasLayer.prototype.getPaneName = function() {
return this.paneName_;
};
/**
* Adds the canvas to the specified container pane. Since this is guaranteed to
* execute only after onAdd is called, this is when paneName's existence is
* checked (and an error is thrown if it doesn't exist).
* @private
*/
CanvasLayer.prototype.setPane_ = function() {
if (!this.isAdded_) {
return;
}
// onAdd has been called, so panes can be used
var panes = this.getPanes();
if (!panes[this.paneName_]) {
throw new Error('"' + this.paneName_ + '" is not a valid MapPane name.');
}
panes[this.paneName_].appendChild(this.canvas);
};
/**
* Set a function that will be called whenever the parent map and the overlay's
* canvas have been resized. If opt_resizeHandler is null or unspecified, any
* existing callback is removed.
* @param {?function=} opt_resizeHandler The resize callback function.
*/
CanvasLayer.prototype.setResizeHandler = function(opt_resizeHandler) {
this.resizeHandler_ = opt_resizeHandler;
};
/**
* Set a function that will be called when a repaint of the canvas is required.
* If opt_updateHandler is null or unspecified, any existing callback is
* removed.
* @param {?function=} opt_updateHandler The update callback function.
*/
CanvasLayer.prototype.setUpdateHandler = function(opt_updateHandler) {
this.updateHandler_ = opt_updateHandler;
};
/**
* @inheritDoc
*/
CanvasLayer.prototype.onAdd = function() {
if (this.isAdded_) {
return;
}
this.isAdded_ = true;
this.setPane_();
this.resizeListener_ = google.maps.event.addListener(this.getMap(),
'resize', this.resizeFunction_);
this.centerListener_ = google.maps.event.addListener(this.getMap(),
'center_changed', this.repositionFunction_);
this.resize_();
this.repositionCanvas_();
this.readyHandler && this.readyHandler();
};
/**
* @inheritDoc
*/
CanvasLayer.prototype.onRemove = function() {
if (!this.isAdded_) {
return;
}
this.isAdded_ = false;
this.topLeft_ = null;
// remove canvas and listeners for pan and resize from map
this.canvas.parentElement.removeChild(this.canvas);
if (this.centerListener_) {
google.maps.event.removeListener(this.centerListener_);
this.centerListener_ = null;
}
if (this.resizeListener_) {
google.maps.event.removeListener(this.resizeListener_);
this.resizeListener_ = null;
}
// cease canvas update callbacks
if (this.requestAnimationFrameId_) {
this.cancelAnimFrame_.call(window, this.requestAnimationFrameId_);
this.requestAnimationFrameId_ = null;
}
};
/**
* The internal callback for resize events that resizes the canvas to keep the
* map properly covered.
* @private
*/
CanvasLayer.prototype.resize_ = function() {
// TODO(bckenny): it's common to use a smaller canvas but use CSS to scale
// what is drawn by the browser to save on fill rate. Add an option to do
// this.
if (!this.isAdded_) {
return;
}
var map = this.getMap();
var width = map.getDiv().offsetWidth;
var height = map.getDiv().offsetHeight;
var oldWidth = this.canvas.width;
var oldHeight = this.canvas.height;
// resizing may allocate a new back buffer, so do so conservatively
if (oldWidth !== width || oldHeight !== height) {
this.canvas.width = width;
this.canvas.height = height;
this.canvas.style.width = width + 'px';
this.canvas.style.height = height + 'px';
this.needsResize_ = true;
this.scheduleUpdate();
}
};
/**
* @inheritDoc
*/
CanvasLayer.prototype.draw = function() {
this.repositionCanvas_();
};
/**
* Internal callback for map view changes. Since the Maps API moves the overlay
* along with the map, this function calculates the opposite translation to
* keep the canvas in place.
* @private
*/
CanvasLayer.prototype.repositionCanvas_ = function() {
// TODO(bckenny): *should* only be executed on RAF, but in current browsers
// this causes noticeable hitches in map and overlay relative
// positioning.
var bounds = this.getMap().getBounds();
this.topLeft_ = new google.maps.LatLng(bounds.getNorthEast().lat(),
bounds.getSouthWest().lng());
// canvas position relative to draggable map's conatainer depends on
// overlayView's projection, not the map's
var projection = this.getProjection();
var divTopLeft = projection.fromLatLngToDivPixel(this.topLeft_);
console.log(this.topLeft_.lng(), divTopLeft.x);
// when the zoom level is low, more than one map can be shown in the screen
// so the canvas should be attach to the map with more are in the screen
var mapSize = (1 << this.getMap().getZoom())*256;
if (Math.abs(divTopLeft.x) > mapSize) {
divTopLeft.x -= mapSize;
}
this.canvas.style[CanvasLayer.CSS_TRANSFORM_] = 'translate(' +
Math.round(divTopLeft.x) + 'px,' + Math.round(divTopLeft.y) + 'px)';
this.scheduleUpdate();
};
/**
* Internal callback that serves as main animation scheduler via
* requestAnimationFrame. Calls resize and update callbacks if set, and
* schedules the next frame if overlay is animated.
* @private
*/
CanvasLayer.prototype.update_ = function() {
this.requestAnimationFrameId_ = null;
if (!this.isAdded_) {
return;
}
if (this.isAnimated_) {
this.scheduleUpdate();
}
if (this.needsResize_ && this.resizeHandler_) {
this.needsResize_ = false;
this.resizeHandler_();
}
if (this.updateHandler_) {
this.updateHandler_();
}
};
/**
* A convenience method to get the current LatLng coordinate of the top left of
* the current view of the map.
* @return {google.maps.LatLng} The top left coordinate.
*/
CanvasLayer.prototype.getTopLeft = function() {
return this.topLeft_;
};
/**
* Schedule a requestAnimationFrame callback to updateHandler. If one is
* already scheduled, there is no effect.
*/
CanvasLayer.prototype.scheduleUpdate = function() {
if (this.isAdded_ && !this.requestAnimationFrameId_) {
this.requestAnimationFrameId_ =
this.requestAnimFrame_.call(window, this.requestUpdateFunction_);
}
};
}

View File

@ -0,0 +1,98 @@
/*
====================
canvas setup for drawing tiles
====================
*/
if(typeof(google) !== 'undefined' && typeof(google.maps) !== 'undefined') {
function CanvasTileLayer(canvas_setup, render) {
this.tileSize = new google.maps.Size(256, 256);
this.maxZoom = 19;
this.name = "Tile #s";
this.alt = "Canvas tile layer";
this.tiles = {};
this.canvas_setup = canvas_setup;
this.render = render;
if (!render) {
this.render = canvas_setup;
}
}
// create a tile with a canvas element
CanvasTileLayer.prototype.create_tile_canvas = function (coord, zoom, ownerDocument) {
// create canvas and reset style
var canvas = ownerDocument.createElement('canvas');
var hit_canvas = ownerDocument.createElement('canvas');
canvas.style.border = hit_canvas.style.border = "none";
canvas.style.margin = hit_canvas.style.margin = "0";
canvas.style.padding = hit_canvas.style.padding = "0";
// prepare canvas and context sizes
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = this.tileSize.width;
ctx.height = canvas.height = this.tileSize.height;
var hit_ctx = hit_canvas.getContext('2d');
hit_canvas.width = hit_ctx.width = this.tileSize.width;
hit_canvas.height = hit_ctx.height = this.tileSize.height;
//set unique id
var tile_id = coord.x + '_' + coord.y + '_' + zoom;
canvas.setAttribute('id', tile_id);
hit_canvas.setAttribute('id', tile_id);
if (tile_id in this.tiles)
delete this.tiles[tile_id];
this.tiles[tile_id] = {canvas:canvas, ctx:ctx, hit_canvas:hit_canvas, hit_ctx:hit_ctx, coord:coord, zoom:zoom, primitives:null};
// custom setup
//if (tile_id == '19295_24654_16'){
if (this.canvas_setup)
this.canvas_setup(this.tiles[tile_id], coord, zoom);
//}
return canvas;
}
CanvasTileLayer.prototype.each = function (callback) {
for (var t in this.tiles) {
var tile = this.tiles[t];
callback(tile);
}
}
CanvasTileLayer.prototype.recreate = function () {
for (var t in this.tiles) {
var tile = this.tiles[t];
this.canvas_setup(tile, tile.coord, tile.zoom);
}
};
CanvasTileLayer.prototype.redraw_tile = function (tile) {
this.render(tile, tile.coord, tile.zoom);
};
CanvasTileLayer.prototype.redraw = function () {
for (var t in this.tiles) {
var tile = this.tiles[t];
this.render(tile, tile.coord, tile.zoom);
}
};
// could be called directly...
CanvasTileLayer.prototype.getTile = function (coord, zoom, ownerDocument) {
return this.create_tile_canvas(coord, zoom, ownerDocument);
};
CanvasTileLayer.prototype.releaseTile = function (tile) {
var id = tile.getAttribute('id');
delete this.tiles[id];
};
}

View File

@ -0,0 +1,186 @@
(function(exports) {
if(typeof(google) === 'undefined' || typeof(google.maps) === 'undefined') return;
function GMapsTileLoader() {
}
GMapsTileLoader.prototype = {
_initTileLoader: function(map, projection) {
this._map = map;
this._projection = projection;
this._tiles = {};
this._tilesToLoad = 0;
this._updateTiles = this._updateTiles.bind(this);
google.maps.event.addListener(this._map, 'dragend', this._updateTiles);
google.maps.event.addListener(this._map, 'zoom_changed', this._updateTiles);
this.tileSize = 256;
this._updateTiles();
},
_removeTileLoader: function() {
//TODO: unbind events
//TODO: remove tiles
},
_removeTiles: function () {
for (var key in this._tiles) {
this._removeTile(key);
}
},
_updateTiles: function () {
if (!this._map) { return; }
var bounds = this._map.getBounds();
var zoom = this._map.getZoom();
var tileSize = this.tileSize;
var mzoom = (1 << zoom);
var topLeft = new google.maps.LatLng(
bounds.getNorthEast().lat(),
bounds.getSouthWest().lng()
);
var bottomRigth = new google.maps.LatLng(
bounds.getSouthWest().lat(),
bounds.getNorthEast().lng()
);
this._projection = this._map.getProjection();
var divTopLeft = this._projection.fromLatLngToPoint(topLeft);
var divBottomRight = this._projection.fromLatLngToPoint(bottomRigth);
var nwTilePoint = new google.maps.Point(
Math.floor(divTopLeft.x*mzoom / tileSize),
Math.floor(divTopLeft.y*mzoom / tileSize)),
seTilePoint = new google.maps.Point(
Math.floor(divBottomRight.x*mzoom / tileSize),
Math.floor(divBottomRight.y*mzoom / tileSize));
this._addTilesFromCenterOut(nwTilePoint, seTilePoint);
this._removeOtherTiles(nwTilePoint, seTilePoint);
},
_removeOtherTiles: function (nwTilePoint, seTilePoint) {
var kArr, x, y, key;
var zoom = this._map.getZoom();
for (key in this._tiles) {
if (this._tiles.hasOwnProperty(key)) {
kArr = key.split(':');
x = parseInt(kArr[0], 10);
y = parseInt(kArr[1], 10);
z = parseInt(kArr[2], 10);
// remove tile if it's out of bounds
if (z !== zoom || x < nwTilePoint.x || x > seTilePoint.x || y < nwTilePoint.y || y > seTilePoint.y) {
this._removeTile(key);
}
}
}
},
_removeTile: function (key) {
this.onTileRemoved && this.onTileRemoved(this._tiles[key]);
delete this._tiles[key];
},
_tileShouldBeLoaded: function (tilePoint) {
return !((tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom) in this._tiles);
},
_tileLoaded: function(tilePoint, tileData) {
this._tilesToLoad--;
this._tiles[tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom] = tileData;
if(this._tilesToLoad === 0) {
this.onTilesLoaded && this.onTilesLoaded();
}
},
getTilePos: function (tilePoint) {
var limit = (1 << this._map.getZoom());
// wrap tile
tilePoint = {
x: ((tilePoint.x % limit) + limit) % limit,
y: tilePoint.y
};
tilePoint = new google.maps.Point(
tilePoint.x * this.tileSize,
tilePoint.y * this.tileSize
);
var bounds = this._map.getBounds();
var topLeft = new google.maps.LatLng(
bounds.getNorthEast().lat(),
bounds.getSouthWest().lng()
);
var divTopLeft = this._map.getProjection().fromLatLngToPoint(topLeft);
zoom = (1 << this._map.getZoom());
divTopLeft.x = divTopLeft.x * zoom;
divTopLeft.y = divTopLeft.y * zoom;
return new google.maps.Point(
tilePoint.x - divTopLeft.x,
tilePoint.y - divTopLeft.y
);
},
_addTilesFromCenterOut: function (nwTilePoint, seTilePoint) {
var queue = [],
center = new google.maps.Point(
(nwTilePoint.x + seTilePoint.x) * 0.5,
(nwTilePoint.y + seTilePoint.y) * 0.5
),
zoom = this._map.getZoom();
var j, i, point;
for (j = nwTilePoint.y; j <= seTilePoint.y; j++) {
for (i = nwTilePoint.x; i <= seTilePoint.x; i++) {
point = new google.maps.Point (i, j);
point.zoom = zoom;
if (this._tileShouldBeLoaded(point)) {
queue.push(point);
}
}
}
var tilesToLoad = queue.length;
if (tilesToLoad === 0) { return; }
function distanceToCenterSq(point) {
var dx = point.x - center.x;
var dy = point.y - center.y;
return dx * dx + dy * dy;
}
// load tiles in order of their distance to center
queue.sort(function (a, b) {
return distanceToCenterSq(a) - distanceToCenterSq(b);
});
this._tilesToLoad += tilesToLoad;
if (this.onTileAdded) {
for (i = 0; i < tilesToLoad; i++) {
this.onTileAdded(queue[i]);
}
}
}
}
torque.GMapsTileLoader = GMapsTileLoader;
})(typeof exports === "undefined" ? this : exports);

259
lib/torque/gmaps/torque.js Normal file
View File

@ -0,0 +1,259 @@
(function(exports) {
if(typeof(google) === 'undefined' || typeof(google.maps) === 'undefined') return;
function GMapsTorqueLayer(options) {
var self = this;
this.key = 0;
this.cartocss = null;
this.ready = false;
this.options = _.extend({}, options);
_.defaults(this.options, {
provider: 'sql_api',
renderer: 'point',
resolution: 2,
steps: 100
});
this.animator = new torque.Animator(function(time) {
var k = time | 0;
if(self.key !== k) {
self.setKey(k);
}
}, this.options);
this.play = this.animator.start.bind(this.animator);
this.stop = this.animator.stop.bind(this.animator);
this.pause = this.animator.pause.bind(this.animator);
this.toggle = this.animator.toggle.bind(this.animator);
CanvasLayer.call(this, {
map: this.options.map,
//resizeHandler: this.redraw,
animate: false,
updateHandler: this.render,
readyHandler: this.initialize
});
}
/**
* torque layer
*/
GMapsTorqueLayer.prototype = _.extend({},
CanvasLayer.prototype,
torque.GMapsTileLoader.prototype,
torque.Event,
{
providers: {
'sql_api': torque.providers.json,
'url_template': torque.providers.jsonarray
},
renderers: {
'point': torque.renderer.Point,
'pixel': torque.renderer.Rectangle
},
initialize: function() {
var self = this;
this.onTileAdded = this.onTileAdded.bind(this);
this.options.ready = function() {
self.fire("change:bounds", {
bounds: self.provider.getBounds()
});
};
this.provider = new this.providers[this.options.provider](this.options);
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), this.options);
this._initTileLoader(this.options.map, this.getProjection());
if (this.cartocss) {
this.renderer.setCartoCSS(this.cartocss);
}
},
getCanvas: function() {
return this.canvas;
},
// for each tile shown on the map request the data
onTileAdded: function(t) {
var self = this;
this.provider.getTileData(t, t.zoom, function(tileData) {
self._tileLoaded(t, tileData);
self.redraw();
});
},
/**
* render the selectef key
* don't call this function directly, it's called by
* requestAnimationFrame. Use redraw to refresh it
*/
render: function() {
var t, tile, pos;
var canvas = this.canvas;
canvas.width = canvas.width;
var ctx = canvas.getContext('2d');
// renders only a "frame"
for(t in this._tiles) {
tile = this._tiles[t];
pos = this.getTilePos(tile.coord);
ctx.setTransform(1, 0, 0, 1, pos.x, pos.y);
this.renderer.renderTile(tile, this.key, pos.x, pos.y);
}
},
/**
* set key to be shown. If it's a single value
* it renders directly, if it's an array it renders
* accumulated
*/
setKey: function(key) {
this.key = key;
this.animator.step(key);
this.redraw();
this.fire('change:time', { time: this.getTime(), step: this.key });
},
/**
* helper function, does the same than ``setKey`` but only
* accepts scalars.
*/
setStep: function(time) {
if(time === undefined || time.length !== undefined) {
throw new Error("setTime only accept scalars");
}
this.setKey(time);
},
/**
* transform from animation step to Date object
* that contains the animation time
*
* ``step`` should be between 0 and ``steps - 1``
*/
stepToTime: function(step) {
if (!this.provider) return 0;
var times = this.provider.getKeySpan();
var time = times.start + (times.end - times.start)*(step/this.options.steps);
return new Date(time*1000);
},
/**
* returns the animation time defined by the data
* in the defined column. Date object
*/
getTime: function() {
return this.stepToTime(this.key);
},
/**
* set the cartocss for the current renderer
*/
setCartoCSS: function(cartocss) {
if (!this.renderer) {
this.cartocss = cartocss;
return this;
}
this.renderer.setCartoCSS(cartocss);
this.redraw();
return this;
},
redraw: function() {
this.scheduleUpdate();
}
});
function GMapsTiledTorqueLayer(options) {
this.options = _.extend({}, options);
CanvasTileLayer.call(this, this._loadTile.bind(this), this.drawTile.bind(this));
this.initialize(options);
}
GMapsTiledTorqueLayer.prototype = _.extend({}, CanvasTileLayer.prototype, {
providers: {
'sql_api': torque.providers.json,
'url_template': torque.providers.JsonArray
},
renderers: {
'point': torque.renderer.Point,
'pixel': torque.renderer.Rectangle
},
initialize: function(options) {
var self = this;
this.key = 0;
this.options.renderer = this.options.renderer || 'pixel';
this.options.provider = this.options.provider || 'sql_api';
this.provider = new this.providers[this.options.provider](options);
this.renderer = new this.renderers[this.options.renderer](null, options);
},
_tileLoaded: function(tile, tileData) {
tile.data = tileData;
this.drawTile(tile);
},
_loadTile: function(tile, coord, zoom) {
var self = this;
var limit = 1 << zoom;
// wrap tile
var wrappedCoord = {
x: ((coord.x % limit) + limit) % limit,
y: coord.y
};
this.provider.getTileData(wrappedCoord, zoom, function(tileData) {
self._tileLoaded(tile, tileData);
});
},
drawTile: function (tile) {
var canvas = tile.canvas;
if(!tile.data) return;
canvas.width = canvas.width;
this.renderer.setCanvas(canvas);
var accum = this.renderer.accumulate(tile.data, this.key);
this.renderer.renderTileAccum(accum, 0, 0);
},
setKey: function(key) {
this.key = key;
this.redraw();
},
/**
* set the cartocss for the current renderer
*/
setCartoCSS: function(cartocss) {
if (!this.renderer) throw new Error('renderer is not valid');
return this.renderer.setCartoCSS(cartocss);
}
});
exports.torque.GMapsTiledTorqueLayer = GMapsTiledTorqueLayer;
exports.torque.GMapsTorqueLayer = GMapsTorqueLayer;
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,125 @@
if(typeof(L) !== 'undefined') {
/**
* full canvas layer implementation for Leaflet
*/
L.CanvasLayer = L.Class.extend({
includes: [L.Mixin.Events, L.Mixin.TileLoader],
options: {
minZoom: 0,
maxZoom: 28,
tileSize: 256,
subdomains: 'abc',
errorTileUrl: '',
attribution: '',
zoomOffset: 0,
opacity: 1,
unloadInvisibleTiles: L.Browser.mobile,
updateWhenIdle: L.Browser.mobile,
tileLoader: false // installs tile loading events
},
initialize: function (options) {
var self = this;
//this.project = this._project.bind(this);
this.render = this.render.bind(this);
L.Util.setOptions(this, options);
this._canvas = document.createElement('canvas');
this._ctx = this._canvas.getContext('2d');
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
this.requestAnimationFrame = requestAnimationFrame;
},
onAdd: function (map) {
this._map = map;
this._staticPane = map._createPane('leaflet-tile-pane', map._container);
this._staticPane.appendChild(this._canvas);
map.on({
'viewreset': this._reset
//'move': this._render
}, this);
map.on('move', this._render, this);//function(){ console.log("a"); }, this);
if(this.options.tileLoader) {
this._initTileLoader();
}
this._reset();
},
getCanvas: function() {
return this._canvas;
},
draw: function() {
return this._reset();
},
onRemove: function (map) {
map._container.removeChild(this._staticPane);
map.off({
'viewreset': this._reset,
'move': this._render
}, this);
},
addTo: function (map) {
map.addLayer(this);
return this;
},
setOpacity: function (opacity) {
this.options.opacity = opacity;
this._updateOpacity();
return this;
},
bringToFront: function () {
return this;
},
bringToBack: function () {
return this;
},
_reset: function () {
var size = this._map.getSize();
this._canvas.width = size.x;
this._canvas.height = size.y;
this.onResize();
this._render();
},
/*
_project: function(x) {
var point = this._map.latLngToLayerPoint(new L.LatLng(x[1], x[0]));
return [point.x, point.y];
},
*/
_updateOpacity: function () { },
_render: function() {
this.requestAnimationFrame.call(window, this.render);
},
redraw: function() {
this._render();
},
onResize: function() {
},
render: function() {
throw new Error('render function should be implemented');
}
});
} //L defined

View File

@ -0,0 +1,133 @@
if(typeof(L) !== 'undefined') {
L.Mixin.TileLoader = {
_initTileLoader: function() {
this._tiles = {}
this._tilesToLoad = 0;
this._map.on({
'moveend': this._updateTiles
}, this);
this._updateTiles();
},
_removeTileLoader: function() {
map.off({
'moveend': this._updateTiles
}, this);
this._removeTiles();
},
_updateTiles: function () {
if (!this._map) { return; }
var bounds = this._map.getPixelBounds(),
zoom = this._map.getZoom(),
tileSize = this.options.tileSize;
if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
return;
}
var nwTilePoint = new L.Point(
Math.floor(bounds.min.x / tileSize),
Math.floor(bounds.min.y / tileSize)),
seTilePoint = new L.Point(
Math.floor(bounds.max.x / tileSize),
Math.floor(bounds.max.y / tileSize)),
tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
this._addTilesFromCenterOut(tileBounds);
this._removeOtherTiles(tileBounds);
},
_removeTiles: function (bounds) {
for (var key in this._tiles) {
this._removeTile(key);
}
},
_removeOtherTiles: function (bounds) {
var kArr, x, y, z, key;
var zoom = this._map.getZoom();
for (key in this._tiles) {
if (this._tiles.hasOwnProperty(key)) {
kArr = key.split(':');
x = parseInt(kArr[0], 10);
y = parseInt(kArr[1], 10);
z = parseInt(kArr[2], 10);
// remove tile if it's out of bounds
if (zoom !== z || x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
this._removeTile(key);
}
}
}
},
_removeTile: function (key) {
this.fire('tileRemoved', this._tiles[key]);
delete this._tiles[key];
},
_tileShouldBeLoaded: function (tilePoint) {
return !((tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom) in this._tiles);
},
_tileLoaded: function(tilePoint, tileData) {
this._tilesToLoad--;
this._tiles[tilePoint.x + ':' + tilePoint.y + ':' + tilePoint.zoom] = tileData;
if(this._tilesToLoad === 0) {
this.fire("tilesLoaded");
}
},
getTilePos: function (tilePoint) {
tilePoint = new L.Point(tilePoint.x, tilePoint.y);
var origin = this._map._getNewTopLeftPoint(this._map.getCenter()),
tileSize = this.options.tileSize;
return tilePoint.multiplyBy(tileSize).subtract(origin);
},
_addTilesFromCenterOut: function (bounds) {
var queue = [],
center = bounds.getCenter(),
zoom = this._map.getZoom();
var j, i, point;
for (j = bounds.min.y; j <= bounds.max.y; j++) {
for (i = bounds.min.x; i <= bounds.max.x; i++) {
point = new L.Point(i, j);
point.zoom = zoom;
if (this._tileShouldBeLoaded(point)) {
queue.push(point);
}
}
}
var tilesToLoad = queue.length;
if (tilesToLoad === 0) { return; }
// load tiles in order of their distance to center
queue.sort(function (a, b) {
return a.distanceTo(center) - b.distanceTo(center);
});
this._tilesToLoad += tilesToLoad;
for (i = 0; i < tilesToLoad; i++) {
this.fire('tileAdded', queue[i]);
}
}
}
} //L defined

View File

@ -0,0 +1,220 @@
if(typeof(L) !== 'undefined') {
/**
* torque layer
*/
L.TorqueLayer = L.CanvasLayer.extend({
providers: {
'sql_api': torque.providers.json,
'url_template': torque.providers.jsonarray
},
renderers: {
'point': torque.renderer.Point,
'pixel': torque.renderer.Rectangle
},
initialize: function(options) {
var self = this;
options.tileLoader = true;
this.key = 0;
options.resolution = options.resolution || 2;
options.steps = options.steps || 100;
this.animator = new torque.Animator(function(time) {
var k = time | 0;
if(self.key !== k) {
self.setKey(k);
}
}, options);
this.play = this.animator.start.bind(this.animator);
this.stop = this.animator.stop.bind(this.animator);
this.pause = this.animator.pause.bind(this.animator);
this.toggle = this.animator.toggle.bind(this.animator);
L.CanvasLayer.prototype.initialize.call(this, options);
this.options.renderer = this.options.renderer || 'point';
this.options.provider = this.options.provider || 'sql_api';
this.provider = new this.providers[this.options.provider](options);
this.renderer = new this.renderers[this.options.renderer](this.getCanvas(), options);
// for each tile shown on the map request the data
this.on('tileAdded', function(t) {
var tileData = this.provider.getTileData(t, t.zoom, function(tileData) {
self._tileLoaded(t, tileData);
self.redraw();
});
}, this);
},
/**
* render the selectef key
* don't call this function directly, it's called by
* requestAnimationFrame. Use redraw to refresh it
*/
render: function() {
var t, tile, pos;
var canvas = this.getCanvas();
canvas.width = canvas.width;
var ctx = canvas.getContext('2d');
for(t in this._tiles) {
tile = this._tiles[t];
pos = this.getTilePos(tile.coord);
ctx.setTransform(1, 0, 0, 1, pos.x, pos.y);
this.renderer.renderTile(tile, this.key, pos.x, pos.y);
}
},
/**
* set key to be shown. If it's a single value
* it renders directly, if it's an array it renders
* accumulated
*/
setKey: function(key) {
this.key = key;
this.animator.step(key);
this.redraw();
this.fire('change:time', { time: this.getTime(), step: this.key });
},
/**
* helper function, does the same than ``setKey`` but only
* accepts scalars.
*/
setStep: function(time) {
if(time === undefined || time.length !== undefined) {
throw new Error("setTime only accept scalars");
}
this.setKey(time);
},
/**
* transform from animation step to Date object
* that contains the animation time
*
* ``step`` should be between 0 and ``steps - 1``
*/
stepToTime: function(step) {
var times = this.provider.getKeySpan();
var time = times.start + (times.end - times.start)*(step/this.options.steps);
return new Date(time*1000);
},
/**
* returns the animation time defined by the data
* in the defined column. Date object
*/
getTime: function() {
return this.stepToTime(this.key);
},
/**
* returns an object with the start and end times
*/
getTimeSpan: function() {
var times = this.provider.getKeySpan();
},
/**
* set the cartocss for the current renderer
*/
setCartoCSS: function(cartocss) {
if (!this.renderer) throw new Error('renderer is not valid');
this.renderer.setCartoCSS(cartocss);
this.redraw();
return this;
}
});
//_.extend(L.TorqueLayer.prototype, torque.Event);
L.TiledTorqueLayer = L.TileLayer.Canvas.extend({
providers: {
'sql_api': torque.providers.json,
'url_template': torque.providers.JsonArray
},
renderers: {
'point': torque.renderer.Point,
'pixel': torque.renderer.Rectangle
},
initialize: function(options) {
var self = this;
this.key = 0;
options.async = true;
L.TileLayer.Canvas.prototype.initialize.call(this, options);
this.options.renderer = this.options.renderer || 'pixel';
this.options.provider = this.options.provider || 'sql_api';
this.provider = new this.providers[this.options.provider](options);
this.renderer = new this.renderers[this.options.renderer](null, options);
},
_tileLoaded: function(tile, tilePoint, tileData) {
if(this._tiles[tilePoint.x + ':' + tilePoint.y] !== undefined) {
this._tiles[tilePoint.x + ':' + tilePoint.y].data = tileData;
this.drawTile(tile);
}
L.TileLayer.Canvas.prototype._tileLoaded.call(this);
},
redraw: function() {
for (var i in this._tiles) {
this._redrawTile(this._tiles[i]);
}
},
_loadTile: function(tile, tilePoint) {
var self = this;
L.TileLayer.Canvas.prototype._loadTile.apply(this, arguments);
// get the data from adjusted point but render in the right canvas
var adjusted = tilePoint.clone()
this._adjustTilePoint(adjusted);
this.provider.getTileData(adjusted, this._map.getZoom(), function(tileData) {
self._tileLoaded(tile, tilePoint, tileData);
L.DomUtil.addClass(tile, 'leaflet-tile-loaded');
});
},
drawTile: function (tile) {
var canvas = tile;
if(!tile.data) return;
canvas.width = canvas.width;
this.renderer.setCanvas(canvas);
var accum = this.renderer.accumulate(tile.data, this.key);
this.renderer.renderTileAccum(accum, 0, 0);
},
setKey: function(key) {
this.key = key;
this.redraw();
},
/**
* set the cartocss for the current renderer
*/
setCartoCSS: function(cartocss) {
if (!this.renderer) throw new Error('renderer is not valid');
return this.renderer.setCartoCSS(cartocss);
}
});
} //L defined

38
lib/torque/math.js Normal file
View File

@ -0,0 +1,38 @@
(function(exports) {
exports.torque = exports.torque || {};
function clamp(a, b) {
return function(t) {
return Math.max(Math.min(t, b), a);
};
}
function invLinear(a, b) {
var c = clamp(0, 1.0);
return function(t) {
return c((t - a)/(b - a));
};
}
function linear(a, b) {
var c = clamp(a, b);
function _linear(t) {
return c(a*(1.0 - t) + t*b);
}
_linear.invert = function() {
return invLinear(a, b);
};
return _linear;
}
exports.torque.math = {
clamp: clamp,
linear: linear,
invLinear: invLinear
};
})(typeof exports === "undefined" ? this : exports);

146
lib/torque/profiler.js Normal file
View File

@ -0,0 +1,146 @@
/*
# metrics profiler
## timing
```
var timer = Profiler.metric('resource:load')
time.start();
...
time.end();
```
## counters
```
var counter = Profiler.metric('requests')
counter.inc(); // 1
counter.inc(10); // 11
counter.dec() // 10
counter.dec(10) // 0
```
## Calls per second
```
var fps = Profiler.metric('fps')
function render() {
fps.mark();
}
```
*/
(function(exports) {
var MAX_HISTORY = 1024;
function Profiler() {}
Profiler.metrics = {};
Profiler.get = function(name) {
return Profiler.metrics[name] || {
max: 0,
min: 10000000,
avg: 0,
total: 0,
count: 0,
history: typeof(Float32Array) !== 'undefined' ? new Float32Array(MAX_HISTORY) : []
};
};
Profiler.new_value = function (name, value) {
var t = Profiler.metrics[name] = Profiler.get(name);
t.max = Math.max(t.max, value);
t.min = Math.min(t.min, value);
t.total += value;
++t.count;
t.avg = t.total / t.count;
t.history[t.count%MAX_HISTORY] = value;
};
Profiler.print_stats = function () {
for (k in Profiler.metrics) {
var t = Profiler.metrics[k];
console.log(" === " + k + " === ");
console.log(" max: " + t.max);
console.log(" min: " + t.min);
console.log(" avg: " + t.avg);
console.log(" count: " + t.count);
console.log(" total: " + t.total);
}
};
function Metric(name) {
this.t0 = null;
this.name = name;
this.count = 0;
}
Metric.prototype = {
//
// start a time measurement
//
start: function() {
this.t0 = +new Date();
return this;
},
// elapsed time since start was called
_elapsed: function() {
return +new Date() - this.t0;
},
//
// finish a time measurement and register it
// ``start`` should be called first, if not this
// function does not take effect
//
end: function() {
if (this.t0 !== null) {
Profiler.new_value(this.name, this._elapsed());
this.t0 = null;
}
},
//
// increments the value
// qty: how many, default = 1
//
inc: function(qty) {
qty = qty === undefined ? 1: qty;
Profiler.new_value(this.name, Profiler.get(this.name).count + (qty ? qty: 0));
},
//
// decrements the value
// qty: how many, default = 1
//
dec: function(qty) {
qty = qty === undefined ? 1: qty;
this.inc(-qty);
},
//
// measures how many times per second this function is called
//
mark: function() {
++this.count;
if(this.t0 === null) {
this.start();
return;
}
var elapsed = this._elapsed();
if(elapsed > 1) {
Profiler.new_value(this.name, this.count);
this.count = 0;
this.start();
}
}
};
Profiler.metric = function(name) {
return new Metric(name);
};
exports.Profiler = Profiler;
})(typeof exports === "undefined" ? this : exports);

272
lib/torque/provider.json.js Normal file
View File

@ -0,0 +1,272 @@
(function(exports) {
var torque = exports.torque = exports.torque || {};
var providers = exports.torque.providers = exports.torque.providers || {};
var Uint8Array = torque.types.Uint8Array;
var Int32Array = torque.types.Int32Array;
var Uint32Array = torque.types.Uint32Array;
// format('hello, {0}', 'rambo') -> "hello, rambo"
function format(str) {
for(var i = 1; i < arguments.length; ++i) {
var attrs = arguments[i];
for(var attr in attrs) {
str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
}
}
return str;
}
var json = function (options) {
this._ready = false;
this._tileQueue = [];
this.options = options;
this.options.is_time = this.options.is_time === undefined ? true: this.options.is_time;
// check options
if (options.resolution === undefined ) throw new Error("resolution should be provided");
if (options.steps === undefined ) throw new Error("steps should be provided");
if(options.start === undefined) {
this._fetchKeySpan();
} else {
this._setReady(true);
}
};
json.prototype = {
/**
* return the torque tile encoded in an efficient javascript
* structure:
* {
* x:Uint8Array x coordinates in tile reference system, normally from 0-255
* y:Uint8Array y coordinates in tile reference system
* Index: Array index to the properties
* }
*/
proccessTile: function(rows, coord, zoom) {
var r;
var x = new Uint8Array(rows.length);
var y = new Uint8Array(rows.length);
// count number of dates
var dates = 0;
var maxDateSlots = 0;
for (r = 0; r < rows.length; ++r) {
var row = rows[r];
if(this.options.cumulative) {
for (var s = 1; s < row.vals__uint8.length; ++s) {
row.vals__uint8[s] += row.vals__uint8[s - 1];
}
}
dates += row.dates__uint16.length;
for(var d = 0; d < row.dates__uint16.length; ++d) {
maxDateSlots = Math.max(maxDateSlots, row.dates__uint16[d]);
}
}
// reserve memory for all the dates
var timeIndex = new Int32Array(maxDateSlots + 1); //index-size
var timeCount = new Int32Array(maxDateSlots + 1);
var renderData = new (this.options.valueDataType || Uint8Array)(dates);
var renderDataPos = new Uint32Array(dates);
var rowsPerSlot = {};
// precache pixel positions
for (var r = 0; r < rows.length; ++r) {
var row = rows[r];
x[r] = row.x__uint8 * this.options.resolution;
y[r] = row.y__uint8 * this.options.resolution;
var dates = row.dates__uint16;
var vals = row.vals__uint8;
for (var j = 0, len = dates.length; j < len; ++j) {
var rr = rowsPerSlot[dates[j]] || (rowsPerSlot[dates[j]] = []);
rr.push([r, vals[j]]);
}
}
// for each timeslot search active buckets
var renderDataIndex = 0;
var timeSlotIndex = 0;
var i = 0;
for(var i = 0; i <= maxDateSlots; ++i) {
var c = 0;
var slotRows = rowsPerSlot[i]
if(slotRows) {
for (var r = 0; r < slotRows.length; ++r) {
var rr = slotRows[r];
++c;
renderDataPos[renderDataIndex] = rr[0]
renderData[renderDataIndex] = rr[1];
++renderDataIndex;
}
}
timeIndex[i] = timeSlotIndex;
timeCount[i] = c;
timeSlotIndex += c;
}
return {
x: x,
y: y,
coord: {
x: coord.x,
y: coord.y,
z: zoom
},
timeCount: timeCount,
timeIndex: timeIndex,
renderDataPos: renderDataPos,
renderData: renderData
};
},
url: function() {
return this.options.url || 'http://' + this.options.user + '.cartodb.com/api/v2/sql';
},
// execute actual query
sql: function(sql, callback, options) {
options = options || {};
torque.net.get(this.url() + "?q=" + encodeURIComponent(sql), function (data) {
if(options.parseJSON) {
data = JSON.parse(data.responseText);
}
callback(data);
});
},
getTileData: function(coord, zoom, callback) {
if(!this._ready) {
this._tileQueue.push([coord, zoom, callback]);
} else {
this._getTileData(coord, zoom, callback);
}
},
_setReady: function(ready) {
this._ready = true;
this._processQueue();
this.options.ready && this.options.ready();
},
_processQueue: function() {
var item;
while (item = this._tileQueue.pop()) {
this._getTileData.apply(this, item);
}
},
/**
* `coord` object like {x : tilex, y: tiley }
* `zoom` quadtree zoom level
*/
_getTileData: function(coord, zoom, callback) {
this.table = this.options.table;
var numTiles = 1 << zoom;
var column_conv = this.options.column;
if(this.options.is_time) {
column_conv = format("date_part('epoch', {column})", this.options);
}
var sql = "" +
"WITH " +
"par AS (" +
" SELECT CDB_XYZ_Resolution({zoom})*{resolution} as res" +
", CDB_XYZ_Extent({x}, {y}, {zoom}) as ext " +
")," +
"cte AS ( "+
" SELECT ST_SnapToGrid(i.the_geom_webmercator, p.res) g" +
", {countby} c" +
", floor(({column_conv} - {start})/{step}) d" +
" FROM {table} i, par p " +
" WHERE i.the_geom_webmercator && p.ext " +
" GROUP BY g, d" +
") " +
"" +
"SELECT least((st_x(g)-st_xmin(p.ext))/p.res, 255) x__uint8, " +
" least((st_y(g)-st_ymin(p.ext))/p.res, 255) y__uint8," +
" array_agg(c) vals__uint8," +
" array_agg(d) dates__uint16" +
" FROM cte, par p GROUP BY x__uint8, y__uint8";
var query = format(sql, this.options, {
zoom: zoom,
x: coord.x,
y: coord.y,
column_conv: column_conv
});
var self = this;
this.sql(query, function (data) {
var rows = JSON.parse(data.responseText).rows;
callback(self.proccessTile(rows, coord, zoom));
});
},
getKeySpan: function() {
return {
start: this.options.start,
end: this.options.end,
step: this.options.step,
steps: this.options.steps
};
},
getBounds: function() {
return this.options.bounds;
},
//
// the data range could be set by the user though ``start``
// option. It can be fecthed from the table when the start
// is not specified.
//
_fetchKeySpan: function() {
var max_col, min_col, max_tmpl, min_tmpl;
if (this.options.is_time){
max_tmpl = "date_part('epoch', max({column}))";
min_tmpl = "date_part('epoch', min({column}))";
} else {
max_tmpl = "max({column})";
min_tmpl = "min({column})";
}
max_col = format(max_tmpl, { column: this.options.column });
min_col = format(min_tmpl, { column: this.options.column });
var sql = format("SELECT st_xmax(st_envelope(st_collect(the_geom))) xmax,st_ymax(st_envelope(st_collect(the_geom))) ymax, st_xmin(st_envelope(st_collect(the_geom))) xmin, st_ymin(st_envelope(st_collect(the_geom))) ymin, {max_col} max, {min_col} min FROM {table}", {
max_col: max_col,
min_col: min_col,
table: this.options.table
});
var self = this;
this.sql(sql, function(data) {
//TODO: manage bounds
data = data.rows[0];
self.options.start = data.min;
self.options.end = data.max;
self.options.step = (data.max - data.min)/self.options.steps;
self.options.bounds = [
[data.ymin, data.xmin],
[data.ymax, data.xmax]
];
self._setReady(true);
}, { parseJSON: true });
}
};
torque.providers.json = json;
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,234 @@
(function(exports) {
var torque = exports.torque = exports.torque || {};
var providers = exports.torque.providers = exports.torque.providers || {};
var Uint8Array = torque.types.Uint8Array;
var Int32Array = torque.types.Int32Array;
var Uint32Array = torque.types.Uint32Array;
// format('hello, {0}', 'rambo') -> "hello, rambo"
function format(str, attrs) {
for(var i = 1; i < arguments.length; ++i) {
var attrs = arguments[i];
for(var attr in attrs) {
str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
}
}
return str;
}
var json = function (options) {
// check options
this.options = options;
};
json.prototype = {
//
// return the data aggregated by key:
// {
// key0: 12,
// key1: 32
// key2: 25
// }
//
aggregateByKey: function(rows) {
function getKeys(row) {
var HEADER_SIZE = 3;
var valuesCount = row.data[2];
var keys = {};
for (var s = 0; s < valuesCount; ++s) {
keys[row.data[HEADER_SIZE + s]] = row.data[HEADER_SIZE + valuesCount + s];
}
return keys;
}
var keys = {};
for (r = 0; r < rows.length; ++r) {
var rowKeys = getKeys(rows[r]);
for(var k in rowKeys) {
keys[k] = keys[k] || 0;
keys[k] += rowKeys[k];
}
}
return keys;
},
/**
*
*/
proccessTile: function(rows, coord, zoom) {
var r;
var x = new Uint8Array(rows.length);
var y = new Uint8Array(rows.length);
var self = this;
// decode into a javascript strcuture the array
function decode_row(row) {
var HEADER_SIZE = 3;
var o = {
x: row.data[0] * self.options.resolution,
y: row.data[1] * self.options.resolution,
valuesCount: row.data[2],
times: [],
values: [],
};
for (var s = 0; s < o.valuesCount; ++s) {
o.times.push(row.data[HEADER_SIZE + s]);
o.values.push(row.data[HEADER_SIZE + o.valuesCount + s]);
}
if(self.options.cumulative) {
for (var s = 1; s < o.valuesCount; ++s) {
o.values[s] += o.values[s - 1];
}
}
return o
}
// decode all the rows
for (r = 0; r < rows.length; ++r) {
rows[r] = decode_row(rows[r]);
}
// count number of dates
var dates = 0;
var maxDateSlots = 0;
for (r = 0; r < rows.length; ++r) {
var row = rows[r];
dates += row.times.length;
for(var d = 0; d < row.times.length; ++d) {
maxDateSlots = Math.max(maxDateSlots, row.times[d]);
}
}
// reserve memory for all the dates
var timeIndex = new Int32Array(maxDateSlots + 1); //index-size
var timeCount = new Int32Array(maxDateSlots + 1);
var renderData = new (this.options.valueDataType || Uint8Array)(dates);
var renderDataPos = new Uint32Array(dates);
var rowsPerSlot = {};
// precache pixel positions
for (var r = 0; r < rows.length; ++r) {
var row = rows[r];
x[r] = row.x;
y[r] = row.y;
var dates = row.times;
var vals = row.values;
for (var j = 0, len = dates.length; j < len; ++j) {
var rr = rowsPerSlot[dates[j]] || (rowsPerSlot[dates[j]] = []);
rr.push([r, vals[j]]);
}
}
// for each timeslot search active buckets
var renderDataIndex = 0;
var timeSlotIndex = 0;
var i = 0;
for(var i = 0; i <= maxDateSlots; ++i) {
var c = 0;
var slotRows = rowsPerSlot[i]
if(slotRows) {
for (var r = 0; r < slotRows.length; ++r) {
var rr = slotRows[r];
++c;
renderDataPos[renderDataIndex] = rr[0]
renderData[renderDataIndex] = rr[1];
++renderDataIndex;
}
}
timeIndex[i] = timeSlotIndex;
timeCount[i] = c;
timeSlotIndex += c;
}
return {
x: x,
y: y,
coord: {
x: coord.x,
y: coord.y,
z: zoom
},
timeCount: timeCount,
timeIndex: timeIndex,
renderDataPos: renderDataPos,
renderData: renderData
};
},
url: function() {
return this.options.url;
},
tileUrl: function(coord, zoom) {
var template = this.url();
var s = (this.options.subdomains || 'abcd')[(coord.x + coord.y + zoom) % 4];
return template
.replace('{x}', coord.x)
.replace('{y}', coord.y)
.replace('{z}', zoom)
.replace('{s}', s);
},
getTile: function(coord, zoom, callback) {
var template = this.tileUrl(coord, zoom);
var self = this;
var fetchTime = Profiler.metric('jsonarray:fetch time');
fetchTime.start();
torque.net.get(template, function (data) {
fetchTime.end();
if(data) {
data = JSON.parse(data.responseText);
}
callback(data);
});
},
/**
* `coord` object like {x : tilex, y: tiley }
* `zoom` quadtree zoom level
*/
getTileData: function(coord, zoom, callback) {
var template = this.tileUrl(coord, zoom);
var self = this;
var fetchTime = Profiler.metric('jsonarray:fetch time');
fetchTime.start();
torque.net.get(template, function (data) {
fetchTime.end();
var processed = null;
var processingTime = Profiler.metric('jsonarray:processing time');
var parsingTime = Profiler.metric('jsonarray:parsing time');
try {
processingTime.start();
parsingTime.start();
var rows = JSON.parse(data.responseText || data.response).rows;
parsingTime.end();
processed = self.proccessTile(rows, coord, zoom);
processingTime.end();
} catch(e) {
console.error("problem parsing JSON on ", coord, zoom);
}
callback(processed);
});
}
};
torque.providers.JsonArray = json
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,47 @@
(function(exports) {
exports.torque = exports.torque || {};
var TAU = Math.PI*2;
function renderPoint(ctx, st) {
ctx.fillStyle = st.fillStyle;
ctx.strokStyle = st.strokStyle;
var pixel_size = st['point-radius']
// render a circle
ctx.beginPath();
ctx.arc(0, 0, pixel_size, 0, TAU, true, true);
ctx.closePath();
if(st.fillStyle) {
if(st.fillOpacity) {
ctx.globalAlpha = st.fillOpacity;
}
ctx.fill();
}
ctx.globalAlpha = 1.0;
if(st.strokeStyle) {
if(st.strokeOpacity) {
ctx.globalAlpha = st.strokeOpacity;
}
if(st.lineWidth) {
ctx.lineWidth = st.lineWidth;
}
ctx.strokeStyle = st.strokeStyle;
ctx.stroke();
}
}
function renderSprite(ctx, st) {
var img = st['point-file'] || st['marker-file'];
var ratio = img.height/img.width;
var w = st['point-radius'] || img.width;
var h = st['point-radius'] || st['marker-height'] || w*ratio;
ctx.drawImage(img, 0, 0, w, h);
}
exports.torque.cartocss = exports.torque.cartocss|| {};
exports.torque.cartocss = {
renderPoint: renderPoint,
renderSprite: renderSprite
};
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,138 @@
(function(exports) {
exports.torque = exports.torque || {};
exports.torque.renderer = exports.torque.renderer || {};
var TAU = Math.PI * 2;
var DEFAULT_CARTOCSS = [
'#layer {',
' marker-fill: #662506;',
' marker-width: 4;',
' [value > 1] { marker-fill: #FEE391; }',
' [value > 2] { marker-fill: #FEC44F; }',
' [value > 3] { marker-fill: #FE9929; }',
' [value > 4] { marker-fill: #EC7014; }',
' [value > 5] { marker-fill: #CC4C02; }',
' [value > 6] { marker-fill: #993404; }',
' [value > 7] { marker-fill: #662506; }',
'}'
].join('\n');
//
// this renderer just render points depending of the value
//
function PointRenderer(canvas, options) {
if (!canvas) {
throw new Error("canvas can't be undefined");
}
this.options = options;
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
this._sprites = []; // sprites per layer
this._shader = null;
this._trailsShader = null;
//carto.tree.Reference.set(torque['torque-reference']);
this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
}
PointRenderer.prototype = {
setCanvas: function(canvas) {
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
},
//
// sets the cartocss style to render stuff
//
setCartoCSS: function(cartocss) {
// clean sprites
this._sprites = [];
this._cartoCssStyle = new carto.RendererJS().render(cartocss);
},
//
// generate sprite based on cartocss style
//
generateSprite: function(shader, value, shaderVars) {
var prof = Profiler.metric('PointRenderer:generateSprite').start();
var st = shader.getStyle('canvas-2d', {
value: value
}, shaderVars);
var pointSize = st['point-radius'];
if(!pointSize) {
throw new Error("marker-width property should be set");
}
var canvasSize = pointSize*2;
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = canvasSize;
ctx.height = canvas.height = canvasSize;
ctx.translate(pointSize, pointSize);
if(st['point-file'] || st['marker-fil']) {
torque.cartocss.renderSprite(ctx, st);
} else {
torque.cartocss.renderPoint(ctx, st);
}
prof.end();
return canvas;
},
//
// renders all the layers (and frames for each layer) from cartocss
//
renderTile: function(tile, key) {
var layers = this._cartoCssStyle.getLayers();
for(var i = 0, n = layers.length; i < n; ++i ) {
var layer = layers[i];
var sprites = this._sprites[i] || (this._sprites[i] = {});
// frames for each layer
for(var fr = 0; fr < layer.frames().length; ++fr) {
var frame = layer.frames()[fr];
var fr_sprites = sprites[frame] || (sprites[frame] = []);
this._renderTile(tile, key - frame, frame, fr_sprites, layer);
}
}
},
//
// renders a tile in the canvas for key defined in
// the torque tile
//
_renderTile: function(tile, key, frame_offset, sprites, shader, shaderVars) {
if(!this._canvas) return;
var prof = Profiler.metric('PointRenderer:renderTile').start();
var ctx = this._ctx;
//var res = 1;//this.options.resolution;
var activePixels = tile.timeCount[key];
if(this.options.blendmode) {
ctx.globalCompositeOperation = this.options.blendmode;
}
if(activePixels) {
var pixelIndex = tile.timeIndex[key];
for(var p = 0; p < activePixels; ++p) {
var posIdx = tile.renderDataPos[pixelIndex + p];
var c = tile.renderData[pixelIndex + p];
if(c) {
var sp = sprites[c];
if(!sp) {
sp = sprites[c] = this.generateSprite(shader, c, _.extend({ zoom: tile.zoom, 'frame-offset': frame_offset }, shaderVars));
}
//var x = tile.x[posIdx]*res - (sp.width >> 1);
//var y = (256 - res - res*tile.y[posIdx]) - (sp.height >> 1);
var x = tile.x[posIdx]- (sp.width >> 1);
var y = (256 - 1 - tile.y[posIdx]) - (sp.height >> 1);
ctx.drawImage(sp, x, y);
}
}
}
prof.end();
}
};
// exports public api
exports.torque.renderer.Point = PointRenderer;
})(typeof exports === "undefined" ? this : exports);

View File

@ -0,0 +1,163 @@
(function(exports) {
exports.torque = exports.torque || {};
exports.torque.renderer = exports.torque.renderer || {};
var DEFAULT_CARTOCSS = [
'#layer {',
' polygon-fill: #FFFF00;',
' [value > 10] { polygon-fill: #FFFF00; }',
' [value > 100] { polygon-fill: #FFCC00; }',
' [value > 1000] { polygon-fill: #FE9929; }',
' [value > 10000] { polygon-fill: #FF6600; }',
' [value > 100000] { polygon-fill: #FF3300; }',
'}'
].join('\n');
var TAU = Math.PI * 2;
//
// this renderer just render points depending of the value
//
function RectanbleRenderer(canvas, options) {
this.options = options;
carto.tree.Reference.set(torque['torque-reference']);
this.setCanvas(canvas);
this.setCartoCSS(this.options.cartocss || DEFAULT_CARTOCSS);
}
RectanbleRenderer.prototype = {
//
// sets the cartocss style to render stuff
//
setCartoCSS: function(cartocss) {
this._cartoCssStyle = new carto.RendererJS().render(cartocss);
if(this._cartoCssStyle.getLayers().length > 1) {
throw new Error("only one CartoCSS layer is supported");
}
this._shader = this._cartoCssStyle.getLayers()[0].shader;
},
setCanvas: function(canvas) {
if(!canvas) return;
this._canvas = canvas;
this._ctx = canvas.getContext('2d');
},
accumulate: function(tile, keys) {
var prof = Profiler.metric('RectangleRender:accumulate').start();
var x, y, posIdx, p, k, key, activePixels, pixelIndex;
var res = this.options.resolution;
var s = 256/res;
var accum = new Float32Array(s*s);
if(typeof(keys) !== 'object') {
keys = [keys];
}
for(k = 0; k < keys.length; ++k) {
key = keys[k];
activePixels = tile.timeCount[key];
if(activePixels) {
pixelIndex = tile.timeIndex[key];
for(p = 0; p < activePixels; ++p) {
posIdx = tile.renderDataPos[pixelIndex + p];
x = tile.x[posIdx]/res;
y = tile.y[posIdx]/res;
accum[x*s + y] += tile.renderData[pixelIndex + p];
}
}
}
prof.end();
return accum;
},
renderTileAccum: function(accum, px, py) {
var prof = Profiler.metric('RectangleRender:renderTileAccum').start();
var color, x, y, alpha;
var res = this.options.resolution;
var ctx = this._ctx;
var s = (256/res) | 0;
var s2 = s*s;
var colors = this._colors;
if(this.options.blendmode) {
ctx.globalCompositeOperation = this.options.blendmode;
}
var polygon_alpha = this._shader['polygon-opacity'] || function() { return 1.0; };
for(var i = 0; i < s2; ++i) {
var xy = i;
var value = accum[i];
if(value) {
x = (xy/s) | 0;
y = xy % s;
// by-pass the style generation for improving performance
color = this._shader['polygon-fill']({ value: value }, { zoom: 0 });
ctx.fillStyle = color;
//TODO: each function should have a default value for each
//property defined in the cartocss
alpha = polygon_alpha({ value: value }, { zoom: 0 });
if(alpha === null) {
alpha = 1.0;
}
ctx.globalAlpha = alpha;
ctx.fillRect(x * res, 256 - res - y * res, res, res);
}
}
prof.end();
},
//
// renders a tile in the canvas for key defined in
// the torque tile
//
renderTile: function(tile, key, px, py) {
if(!this._canvas) return;
var res = this.options.resolution;
//var prof = Profiler.get('render').start();
var ctx = this._ctx;
var colors = this._colors;
var activepixels = tile.timeCount[key];
if(activepixels) {
var w = this._canvas.width;
var h = this._canvas.height;
//var imageData = ctx.getImageData(0, 0, w, h);
//var pixels = imageData.data;
var pixelIndex = tile.timeIndex[key];
for(var p = 0; p < activePixels; ++p) {
var posIdx = tile.renderDataPos[pixelIndex + p];
var c = tile.renderData[pixelIndex + p];
if(c) {
var color = colors[Math.min(c, colors.length - 1)];
var x = tile.x[posIdx];// + px;
var y = tile.y[posIdx]; //+ py;
ctx.fillStyle = color;
ctx.fillRect(x, y, res, res);
/*
for(var xx = 0; xx < res; ++xx) {
for(var yy = 0; yy < res; ++yy) {
var idx = 4*((x+xx) + w*(y + yy));
pixels[idx + 0] = color[0];
pixels[idx + 1] = color[1];
pixels[idx + 2] = color[2];
pixels[idx + 3] = color[3];
}
}
*/
}
}
//ctx.putImageData(imageData, 0, 0);
}
//prof.end();
}
};
// exports public api
exports.torque.renderer.Rectangle = RectanbleRenderer;
})(typeof exports === "undefined" ? this : exports);

38
lib/torque/request.js Normal file
View File

@ -0,0 +1,38 @@
(function(exports) {
var torque = exports.torque = exports.torque || {};
torque.net = torque.net || {};
function get(url, callback) {
var request = XMLHttpRequest;
// from d3.js
if (window.XDomainRequest
&& !("withCredentials" in request)
&& /^(http(s)?:)?\/\//.test(url)) request = XDomainRequest;
var req = new request();
function respond() {
var status = req.status, result;
if (!status && req.responseText || status >= 200 && status < 300 || status === 304) {
callback(req);
} else {
callback(null);
}
}
"onload" in req
? req.onload = req.onerror = respond
: req.onreadystatechange = function() { req.readyState > 3 && respond(); };
req.open("GET", url, true);
//req.responseType = 'arraybuffer';
req.send(null)
return req;
}
torque.net = {
get: get
};
})(typeof exports === "undefined" ? this : exports);

31
lib/underscore-min.js vendored
View File

@ -1,31 +0,0 @@
// 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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};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);

File diff suppressed because it is too large Load Diff

27
package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "torque.js",
"version": "2.0.00",
"description": "Torque javascript library",
"repository": {
"type": "git",
"url": "git://github.com/CartoDB/torque.git"
},
"author": {
"name": "CartoDB",
"url": "http://cartodb.com/",
"email": "wadus@cartodb.com"
},
"contributors": [
"Andrew Hill <andrew@vizzuality.com>",
"Simon Tokumine <tokumine@google.com>",
"Javier Alvarez <jmedina@vizzuality.com>",
"Javier Arce <javierarce@vizzuality.com>",
"Javier Santana <jsantana@vizzuality.com>"
],
"licenses": [{
"type": "BSD"
}],
"devDependencies": {
"uglify-js": "1.3.3"
}
}

View File

@ -1,94 +0,0 @@
/*
====================
canvas setup for drawing tiles
====================
*/
function CanvasTileLayer(canvas_setup, render) {
this.tileSize = new google.maps.Size(256, 256);
this.maxZoom = 19;
this.name = "Tile #s";
this.alt = "Canvas tile layer";
this.tiles = {};
this.canvas_setup = canvas_setup;
this.render = render;
if (!render) {
this.render = canvas_setup;
}
}
// create a tile with a canvas element
CanvasTileLayer.prototype.create_tile_canvas = function (coord, zoom, ownerDocument) {
// create canvas and reset style
var canvas = ownerDocument.createElement('canvas');
var hit_canvas = ownerDocument.createElement('canvas');
canvas.style.border = hit_canvas.style.border = "none";
canvas.style.margin = hit_canvas.style.margin = "0";
canvas.style.padding = hit_canvas.style.padding = "0";
// prepare canvas and context sizes
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = this.tileSize.width;
ctx.height = canvas.height = this.tileSize.height;
var hit_ctx = hit_canvas.getContext('2d');
hit_canvas.width = hit_ctx.width = this.tileSize.width;
hit_canvas.height = hit_ctx.height = this.tileSize.height;
//set unique id
var tile_id = coord.x + '_' + coord.y + '_' + zoom;
canvas.setAttribute('id', tile_id);
hit_canvas.setAttribute('id', tile_id);
if (tile_id in this.tiles)
delete this.tiles[tile_id];
this.tiles[tile_id] = {canvas:canvas, ctx:ctx, hit_canvas:hit_canvas, hit_ctx:hit_ctx, coord:coord, zoom:zoom, primitives:null};
// custom setup
//if (tile_id == '19295_24654_16'){
if (this.canvas_setup)
this.canvas_setup(this.tiles[tile_id], coord, zoom);
//}
return canvas;
}
CanvasTileLayer.prototype.each = function (callback) {
for (var t in this.tiles) {
var tile = this.tiles[t];
callback(tile);
}
}
CanvasTileLayer.prototype.recreate = function () {
for (var t in this.tiles) {
var tile = this.tiles[t];
this.canvas_setup(tile, tile.coord, tile.zoom);
}
};
CanvasTileLayer.prototype.redraw_tile = function (tile) {
this.render(tile, tile.coord, tile.zoom);
};
CanvasTileLayer.prototype.redraw = function () {
for (var t in this.tiles) {
var tile = this.tiles[t];
this.render(tile, tile.coord, tile.zoom);
}
};
// could be called directly...
CanvasTileLayer.prototype.getTile = function (coord, zoom, ownerDocument) {
return this.create_tile_canvas(coord, zoom, ownerDocument);
};
CanvasTileLayer.prototype.releaseTile = function (tile) {
var id = tile.getAttribute('id');
delete this.tiles[id];
};

View File

@ -1,451 +0,0 @@
/*
====================
this class renders tile data in a given time
====================
*/
function TimePlayer(min_date, end, step, options) {
this.time = 0;
this.step = step;
this.CAP_UNIT = end;
this.MIN_DATE = min_date;
this.MAX_UNITS = options.steps + 2;
this.MAX_VALUE = 0;
this.MAX_VALUE_LOG = 0;
this.BASE_UNIT = 0;
this.canvas_setup = this.get_time_data;
this.render = this.render_time;
this.cells = [];
this.table = options.table;
this.user = options.user;
this.t_column = options.column;
this.resolution = options.resolution;
this.countby = options.countby
this.base_url = 'http://' + this.user + '.cartodb.com/api/v2/sql';
this.options = options;
}
TimePlayer.prototype = new CanvasTileLayer();
/**
* change time, t is the month (integer)
*/
TimePlayer.prototype.set_time = function (t) {
if (this.time != (t >> 0)) {
this.time = t;
this.redraw();
}
};
TimePlayer.prototype.reset_max_value = function () {
this.MAX_VALUE = 0;
this.MAX_VALUE_LOG = 0;
};
/**
* change table where the data is choosen
*/
TimePlayer.prototype.set_table = function (table, size) {
if (this.table === table) {
return; // nothing to do
}
this.table = table;
this.pixel_size = size;
this.recreate();
this.redraw();
};
/**
* private
*/
// get data from cartodb
TimePlayer.prototype.sql = function (sql, callback) {
var self = this;
var uri = this.base_url + "?q=" + encodeURIComponent(sql);
//uri += '&t=' + Date.now() + Math.random();
$.getJSON(uri, function (data) {
callback(data);
});
};
var originShift = 2 * Math.PI * 6378137 / 2.0;
var initialResolution = 2 * Math.PI * 6378137 / 256.0;
function meterToPixels(mx, my, zoom) {
var res = initialResolution / (1 << zoom);
var px = (mx + originShift) / res;
var py = (my + originShift) / res;
return [px, py];
}
// precache data to render fast
TimePlayer.prototype.pre_cache_months = function (rows, coord, zoom) {
var row;
var xcoords;
var ycoords;
var values;
if (typeof(ArrayBuffer) !== undefined) {
xcoords = new Uint8Array(new ArrayBuffer(rows.length));
ycoords = new Uint8Array(new ArrayBuffer(rows.length));
values = new Uint8Array(new ArrayBuffer(rows.length * this.MAX_UNITS));// 256 months
} else {
// fallback
xcoords = [];
ycoords = [];
values = [];
// array buffer set by default to 0
for (var i = 0; i < rows.length * this.MAX_UNITS; ++i) {
values[i] = 0;
}
}
// base tile x, y
var tile_base_x = coord.x * 256;
var tile_base_y = coord.y * 256;
var total_pixels = 256 << zoom;
for (var i in rows) {
row = rows[i];
pixels = meterToPixels(row.x, row.y, zoom);
pixels[1] = total_pixels - pixels[1];
xcoords[i] = pixels[0];
ycoords[i] = pixels[1];
var base_idx = i * this.MAX_UNITS;
//def[row.sd[0]] = row.se[0];
for (var j = 0; j < row.dates.length; ++j) {
values[base_idx + row.dates[j]] = row.vals[j];
if (row.vals[j] > this.MAX_VALUE) {
this.MAX_VALUE = row.vals[j];
this.MAX_VALUE_LOG = Math.log(this.MAX_VALUE);
}
}
;
if (this.options.cumulative) {
for (var j = 1; j < this.MAX_UNITS; ++j) {
values[base_idx + j] += values[base_idx + j - 1];
if (this.options.cumulative_expires) {
for ( var u = 0; u < row.dates_end.length; ++u ) {
if ( row.dates_end[u] != null && row.dates_end[u] < (j+1) ) {
values[base_idx + j - 1 ] -= row.vals[u]
}
}
}
if (values[base_idx + j] > this.MAX_VALUE) {
this.MAX_VALUE = values[base_idx + j];
this.MAX_VALUE_LOG = Math.log(this.MAX_VALUE);
}
}
}
}
return {
length:rows.length,
xcoords:xcoords,
ycoords:ycoords,
values:values,
size:1 << (this.resolution * 2)
};
};
// get time data in json format
TimePlayer.prototype.get_time_data = function (tile, coord, zoom) {
var self = this;
if (!self.table) {
return;
}
// get x, y for cells and sd, se for deforestation changes
// sd contains the months
// se contains the deforestation for each entry in sd
// take se and sd as a matrix [se|sd]
var numTiles = 1 << zoom;
var sql = ""
var column_conv = "";
var expir_conv = "";
if (this.options.istime == true){
column_conv = "date_part('epoch',{0})".format(this.t_column);
expir_conv = "date_part('epoch',{0})".format(this.options.expiration_column);
} else {
column_conv = this.t_column;
expir_conv = this.options.expiration_column;
}
var z_resolution = function(z) {
var earth_circumference = 40075017;
var tile_size = 256;
var full_resolution = earth_circumference/tile_size;
return full_resolution / (Math.pow(2,z));
};
sql = "WITH cte AS ( " +
"SELECT ST_SnapToGrid(i.the_geom_webmercator, " +
"CDB_XYZ_Resolution({0})*{1}) g"
. format(zoom, this.resolution) +
", {0} c " .format(this.countby) +
", floor(({0}- {1})/{2}) d" .format(column_conv, this.MIN_DATE, this.step);
if ( this.options.cumulative_expires ) {
sql += ", floor(({0}- {1})/{2}) de".format(expir_conv, this.MIN_DATE, this.step);
}
sql += " FROM {0} i\n".format(this.options.table) +
"WHERE i.the_geom_webmercator && CDB_XYZ_Extent({0}, {1}, {2}) "
.format(coord.x, coord.y, zoom) +
" GROUP BY g, d";
if ( this.options.cumulative_expires ) {
sql += ", de";
}
sql += ") SELECT st_x(g) x, st_y(g) y, array_agg(c) vals, array_agg(d) dates ";
if ( this.options.cumulative_expires ) {
sql += ", array_agg(de) dates_end";
}
sql += " FROM cte GROUP BY x,y";
var prof = Profiler.get('tile fetch');
prof.start();
this.sql(sql, function (data) {
if (data.rows) {
prof.end();
var p = Profiler.get('tile data cache');
p.start();
tile.cells = self.pre_cache_months(data.rows, coord, zoom);
p.end();
p = Profiler.get('tile render');
p.start();
self.redraw_tile(tile);
p.end();
}
});
};
YO = 1;
TimePlayer.prototype.render_time = function (tile, coord, zoom) {
var self = this;
//var month = -this.BASE_UNIT + 1 + this.time>>0;
//var month = Math.ceil(this.MAX_UNITS * (this.time - this.BASE_UNIT)/(this.CAP_UNIT-this.BASE_UNIT));
var month = this.time;
var w = tile.canvas.width;
var h = tile.canvas.height;
var ctx = tile.ctx;
var i, x, y, cell, cells;
cells = tile.cells;
if (!cells || cells.length === 0) {
return;
}
var colors = [
//"#FFFFE5",
//"#FFF7BC",
"#FEE391",
"#FEC44F",
"#FE9929",
"#EC7014",
"#CC4C02",
"#993404",
"#662506"
];
var fillStyle;
// clear canvas
tile.canvas.width = w;
var ci = 0;
var cu = 0;
ctx.strokeStyle = ctx.fillStyle = colors[cu];
ctx.globalCompositeOperation = this.options.blendmode;
var xc = cells.xcoords;
var yc = cells.ycoords;
var vals = cells.values;
var dz = 256 / Math.pow(2, zoom)
// render cells
var len = cells.length;
var pixel_size = this.resolution//*this.options.cellsize;
var pixel_size_trail_circ = pixel_size * 2;
var pixel_size_trail_squa = pixel_size * 1.5;
var offset = Math.floor((pixel_size - 1) / 2);
var tau = Math.PI * 2;
// memoize sprite canvases
if (self.sprite_1 == undefined) {
self.sprite_1 = [];
$(colors).each(function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = pixel_size * 2;
ctx.height = canvas.height = pixel_size * 2;
ctx.globalAlpha = 1;
ctx.fillStyle = this.toString();
ctx.beginPath();
ctx.arc(pixel_size, pixel_size, pixel_size, 0, tau, true, true);
ctx.closePath();
ctx.fill();
self.sprite_1.push(canvas);
});
}
if (self.sprite_2 == undefined) {
self.sprite_2 = [];
$(colors).each(function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = pixel_size_trail_circ * 2;
ctx.height = canvas.height = pixel_size_trail_circ * 2;
ctx.globalAlpha = 0.3;
ctx.fillStyle = this.toString();
ctx.beginPath();
ctx.arc(pixel_size_trail_circ, pixel_size_trail_circ, pixel_size_trail_circ, 0, tau, true, true);
ctx.closePath();
ctx.fill();
self.sprite_2.push(canvas);
});
}
if (self.sprite_3 == undefined) {
self.sprite_3 = [];
$(colors).each(function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.width = canvas.width = pixel_size * 2;
ctx.height = canvas.height = pixel_size * 2;
ctx.globalAlpha = 0.3;
ctx.fillStyle = this.toString();
ctx.beginPath();
ctx.arc(pixel_size, pixel_size, pixel_size, 0, tau, true, true);
ctx.closePath();
ctx.fill();
self.sprite_3.push(canvas);
});
}
var numTiles = 1 << zoom;
for (i = 0; i < len; ++i) {
var cell = cells.values[this.MAX_UNITS * i + month];
if (cell) {
ci = cell == 0 ? 0 : Math.floor((colors.length - 1) * (Math.log(cell) / this.MAX_VALUE_LOG));
if (ci != cu) {
cu = ci < colors.length ? ci : cu;
ctx.fillStyle = colors[cu];
}
if (this.options.point_type == 'circle') {
ctx.drawImage(self.sprite_1[cu], xc[i] - pixel_size, yc[i] - pixel_size)
} else if (this.options.point_type == 'square') {
ctx.fillRect(xc[i] - offset, yc[i] - offset, pixel_size, pixel_size);
}
}
if (this.options.trails == true) {
cell = cells.values[this.MAX_UNITS * i + month - 1];
if (cell) {
ci = cell == 0 ? 0 : Math.floor((colors.length - 1) * (Math.log(cell) / this.MAX_VALUE_LOG));
if (ci != cu) {
cu = ci < colors.length ? ci : cu;
ctx.fillStyle = colors[cu];
}
if (this.options.point_type == 'circle') {
//alignment hack - sorry to the gods of graphics
ctx.drawImage(self.sprite_2[cu], xc[i] - pixel_size_trail_squa - 1, yc[i] - pixel_size_trail_squa - 1)
} else if (this.options.point_type == 'square') {
ctx.fillRect(xc[i] - offset, yc[i] - offset, pixel_size_trail_squa, pixel_size_trail_squa);
}
}
cell = cells.values[this.MAX_UNITS * i + month - 2];
if (cell) {
ci = cell == 0 ? 0 : Math.floor((colors.length - 1) * (Math.log(cell) / this.MAX_VALUE_LOG));
if (ci != cu) {
cu = ci < colors.length ? ci : cu;
ctx.fillStyle = colors[cu];
}
if (this.options.point_type == 'circle') {
ctx.drawImage(self.sprite_3[cu], xc[i] - pixel_size, yc[i] - pixel_size)
} else if (this.options.point_type == 'square') {
ctx.fillRect(xc[i] - offset, yc[i] - offset, pixel_size, pixel_size);
}
}
}
}
};
/**
* String formatting for JavaScript.
*
* Usage:
*
* "{0} is {1}".format("CartoDB", "epic!");
* // CartoDB is epic!
*
*/
String.prototype.format = (function (i, safe, arg) {
function format() {
var str = this,
len = arguments.length + 1;
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;
}
//format.native = String.prototype.format;
return format;
})();
// =================
// profiler
// =================
function Profiler() {
}
Profiler.times = {};
Profiler.new_time = function (type, time) {
var t = Profiler.times[type] = Profiler.times[type] || {
max:0,
min:10000000,
avg:0,
total:0,
count:0
};
t.max = Math.max(t.max, time);
t.total += time;
t.min = Math.min(t.min, time);
++t.count;
t.avg = t.total / t.count;
};
Profiler.print_stats = function () {
for (k in Profiler.times) {
var t = Profiler.times[k];
console.log(" === " + k + " === ");
console.log(" max: " + t.max);
console.log(" min: " + t.min);
console.log(" avg: " + t.avg);
console.log(" total: " + t.total);
}
};
Profiler.get = function (type) {
return {
t0:null,
start:function () {
this.t0 = new Date().getTime();
},
end:function () {
if (this.t0 !== null) {
Profiler.new_time(type, this.time = new Date().getTime() - this.t0);
this.t0 = null;
}
}
};
};

View File

@ -1,383 +0,0 @@
/**
*
* Torque library
*
* A tool for mapping temporal data from CartoDB
* Still in development and being finalized for
* CartoDB 2.0
*
* Authors: Andrew Hill, Simon Tokumine, Javier Santana
*
*/
// iOS fix
if (Function.prototype.bind == undefined) {
Function.prototype.bind = function (bind) {
var self = this;
return function () {
var args = Array.prototype.slice.call(arguments);
return self.apply(bind || null, args);
};
};
}
function Torque() {
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 Torque)) {
return new Torque(modules, callback);
}
if (!modules || modules === '*') {
modules = [];
for (i in Torque.modules) {
if (Torque.modules.hasOwnProperty(i)) {
modules.push(i);
}
}
}
for (i = 0; i < modules.length; i += 1) {
Torque.modules[modules[i]](this);
}
callback(this);
return this;
}
;
Torque.modules = {};
Torque.modules.app = function (torque) {
torque.app = {};
torque.app.Instance = Class.extend(
{
init:function (logging) {
this.layers = {};
torque.log.enabled = logging ? logging : false;
},
addLayer:function (map, options) {
var layer = new torque.layer.Engine(map, options);
return layer
}
}
);
};
Torque.modules.layer = function (torque) {
torque.layer = {};
torque.layer.Engine = Class.extend({
init:function (map, options) {
this._defaults = {
user:'viz2',
table:'ny_bus',
column:'timestamp',
istime: true,
steps:250,
resolution:3,
cumulative:false,
fps:24,
autoplay:true,
clock:false,
zindex:0,
fitbounds:false,
countby:'count(i.cartodb_id)',
blendmode:'source-over',
trails:false,
point_type:'square',
subtitles:false,
scrub:false
}
this.options = _.defaults(options, this._defaults);
this._map = map;
this._index = this.options.zindex;
while (this._map.overlayMapTypes.length < this.options.zindex) {
this._map.overlayMapTypes.push(null);
}
this._cartodb = new Backbone.CartoDB({user:this.options.user});
this.bounds = new google.maps.LatLngBounds();
torque.clock.enabled = this.options.clock ? this.options.clock : false;
torque.clock.set('loading...');
this.getDeltas();
},
pause:function () {
if (this.running == true) {
this.running = false;
} else {
this.running = true;
this.play();
}
},
setOptions:function (new_options) {
this.running = false;
this.options = _.defaults(new_options, this._defaults);
torque.clock.enabled = this.options.clock ? this.options.clock : false;
torque.clock.set('loading...');
this._cartodb = new Backbone.CartoDB({user:this.options.user});
this.bounds = new google.maps.LatLngBounds();
this._map.overlayMapTypes.setAt(this._index, null);
this.getDeltas();
},
run:function () {
this.start = new Date(this.options.start).getTime();
this.end = new Date(this.options.end).getTime();
this._current = this.start;
this._step = Math.floor((this.end - this.start) / this.options.steps);
this._setupListeners();
this._display = new TimePlayer(this.start, (this.start - this.end), this._step, this.options);
this._map.overlayMapTypes.setAt(this._index, this._display);
this.fitBounds(this.options.fitbounds);
this.running = false;
torque.clock.clear();
// If scrubbable, override other options that may have been set
if (this.options.scrub){
this.options.scrub(this);
// this.options.autoplay = false;
// this.options.trails = false;
}
if (this.options.autoplay) {
this.running = true;
this.play();
}
torque.log.info('Layer is now running!');
},
_setupListeners:function () {
var that = this;
google.maps.event.addListener(this._map, 'zoom_changed', function () {
that._display.reset_max_value();
});
},
getBounds:function () {
return this.bounds;
},
fitBounds:function (f) {
if (f !== false) {
this._map.fitBounds(this.bounds);
if (typeof f == 'number') {
this._map.setZoom(this._map.getZoom() + f);
} else {
this._map.setZoom(this._map.getZoom());
}
}
},
getDeltas:function (options) {
var that = this;
if (this.options.istime == true){
var max_col = "date_part('epoch',max({0}))".format(this.options.column);
var min_col = "date_part('epoch',min({0}))".format(this.options.column);
} else {
var max_col = "max({0})".format(this.options.column);
var min_col = "min({0})".format(this.options.column);
}
var sql = "SELECT st_xmax(st_envelope(st_collect(the_geom))) xmax,st_ymax(st_envelope(st_collect(the_geom))) ymax, st_xmin(st_envelope(st_collect(the_geom))) xmin, st_ymin(st_envelope(st_collect(the_geom))) ymin, {0} max, {1} min FROM {2}".format(max_col, min_col, this.options.table);
var timeExtents = this._cartodb.CartoDBCollection.extend({
sql:sql
});
var times = new timeExtents();
times.fetch();
times.bind('reset', function () {
times.each(function (p) {
that.options.start = p.get('min');
that.options.end = p.get('max');
that.bounds.extend(new google.maps.LatLng(p.get('ymin'), p.get('xmax')));
that.bounds.extend(new google.maps.LatLng(p.get('ymax'), p.get('xmin')));
that.bounds.extend(new google.maps.LatLng((p.get('ymax') + p.get('ymin')) / 2, (p.get('xmax') + p.get('xmin')) / 2));
});
that.run();
});
},
advance:function () {
if (this._current + this._step < this.end) {
this._current = this._current + this._step;
// } else if (this._current < this.end) {
// this._current = this.end;
} else {
this._current = this.start;
}
this._display.set_time((this._current - this.start) / this._step);
},
play:function () {
var pause = 0;
if (this._current < this.end) {
this._current = this._current + this._step
if (this.end < this._current) {
pause = 500;
}
} else {
this._current = this.start;
}
var date = new Date(this._current * 1000);
var date_arry = date.toString().substr(4).split(' ');
torque.clock.set('<span id="month">' + date_arry[0] + '</span> <span id="year">' + date_arry[2] + '</span>');
if (this.options.subtitles) {
torque.subtitles.set(date);
}
this._display.set_time((this._current - this.start) / this._step);
if (this.options.scrub_move){
this.options.scrub_move(this)
}
if (this.running) {
if ( this.options.fps ) {
var ms = pause + 1000 * 1 / this.options.fps;
//console.log("play timeout: " + ms + " ms (pause:" + pause + ", fps:" + this.options.fps + ")");
setTimeout(function () {
this.play()
}.bind(this), ms);
}
}
}
});
}
Torque.modules.clock = function (torque) {
torque.clock = {};
torque.clock.clear = function () {
$('.torque_time').html('');
};
torque.clock.set = function (msg) {
torque.clock._hand(msg);
};
torque.clock._hand = function (msg) {
var clockger = window.console;
if (torque.clock.enabled) {
$('.torque_time').html(msg);
}
};
};
Torque.modules.subtitles = function (torque) {
torque.subtitles = {
subs:[
{
from:new Date("March 01, 1913 00:00:00"),
to:new Date("July 01, 1914 00:00:00"),
sub:"Pre war"
},
{
from:new Date("August 01, 1914 00:00:00"),
to:new Date("February 01, 1915 00:00:00"),
sub:"War begins with Germany"
},
{
from:new Date("February 02, 1915 00:00:00"),
to:new Date("October 01, 1916 00:00:00"),
sub:"North Sea naval blockade"
},
{
from:new Date("October 02, 1917 00:00:00"),
to:new Date("April 01, 1917 00:00:00"),
sub:"Atlantic U-boat warfare"
},
{
from:new Date("April 02, 1917 00:00:00"),
to:new Date("September 01, 1917 00:00:00"),
sub:"USA enters war"
},
{
from:new Date("September 02, 1917 00:00:00"),
to:new Date("November 01, 1918 00:00:00"),
sub:"Destroyers begin to escort convoys in Atlantic"
},
{
from:new Date("November 02, 1918 00:00:00"),
to:new Date("August 01, 1920 00:00:00"),
sub:"End of WWI"
},
{
from:new Date("August 02, 1920 00:00:00"),
to:new Date("August 01, 1925 00:00:00"),
sub:"Trade routes resume"
}
]
};
torque.subtitles.clear = function () {
$('.torque_subs').html('');
};
torque.subtitles.set = function (date) {
$.each(this.subs, function () {
if (this.from < date && this.to > date) {
torque.subtitles._update(this.sub);
}
});
};
torque.subtitles._update = function (msg) {
$('.torque_subs').html(msg);
};
};
/**
* Logging module that torquetes log messages to the console and to the Speed
* Tracer API. It contains convenience methods for info(), warn(), error(),
* and todo().
*
*/
Torque.modules.log = function (torque) {
torque.log = {};
torque.log.info = function (msg) {
torque.log._torquete('INFO: ' + msg);
};
torque.log.warn = function (msg) {
torque.log._torquete('WARN: ' + msg);
};
torque.log.error = function (msg) {
torque.log._torquete('ERROR: ' + msg);
};
torque.log.todo = function (msg) {
torque.log._torquete('TODO: ' + msg);
};
torque.log._torquete = function (msg) {
var logger = window.console;
if (torque.log.enabled) {
if (logger && logger.markTimeline) {
logger.markTimeline(msg);
}
console.log(msg);
}
};
};
var originShift = 2 * Math.PI * 6378137 / 2.0;
var initialResolution = 2 * Math.PI * 6378137 / 256.0;
function meterToPixels(mx, my, zoom) {
var res = initialResolution / (1 << zoom);
var px = (mx + originShift) / res;
var py = (my + originShift) / res;
return [px, py];
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
test("processTile", function() {
var json = new torque.providers.JsonArray({
url: "http://test.com/{z}/{x}/{y}.json"
});
var tile = json.proccessTile(jsonarray_fixture.rows, {
x: 0,
y: 0,
z: 0
});
ok(tile);
equal(jsonarray_fixture.rows.length, tile.x.length);
equal(jsonarray_fixture.rows.length, tile.y.length);
});

18
test/suite.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="vendor/qunit.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="vendor/qunit.js"></script>
<script src="../lib/torque/provider.jsonarray.js"></script>
<script src="data/torque.array.json"></script>
<script src="provider.jsonarray.js"></script>
</body>
</html>

244
test/vendor/qunit.css vendored Normal file
View File

@ -0,0 +1,244 @@
/**
* QUnit v1.12.0 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-top-right-radius: 5px;
-webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-testrunner-toolbar label {
display: inline-block;
padding: 0 .5em 0 .1em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
#qunit-modulefilter-container {
float: right;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests li .runtime {
float: right;
font-size: smaller;
}
.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
.qunit-collapsed {
display: none;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3c510c;
background-color: #fff;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}

2212
test/vendor/qunit.js vendored Normal file

File diff suppressed because it is too large Load Diff

5178
vendor/carto.js vendored Normal file

File diff suppressed because it is too large Load Diff

235
vendor/leaflet.carto.js vendored Normal file
View File

@ -0,0 +1,235 @@
// 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 + ";";
};
Object.defineProperty(tree.Filterset.prototype, 'toJS', {
enumerable: false,
value: function(env) {
var opMap = {
'=': '==='
};
return _.map(this, 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.Definition.prototype.toJS = function() {
var shaderAttrs = {};
// merge conditions from filters with zoom condition of the
// definition
var zoom = "(" + this.zoom + " & (1 << ctx.zoom))";
var _if = this.filters.toJS()
if(_if && _if.length > 0) {
_if += " && " + zoom;
} else {
_if = zoom;
}
_.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 CartoCSS(style) {
if(style) {
this.setStyle(style);
}
}
CartoCSS.Layer = function(shader, options) {
this.options = options;
this.shader = shader;
};
CartoCSS.renderers = {};
CartoCSS.renderers['svg'] = {
maps: {},
transform: function(src) {
var target = {};
for(var i in src) {
var t = this.maps[i];
if(t) {
target[t] = src[i];
} else {
console.log("unknow property: " + i);
}
}
return target;
}
};
(function() {
var renderer = CartoCSS.renderers['svg'];
var ref = window.carto['mapnik-reference'].version.latest;
var s = 'polygon';
for(var i in ref.symbolizers[s]) {
renderer.maps[ref.symbolizers[s][i].css] = i;
}
console.log(renderer.maps);
})();
CartoCSS.Layer.prototype = {
/*
* ``target``: style, 'svg', 'canvas'...
* ``props``: feature properties
* ``context``: rendering properties, i.e zoom
*/
getStyle: function(target, props, context) {
var style = {};
for(var i in this.shader) {
style[i] = this.shader[i](props, context);
}
return CartoCSS.renderers[target].transform(style);
},
/**
* returns true if a feature needs to be rendered
*/
filter: function(featureType, props, context) {
for(var i in this.shader) {
var s = this.shader[i](props, context);
if(s) {
return true;
}
}
return false;
},
transformGeometries: function(geojson) {
return geojson;
}
};
CartoCSS.prototype = {
setStyle: function(style) {
var layers = this.parse(style);
this.layers = layers.map(function(shader) {
return new CartoCSS.Layer(shader);
});
},
getLayers: function() {
return this.layers;
},
_createFn: function(ops) {
var body = ops.join('\n');
return Function("data","ctx", "var _value = null; " + body + "; return _value; ");
},
_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]; })();");
}
}
},
parse: function(cartocss) {
var parse_env = {
frames: [],
errors: [],
error: function(obj) {
this.errors.push(obj);
}
};
var ruleset = null;
try {
ruleset = (new carto.Parser(parse_env)).parse(cartocss);
} catch(e) {
// add the style.mss string to match the response from the server
parse_env.errors.push(e.message);
return;
}
if(ruleset) {
var defs = ruleset.toList(parse_env);
defs.reverse();
// group by elements[0].value::attachment
var layers = {};
for(var i = 0; i < defs.length; ++i) {
var def = defs[i];
var key = def.elements[0] + "::" + def.attachment;
var layer = layers[key] = (layers[key] || {});
var props = def.toJS();
for(var v in props) {
(layer[v] = (layer[v] || [])).push(props[v].join('\n'))
}
}
var ordered_layers = [];
var done = {};
for(var i = 0; i < defs.length; ++i) {
var def = defs[i];
var k = def.elements[0] + "::" + def.attachment;
if(!done[k]) {
var layer = layers[k];
for(var prop in layer) {
layer[prop] = this._createFn(layer[prop]);
}
ordered_layers.push(layer);
done[k] = true;
}
}
return ordered_layers;
}
return null;
}
};

467
vendor/leaflet.css vendored Normal file
View File

@ -0,0 +1,467 @@
/* required styles */
.leaflet-map-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-pane,
.leaflet-tile-container,
.leaflet-overlay-pane,
.leaflet-shadow-pane,
.leaflet-marker-pane,
.leaflet-popup-pane,
.leaflet-overlay-pane svg,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
-ms-touch-action: none;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container img {
max-width: none !important;
}
/* stupid Android 2 doesn't understand "max-width: none" properly */
.leaflet-container img.leaflet-image-layer {
max-width: 15000px !important;
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-tile-pane { z-index: 2; }
.leaflet-objects-pane { z-index: 3; }
.leaflet-overlay-pane { z-index: 4; }
.leaflet-shadow-pane { z-index: 5; }
.leaflet-marker-pane { z-index: 6; }
.leaflet-popup-pane { z-index: 7; }
/* control positioning */
.leaflet-control {
position: relative;
z-index: 7;
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-tile,
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-tile-loaded,
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile,
.leaflet-touching .leaflet-zoom-animated {
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-clickable {
cursor: pointer;
}
.leaflet-container {
cursor: -webkit-grab;
cursor: -moz-grab;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging,
.leaflet-dragging .leaflet-clickable,
.leaflet-dragging .leaflet-container {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline: 0;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-container a.leaflet-active {
outline: 2px solid orange;
}
.leaflet-zoom-box {
border: 2px dotted #05f;
background: white;
opacity: 0.5;
}
/* general typography */
.leaflet-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 7px rgba(0,0,0,0.65);
-webkit-border-radius: 4px;
border-radius: 4px;
}
.leaflet-bar a, .leaflet-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
-webkit-border-top-left-radius: 4px;
border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
-webkit-border-bottom-left-radius: 4px;
border-bottom-left-radius: 4px;
-webkit-border-bottom-right-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar {
-webkit-border-radius: 10px;
border-radius: 10px;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
-webkit-border-top-left-radius: 7px;
border-top-left-radius: 7px;
-webkit-border-top-right-radius: 7px;
border-top-right-radius: 7px;
}
.leaflet-touch .leaflet-bar a:last-child {
-webkit-border-bottom-left-radius: 7px;
border-bottom-left-radius: 7px;
-webkit-border-bottom-right-radius: 7px;
border-bottom-right-radius: 7px;
border-bottom: none;
}
/* zoom control */
.leaflet-control-zoom-in {
font: bold 18px 'Lucida Console', Monaco, monospace;
}
.leaflet-control-zoom-out {
font: bold 22px 'Lucida Console', Monaco, monospace;
}
.leaflet-touch .leaflet-control-zoom-in {
font-size: 22px;
line-height: 30px;
}
.leaflet-touch .leaflet-control-zoom-out {
font-size: 28px;
line-height: 30px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 7px rgba(0,0,0,0.4);
background: #f8f8f9;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background-color: rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px #bbb;
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
}
.leaflet-container .leaflet-control-attribution,
.leaflet-container .leaflet-control-scale {
font-size: 11px;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
color: black;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
text-shadow: 1px 1px 1px #fff;
background-color: rgba(255, 255, 255, 0.5);
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
white-space: nowrap;
overflow: hidden;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 4px solid rgba(0,0,0,0.3);
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
-webkit-border-radius: 12px;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 19px;
line-height: 1.4;
}
.leaflet-popup-content p {
margin: 18px 0;
}
.leaflet-popup-tip-container {
margin: 0 auto;
width: 40px;
height: 20px;
position: relative;
overflow: hidden;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
background: white;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
padding: 4px 4px 0 0;
text-align: center;
width: 18px;
height: 14px;
font: 16px/14px Tahoma, Verdana, sans-serif;
color: #c3c3c3;
text-decoration: none;
font-weight: bold;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover {
color: #999;
}
.leaflet-popup-scrolled {
overflow: auto;
border-bottom: 1px solid #ddd;
border-top: 1px solid #ddd;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
.leaflet-editing-icon {
-webkit-border-radius: 2px;
border-radius: 2px;
}

8909
vendor/leaflet.js vendored Normal file

File diff suppressed because it is too large Load Diff

1059
vendor/underscore.js vendored Normal file

File diff suppressed because it is too large Load Diff