How to Hack a Road Trip with a Webcam, a GSP and Some Fun
NodeMTL.com
StreetView+ on the cheap
Pascal DeschenesTechnologist, Nu Echo Co-Founder
@pdeschenhttp://about.me/pdeschen
● Background● Base Modules● Geo Storage● Real-time Layer● Web Front● Demo
Outline
Background
Stop-motion movie of our Newfoundland summer road trip
Base Modules
Non-Blocking Webcam Frame Grabbing and Remote Controller
Camelot
var spawn = require('child_process').spawn;var arguments = [];arguments.push(foo);...var fswebcam = spawn('fswebcam', arguments);
fswebcam.stderr.on('data', function (data) { console.log('stdout: ' + data); });
fswebcam.on('exit', function (code) { ...});
Process Spawning
Non-Blocking GPS Daemon Client
Bancroft
var events = require('events');.../* tap into prototype chain */sys.inherits(Bancroft, events.EventEmitter);...var emitter = events.EventEmitter.call(this);...emitter.emit('location', self.location);...emitter.emit('error', error);
Event Emitting
var bancroft = new Bancroft();bancroft.on('connect', function () { console.log('connected');});bancroft.on('location', function (location) { console.log('got new location', location);});
Event Handling
Geo Storage
A high-level, caching, CouchDB client
Cradle
var Cradle = require('cradle');var cradle = new (Cradle.Connection)('http://127.0.0.1', 5984, {cache: false});
var db = cradle.database('kerouac');if (!db.exists()) {db.create();}
Init
var document = { timestamp : new Date().getTime(), location : bancroft.location};
db.save(uuid(), document, function (err, res) { console.log(res); db.saveAttachment(res.id, res.rev, 'frame', 'image/png', frame, function (err, data) { ... });});
Store
db.view('k/coordinates', function (err, rows) { rows.forEach(function (row) {console.log('deleting', row);db.remove(row.key._id, row.key._rev); });});
Delete
{ "_id": "ffdba8b3-e125-4b4e-98fe-0be027aaec40", "_rev": "2-43d3afdb1909626bc962e44612c57150", "timestamp": 1311513742115, "location": { "timestamp": 1311513742000, "latitude": 44.423216667, "longitude": -72.944055, "altitude": 194.7, "speed": 0, "geometries": { "type": "Point", "coordinates": [-72.944055, 44.423216667, 194.7] } }, "_attachments": { "frame": { "content_type": "image/png", "revpos": 2, "length": 142666, "stub": true } }}
Model
Real-time Layer
Sending binarymessages
Socket.IO
/* server side */io.sockets.volatile.emit('frame', { data : frame.toString('base64') });
/* client side */socket.on('frame', function (frame) { var img = $('#frame'); img.attr("src", 'data:image/png;base64,' + frame.data); });
Base64 Encoding
Web Front
app.get('/map', function (req, res) { res.render('map', { title : "Kerouac" });});
Express
<?xml version="1.0" encoding="UTF-8"?>kml(xmlns="http://earth.google.com/kml/2.1") Document name Newfoundland RoadTrip description A dynamically waypoint selection from an ongoing road trip Style(id="blueLine") LineStyle color red width 4 Placemark name Blue Line styleUrl #blueLine LineString altitudeMode relative coordinates - if (coordinates.length) - coordinates.forEach(function(coordinate) { =coordinate - })
Jade Templates
app.get('/status', function (req, res) { res.header('content-type', 'application/json');
var status = messaging.location;
db.view('kerouac/speed_mean', function (err, rows) {
if (rows[0]) { status['mean'] = rows[0].value.toFixed(2); } else { status['mean'] = 'n.a.'; }
var json = JSON.stringify(status); res.send(json); });});
REST Handling
Show Time
How to unit test event emission?
What about native c++ module?
What are the best practices regarding express.js code organization?
How to distribute Socket.io/Express behind a proxy?
Open Issuesfor an upcoming meet-up? volunteers?
Questions?
@pdeschen
http://nodejs.org/docs/v0.4.9/api/child_processes.htmlhttp://nodejs.org/docs/v0.4.9/api/events.htmlhttp://blog.rassemblr.com/tag/nodejs/https://github.com/pdeschen/camelothttps://github.com/pdeschen/bancrofthttps://github.com/cloudhead/cradlehttp://geojson.org/http://socket.io/http://expressjs.com/http://jade-lang.com/
References