basic connector + example

This commit is contained in:
Dani Carrion 2015-06-23 17:40:00 +02:00
parent be7046e5a0
commit 4d1cf96853
5 changed files with 300 additions and 2 deletions

87
examples/csv.html Normal file
View File

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="vendor/leaflet.css"/>
<style>
#map, html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<input type="file" id="files" name="files" />
<div id="map"></div>
<script src="vendor/leaflet.js"></script>
<script src="vendor/papaparse.min.js"></script>
<script src="../dist/torque.full.uncompressed.js"></script>
<script>
var map = new L.Map('map', {
zoomControl: true,
center: [40, -100],
zoom: 3
});
L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>'
}).addTo(map);
var CARTOCSS = [
'Map {',
'-torque-time-attribute: "date";',
'-torque-aggregation-function: "count(cartodb_id)";',
'-torque-frame-count: 1000;',
'-torque-animation-duration: 200;',
'-torque-resolution: 2',
'}',
'#layer {',
' marker-width: 3;',
' marker-fill-opacity: 0.8;',
' marker-fill: #FEE391; ',
' comp-op: "lighten";',
' [value > 10] { marker-fill: #FEC44F; }',
' [value > 20] { marker-fill: #CC4C02; }',
' [value > 30] { marker-fill: #662506; }',
' [frame-offset = 1] { marker-width: 10; marker-fill-opacity: 0.05;}',
' [frame-offset = 2] { marker-width: 15; marker-fill-opacity: 0.02;}',
'}'
].join('\n');
var torqueLayer = new L.TorqueLayer({
provider: 'internal',
resolution: 4,
start: 0,
end_date: 999,
step: 1,
steps: 1000,
countby: 'count(amount)',
pixel_size: 3,
cartocss: CARTOCSS
});
torqueLayer.addTo(map);
function handleFileSelect(evt) {
var file = evt.target.files[0];
Papa.parse(file, {
complete: function (results) {
for (var i = 1; i <= 1000; i++) {
var point = results.data[i];
torqueLayer.provider.addPoint(point[1], point[0], point[3], point[2]);
}
torqueLayer.provider.setReady();
torqueLayer.play();
}
});
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
</body>
</html>

6
examples/vendor/papaparse.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,8 @@ L.TorqueLayer = L.CanvasLayer.extend({
providers: {
'sql_api': torque.providers.json,
'url_template': torque.providers.JsonArray,
'windshaft': torque.providers.windshaft
'windshaft': torque.providers.windshaft,
'internal': torque.providers.internal
},
renderers: {

View File

@ -1,5 +1,6 @@
module.exports = {
json: require('./json'),
JsonArray: require('./jsonarray'),
windshaft: require('./windshaft')
windshaft: require('./windshaft'),
internal: require('./internal')
};

View File

@ -0,0 +1,203 @@
var torque = require('../');
/** Converts numeric degrees to radians */
Number.prototype.toRad = function () {
return this * Math.PI / 180;
};
var internal = function (options) {
this.setReady(false);
this.options = options;
this.points = [];
this._tileQueue = [];
};
internal.prototype = {
addPoint: function (lat, lon, time, value) {
this.points.push({lat: parseFloat(lat), lon: parseFloat(lon), time: parseInt(time), value: parseFloat(value)});
},
getBounds: function() {
return this.options.bounds;
},
setReady: function (ready) {
if (ready == false) {
this._ready = false;
} else {
this._ready = true;
this._processQueue();
this.options.ready && this.options.ready();
}
},
getTileData: function (coord, zoom, callback) {
if(!this._ready) {
this._tileQueue.push([coord, callback]);
} else {
this._getTileData(coord, callback);
}
},
_getTileData: function (tile, callback) {
this.prepareTile(tile);
var pointsInTile = this.getPointsInTile(tile);
callback(this.processTile(tile, pointsInTile));
},
_processQueue: function() {
var item;
while (item = this._tileQueue.pop()) {
this._getTileData.apply(this, item);
}
},
prepareTile: function (tile) {
/* Calculate tile bounds in lat/lon */
var bounds = tileBoundsInMeters(tile.zoom, tile.x, tile.y);
var mins = metersToLatLon(bounds[0]);
var maxs = metersToLatLon(bounds[1]);
tile.latLonBounds = {
minLat: mins[1],
maxLat: maxs[1],
minLon: mins[0],
maxLon: maxs[0]
};
/* Function to find out if a point falls into this tile */
tile.contains = function (point) {
return point.lat < tile.latLonBounds.maxLat && point.lat > tile.latLonBounds.minLat && point.lon < tile.latLonBounds.maxLon && point.lon > tile.latLonBounds.minLon;
}
},
/*
* Get the all the data points, no matter their timestamp, that fall into the tile
*/
getPointsInTile: function (tile) {
var pointsInTile = [];
for (var i = 0; i < this.points.length; i++) {
if (tile.contains(this.points[i])) {
pointsInTile.push(this.points[i]);
}
}
return pointsInTile;
},
processTile: function (tile, pointsInTile) {
/*
* For each this.points[i], x[i] and y[i] are the offsets in pixels from the tile boundaries.
*/
var x = [];
var y = [];
/*
* timeSlots:
*/
var timeSlots = {};
var timeCount = [];
var timeIndex = [];
var renderData = [];
var renderDataPos = [];
for (var pointIdx = 0; pointIdx < pointsInTile.length; pointIdx++) {
var point = pointsInTile[pointIdx];
var tileXY = latLonToTileXY(point.lat, point.lon, tile.latLonBounds);
x[pointIdx] = tileXY.x;
y[pointIdx] = tileXY.y;
var timeSlot = timeSlots[point.time] || (timeSlots[point.time] = []);
timeSlot.push([pointIdx, point.value]);
}
var times = Object.keys(timeSlots);
var maxTime = times && times.length ? times[times.length - 1] : null;
var renderDataIndex = 0;
var timeSlotIndex = 0;
for (var timestamp = 0; timestamp <= maxTime; ++timestamp) {
timeSlot = timeSlots[timestamp];
if (timeSlot) {
for (var pointInTimeSlotIdx = 0; pointInTimeSlotIdx < timeSlot.length; pointInTimeSlotIdx++) {
var pointInTimeSlot = timeSlot[pointInTimeSlotIdx];
renderDataPos[renderDataIndex] = pointInTimeSlot[0];
renderData[renderDataIndex] = pointInTimeSlot[1];
++renderDataIndex;
}
}
timeIndex[timestamp] = timeSlotIndex;
var increase = timeSlot ? timeSlot.length : 0;
timeCount[timestamp] = increase;
timeSlotIndex += increase;
}
return {
x: x,
y: y,
z: tile.zoom,
coord: {
x: tile.x,
y: tile.y,
z: tile.zoom
},
timeCount: timeCount,
timeIndex: timeIndex,
renderDataPos: renderDataPos,
renderData: renderData,
maxDate: maxTime
};
},
getKeySpan: function () {
return {
start: this.options.start * 1000,
end: this.options.end * 1000,
step: this.options.step,
steps: this.options.steps,
columnType: this.options.is_time ? 'date': 'number'
};
},
getSteps: function () {
return Math.min(this.options.steps, this.options.steps);
}
};
function metersToLatLon(coord) {
var lon = (coord[0] / (2 * Math.PI * 6378137 / 2.0)) * 180.0;
var lat = (coord[1] / (2 * Math.PI * 6378137 / 2.0)) * 180.0;
lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180.0)) - Math.PI / 2.0);
return [lon, lat]
}
function tileBoundsInMeters(z, x, y) {
var mins = pixelsToMeters(z, x * 256, (y + 1) * 256);
var maxs = pixelsToMeters(z, (x + 1) * 256, y * 256);
return [mins, maxs];
}
function pixelsToMeters(z, x, y) {
var res = (2 * Math.PI * 6378137 / 256) / (Math.pow(2, z));
var mx = x * res - (2 * Math.PI * 6378137 / 2.0);
var my = y * res - (2 * Math.PI * 6378137 / 2.0);
my = -my;
return [mx, my];
}
/*
* Convert lat and lon into pixels offsets inside the tile
*/
function latLonToTileXY(lat, lon, latLonBounds) {
return {
x: parseInt(256 * (lon - latLonBounds.minLon) / (latLonBounds.maxLon - latLonBounds.minLon)),
y: parseInt(256 * (lat - latLonBounds.minLat) / (latLonBounds.maxLat - latLonBounds.minLat))
};
}
module.exports = internal;