Merge branch 'master' into gh-pages
This commit is contained in:
commit
2690dfacc7
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
.idea/
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
*.swp
|
||||
node_modules
|
||||
|
28
Makefile
Normal file
28
Makefile
Normal 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
|
||||
|
69
README.md
69
README.md
@ -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
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
3088
dist/torque.uncompressed.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
193
doc/API.md
Normal file
193
doc/API.md
Normal 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
|
@ -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>
|
@ -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
67
examples/leaflet.html
Normal 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
113
examples/navy_gmaps.html
Normal 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>
|
||||
|
79
examples/navy_leaflet.html
Normal file
79
examples/navy_leaflet.html
Normal 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>
|
||||
|
@ -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>
|
@ -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>
|
||||
|
@ -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
221
examples/playground.html
Normal 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>
|
@ -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>
|
@ -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>
|
@ -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
263
examples/vendor/codemirror.css
vendored
Normal 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
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
639
examples/vendor/css.js
vendored
Normal 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"
|
||||
});
|
||||
})();
|
@ -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>
|
@ -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>
|
570
index.html
570
index.html
@ -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>
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
};
|
1159
lib/backbone.js
1159
lib/backbone.js
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 116 B |
2799
lib/carto.js
2799
lib/carto.js
File diff suppressed because it is too large
Load Diff
@ -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);
|
@ -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;}
|
66
lib/class.js
66
lib/class.js
@ -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;
|
||||
};
|
||||
|
||||
|
||||
})();
|
6
lib/jquery-ui-1.10.2.custom.min.js
vendored
6
lib/jquery-ui-1.10.2.custom.min.js
vendored
File diff suppressed because one or more lines are too long
2945
lib/modestmaps.js
2945
lib/modestmaps.js
File diff suppressed because it is too large
Load Diff
BIN
lib/sprite.png
BIN
lib/sprite.png
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB |
93
lib/torque/animator.js
Normal file
93
lib/torque/animator.js
Normal 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);
|
348
lib/torque/cartocss_reference.js
Normal file
348
lib/torque/cartocss_reference.js
Normal 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
44
lib/torque/core.js
Normal 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
506
lib/torque/gmaps/CanvasLayer.js
Executable 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_);
|
||||
}
|
||||
};
|
||||
}
|
98
lib/torque/gmaps/canvas_tile_layer.js
Normal file
98
lib/torque/gmaps/canvas_tile_layer.js
Normal 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];
|
||||
};
|
||||
|
||||
}
|
186
lib/torque/gmaps/gmaps_tileloader_mixin.js
Normal file
186
lib/torque/gmaps/gmaps_tileloader_mixin.js
Normal 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
259
lib/torque/gmaps/torque.js
Normal 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);
|
125
lib/torque/leaflet/canvas_layer.js
Normal file
125
lib/torque/leaflet/canvas_layer.js
Normal 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
|
133
lib/torque/leaflet/leaflet_tileloader_mixin.js
Normal file
133
lib/torque/leaflet/leaflet_tileloader_mixin.js
Normal 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
|
220
lib/torque/leaflet/torque.js
Normal file
220
lib/torque/leaflet/torque.js
Normal 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
38
lib/torque/math.js
Normal 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
146
lib/torque/profiler.js
Normal 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
272
lib/torque/provider.json.js
Normal 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);
|
234
lib/torque/provider.jsonarray.js
Normal file
234
lib/torque/provider.jsonarray.js
Normal 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);
|
47
lib/torque/renderer/cartocss_render.js
Normal file
47
lib/torque/renderer/cartocss_render.js
Normal 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);
|
138
lib/torque/renderer/point.js
Normal file
138
lib/torque/renderer/point.js
Normal 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);
|
163
lib/torque/renderer/rectangle.js
Normal file
163
lib/torque/renderer/rectangle.js
Normal 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
38
lib/torque/request.js
Normal 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
31
lib/underscore-min.js
vendored
@ -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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),
|
||||
function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+
|
||||
u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]=
|
||||
function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=
|
||||
true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);
|
2766
lib/wax.g.js
2766
lib/wax.g.js
File diff suppressed because it is too large
Load Diff
27
package.json
Normal file
27
package.json
Normal 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"
|
||||
}
|
||||
}
|
@ -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];
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
383
src/torque.js
383
src/torque.js
@ -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];
|
||||
}
|
1
test/data/torque.array.json
Normal file
1
test/data/torque.array.json
Normal file
File diff suppressed because one or more lines are too long
15
test/provider.jsonarray.js
Normal file
15
test/provider.jsonarray.js
Normal 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
18
test/suite.html
Normal 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
244
test/vendor/qunit.css
vendored
Normal 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
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
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
235
vendor/leaflet.carto.js
vendored
Normal 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
467
vendor/leaflet.css
vendored
Normal 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
8909
vendor/leaflet.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1059
vendor/underscore.js
vendored
Normal file
1059
vendor/underscore.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user