Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First commit

  • Loading branch information...
commit 5d35783a47754ce08a7a890494dc7b58d96747c2 0 parents
@glennblock authored
BIN  .DS_Store
Binary file not shown
9 .gitignore
@@ -0,0 +1,9 @@
+node_modules/
+*.suo
+*.user
+projects/VS/*.XML
+projects/VS/_ReSharper*
+projects/VS/obj/
+projects/VS/bin/
+projects/Eclipse
+targets/*
127 client.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>My Simple Map Application</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
+ <script src="http://code.jquery.com/jquery-latest.js"></script>
+ <script type="text/javascript" src="/socket.io/socket.io.js"></script>
+ <script type="text/javascript">
+ var socket = io.connect('http://localhost:81');
+
+ var map = null;
+ var pushpins = [];
+ var newPushpin = null;
+
+ function getMap() {
+ map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
+ credentials: 'ArK42x5AOoN5uQkM9A66F01WbTgO7vYt3aCx3_JiOjAcDi8u8ETbxL0kppWWnag4',
+ center: new Microsoft.Maps.Location(47.6, -122.2),
+ zoom: 8
+ });
+
+ // add click event handler
+ Microsoft.Maps.Events.addHandler(map, 'click', addPushpinOnMapClick);
+
+ // add socket io add pushpin events
+ socket.on('addPushpin', function (pushpinData) {
+ var exists = false;
+ for (var i = pushpins; i < pushpins.length; i++) {
+ if (pushpinData.name === pushpins[i].name) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (!exists) {
+ pushpins.push(pushpinData);
+ addPushpin(pushpinData);
+ }
+ });
+
+ socket.on('removePushpin', function (point) {
+ for (var i = map.entities.getLength() - 1; i >= 0; i--) {
+ if (map.entities.get(i).getLocation().latitude === point.latitude &&
+ map.entities.get(i).getLocation().longitude === point.longitude) {
+ map.entities.removeAt(i);
+ break;
+ }
+ }
+ });
+ }
+
+ function addPushpinOnMapClick(e) {
+ if (e.targetType == "map") {
+ var point = new Microsoft.Maps.Point(e.getX(), e.getY());
+ var loc = e.target.tryPixelToLocation(point);
+ addPushpin(loc, true);
+ }
+ }
+
+ function addPushpin(location, isNew) {
+ if (newPushpin) {
+ map.entities.remove(newPushpin);
+ newPushpin = null;
+ }
+
+ // create temporary pushpin
+ newPushpin = new Microsoft.Maps.Pushpin(location, null);
+ map.entities.push(newPushpin);
+ Microsoft.Maps.Events.addHandler(newPushpin, 'click', showPushpinInfo);
+
+ clearFormData();
+ if (isNew) {
+ // enable
+ $("#pushpinData").removeAttr('disabled');
+ } else {
+ newPushpin = null;
+ }
+ }
+
+ function showPushpinInfo(e) {
+ if (e.targetType == "pushpin") {
+ var pushpin = e.target;
+ for (var i = 0; i < pushpins.length; i++) {
+ if (pushpin.getLocation().latitude === pushpins[i].latitude &&
+ pushpin.getLocation().longitude === pushpins[i].longitude) {
+
+ $("#pushpinName").val(pushpins[i].name);
+ break;
+ }
+ }
+ }
+ }
+
+ function cancelPushpin() {
+ map.entities.remove(newPushpin);
+ clearFormData();
+ }
+
+ function clearMap() {
+ map.entities.clear();
+ socket.emit('clear', null);
+ }
+
+ function clearFormData() {
+ $("#pushpinName").val('');
+ $("#pushpinData").attr('disabled', 'disabled');
+ }
+ </script>
+ </head>
+ <body onload="getMap();">
+ <div id="main">
+ <div id='myMap' style="display:block; position:absolute; top:0; left:0; width:80%; height:90%;"></div>
+ <div id="pushpinData" style="padding:0 10px; display:block; position:absolute; top:0; left:80%; width:20%; height:90%;">
+ <form action="create" enctype="multipart/form-data" method="post">
+ <p><br />Name:<input id="pushpinName" name="pushpinName" type="text" size="25" maxlength="30" value="Enter Name"/></p>
+ <p><br />Image:<input id="pushpinFile" type="file" name="pushpinFile" /></p>
+ <input type="submit" value="Save" />
+ <input type="button" onclick="cancelPushpin()" value="Cancel" />
+ </form>
+ </div>
+ </div>
+ <div id='bottom' style="display:block; position:absolute; top:90%; left:0; width:100%; height:10%;">
+ <input type="button" value="Clear" onclick="clearMap()" />
+ </div>
+ </body>
+</html>
11 package.json
@@ -0,0 +1,11 @@
+{
+ "name": "geophoto"
+ , "version": "0.0.1"
+ , "dependencies": {
+ "azure": ">= 0.5.1"
+ , "express": "2.5.1"
+ , "ejs": ">= 0.0.1"
+ , "socket.io": "0.8.7"
+ , "node-uuid": ">= 1.3.3"
+ }
+}
115 pushpinService.js
@@ -0,0 +1,115 @@
+var azure = require('azure')
+ , uuid = require('node-uuid')
+ , ServiceClient = azure.ServiceClient;
+module.exports = PushpinService;
+
+var TABLE_NAME = 'pushpins';
+var CONTAINER_NAME = 'pushpins';
+
+function PushpinService(tableClient, blobClient) {
+ this.tableClient = tableClient;
+ this.blobClient = blobClient;
+};
+
+PushpinService.createPushpinService = function (callback) {
+
+ //var tableClient = azure.createTableService(ServiceClient.DEVSTORE_STORAGE_ACCOUNT, ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY, ServiceClient.DEVSTORE_TABLE_HOST);
+ //var blobClient = azure.createBlobService(azure.ServiceClient.DEVSTORE_STORAGE_ACCOUNT, azure.ServiceClient.DEVSTORE_STORAGE_ACCESS_KEY, azure.ServiceClient.DEVSTORE_BLOB_HOST).withFilter(new azure.ExponentialRetryPolicyFilter());
+
+ var tableClient = azure.createTableService("nodesummitworkshop", "Ta+1p/19QrOPbsRl0eNzGyxd7Ths0Qp2qpNyob8FyERIBhzbsFtPgn70RdAmrUJsDrYbTX2DJwEzZ8syRNw/Xg==");
+ var blobClient = azure.createBlobService("nodesummitworkshop", "Ta+1p/19QrOPbsRl0eNzGyxd7Ths0Qp2qpNyob8FyERIBhzbsFtPgn70RdAmrUJsDrYbTX2DJwEzZ8syRNw/Xg==").withFilter(new azure.ExponentialRetryPolicyFilter());
+
+ var pushpinService = new PushpinService(tableClient, blobClient);
+
+ // create table if it doesnt exist
+ tableClient.createTableIfNotExists(TABLE_NAME, function (error) {
+ if (error) {
+ throw error;
+ } else {
+ // create blob container if it doesnt exist
+ blobClient.createContainerIfNotExists(CONTAINER_NAME, function (error2) {
+ if (error2) {
+ throw error2;
+ } else {
+ // set blob container public
+ blobClient.setContainerAcl(CONTAINER_NAME, azure.Constants.BlobConstants.BlobContainerPublicAccessType.BLOB, function (error1) {
+ if (error1) {
+ throw error1;
+ } else {
+ callback(pushpinService);
+ }
+ });
+ }
+ });
+ }
+ });
+};
+
+PushpinService.prototype = {
+ showPushpins: function (req, res) {
+ res.render('index');
+ },
+
+ getPushpins: function (callback) {
+ var self = this;
+
+ var tableQuery = azure.TableQuery
+ .select()
+ .from(TABLE_NAME);
+
+ self.tableClient.queryEntities(tableQuery, function (err, pushpins) {
+ for (var i = 0; i < pushpins.length; i++) {
+ pushpins[i].imageUrl = self.blobClient.getBlobUrl(CONTAINER_NAME, pushpins[i].RowKey).url();
+ }
+
+ callback(err, pushpins);
+ });
+ },
+
+ clearPushpins: function (callback) {
+ var self = this;
+ var tableQuery = azure.TableQuery
+ .select()
+ .from(TABLE_NAME);
+
+ self.tableClient.queryEntities(tableQuery, function (err, entities) {
+ for (var entity in entities) {
+ self.tableClient.deleteEntity(TABLE_NAME, entities[entity], callback);
+ }
+ });
+ },
+
+ newPushpin: function (req, res) {
+ var self = this;
+
+ var createPushpin = function () {
+ var pushpin = req.body;
+ pushpin.RowKey = uuid();
+ pushpin.PartitionKey = 'locations';
+
+ self.tableClient.insertEntity(TABLE_NAME, pushpin, function (error) {
+ if (error) {
+ console.log(error);
+ throw error;
+ }
+
+ console.log('pushpin created, uploading photo.');
+ var options = {
+ contentType: req.files.pushpinFile.type,
+ metadata: { fileName: pushpin.RowKey }
+ };
+
+ self.blobClient.createBlockBlobFromFile(CONTAINER_NAME, pushpin.RowKey, req.files.pushpinFile.path, options, function (error1, blockBlob) {
+ if (error1) {
+ throw error;
+ } else {
+ console.log(JSON.stringify(blockBlob));
+ res.redirect('/');
+ }
+ });
+ });
+ };
+
+ createPushpin();
+ }
+};
55 server.js
@@ -0,0 +1,55 @@
+/**
+* Module dependencies.
+*/
+
+var express = require('express')
+ , PushpinService = require('./pushpinService')
+ , azure = require('azure')
+ , socketio = require('socket.io');
+
+var app = module.exports = express.createServer();
+
+PushpinService.createPushpinService(function (pushpinService) {
+ // Configuration
+
+ app.configure(function () {
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'ejs');
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(app.router);
+ app.use(express.static(__dirname + '/public'));
+ });
+
+ app.configure('development', function () {
+ app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+ });
+
+ app.configure('production', function () {
+ app.use(express.errorHandler());
+ });
+
+ // Routes
+ app.get('/', pushpinService.showPushpins.bind(pushpinService));
+ app.post('/create', pushpinService.newPushpin.bind(pushpinService));
+
+ app.listen(process.env.PORT || 1337);
+ console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
+
+ var io = socketio.listen(app);
+
+ io.sockets.on('connection', function (socket) {
+ // get list of pushpins from the table and emit events for each of them
+ pushpinService.getPushpins(function (err, entities) {
+ for (var entity in entities) {
+ socket.emit('addPushpin', entities[entity]);
+ }
+ });
+
+ socket.on('clear', function () {
+ pushpinService.clearPushpins(function () {
+ socket.emit('clear');
+ });
+ });
+ });
+});
0  views/index.ejs
No changes.
159 views/layout.ejs
@@ -0,0 +1,159 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+ <head>
+ <title>My Simple Map Application</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
+ <script src="http://code.jquery.com/jquery-latest.js"></script>
+ <script type="text/javascript" src="/socket.io/socket.io.js"></script>
+ <script type="text/javascript">
+ var socket = io.connect('http://localhost:1337');
+
+ var map = null;
+ var pushpins = [];
+ var newPushpin = null;
+ var currentPushpinInfobox = null;
+
+ function getMap() {
+ map = new Microsoft.Maps.Map(document.getElementById('myMap'), {
+ credentials: 'ArK42x5AOoN5uQkM9A66F01WbTgO7vYt3aCx3_JiOjAcDi8u8ETbxL0kppWWnag4',
+ center: new Microsoft.Maps.Location(47.6, -122.2),
+ zoom: 8
+ });
+
+ // add click event handler
+ Microsoft.Maps.Events.addHandler(map, 'click', addPushpinOnMapClick);
+
+ // add socket io add pushpin events
+ socket.on('addPushpin', function (pushpinData) {
+ var exists = false;
+ for (var i = pushpins; i < pushpins.length; i++) {
+ if (pushpinData.name === pushpins[i].name) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (!exists) {
+ pushpins.push(pushpinData);
+ addPushpin(pushpinData);
+ }
+ });
+
+ socket.on('removePushpin', function (point) {
+ for (var i = map.entities.getLength() - 1; i >= 0; i--) {
+ if (map.entities.get(i).getLocation().latitude === point.latitude &&
+ map.entities.get(i).getLocation().longitude === point.longitude) {
+ map.entities.removeAt(i);
+ break;
+ }
+ }
+ });
+
+ socket.on('clear', function () {
+ map.entities.clear();
+ });
+ }
+
+ function addPushpinOnMapClick(e) {
+ if (e.targetType == "map") {
+ var point = new Microsoft.Maps.Point(e.getX(), e.getY());
+ var loc = e.target.tryPixelToLocation(point);
+ addPushpin(loc, true);
+ }
+ }
+
+ function addPushpin(location, isNew) {
+ if (newPushpin) {
+ map.entities.remove(newPushpin);
+ newPushpin = null;
+ }
+
+ if (currentPushpinInfobox) {
+ map.entities.remove(currentPushpinInfobox);
+ currentPushpinInfobox = null;
+ }
+
+ // create temporary pushpin
+ newPushpin = new Microsoft.Maps.Pushpin(location, null);
+ map.entities.push(newPushpin);
+ Microsoft.Maps.Events.addHandler(newPushpin, 'click', showPushpinInfo);
+
+ clearFormData();
+ if (isNew) {
+ // enable
+ $("#latitude").val(newPushpin.getLocation().latitude);
+ $("#longitude").val(newPushpin.getLocation().longitude);
+ $("#pushpinData").removeAttr('disabled');
+ } else {
+ newPushpin = null;
+ }
+ }
+
+ function showPushpinInfo(e) {
+ if (newPushpin) {
+ map.entities.remove(newPushpin);
+ newPushpin = null;
+ }
+
+ if (e.targetType == "pushpin") {
+ var pushpin = e.target;
+ for (var i = 0; i < pushpins.length; i++) {
+ if (pushpin.getLocation().latitude === pushpins[i].latitude &&
+ pushpin.getLocation().longitude === pushpins[i].longitude) {
+
+ if (currentPushpinInfobox) {
+ map.entities.remove(currentPushpinInfobox);
+ currentPushpinInfobox = null;
+ }
+
+ var infoboxOptions = {
+ title: pushpins[i].name,
+ width: 200,
+ height: 200,
+ description: '<img src="' + pushpins[i].imageUrl + '" width="70px" />',
+ offset: new Microsoft.Maps.Point(0, 40) };
+ currentPushpinInfobox = new Microsoft.Maps.Infobox(pushpin.getLocation(), infoboxOptions);
+ map.entities.push(currentPushpinInfobox);
+
+ break;
+ }
+ }
+ }
+ }
+
+ function cancelPushpin() {
+ map.entities.remove(newPushpin);
+ clearFormData();
+ }
+
+ function clearMap() {
+ map.entities.clear();
+ socket.emit('clear', null);
+ }
+
+ function clearFormData() {
+ $("#pushpinName").val('');
+ $("#pushpinData").attr('disabled', 'disabled');
+ }
+ </script>
+ </head>
+ <body onload="getMap();">
+ <div id="main">
+ <div id='myMap' style="display:block; position:absolute; top:0; left:0; width:80%; height:90%;"></div>
+ <div id="pushpinData" style="padding:0 10px; display:block; position:absolute; top:0; left:80%; width:20%; height:90%;">
+ <form action="create" enctype="multipart/form-data" method="post">
+ <p><br />Name:<input id="pushpinName" name="name" type="text" size="25" maxlength="30" value="Enter Name"/></p>
+ <p><br />Image:<input id="pushpinFile" type="file" name="pushpinFile" /></p>
+ <input type="hidden" id="latitude" name="latitude" value="" />
+ <input type="hidden" id="longitude" name="longitude" value="" />
+ <input type="submit" value="Save" />
+ <input type="button" onclick="cancelPushpin()" value="Cancel" />
+ </form>
+ </div>
+ </div>
+ <div id='bottom' style="display:block; position:absolute; top:90%; left:0; width:100%; height:10%;">
+ <input type="button" value="Clear" onclick="clearMap()" />
+ </div>
+ </body>
+</html>
Please sign in to comment.
Something went wrong with that request. Please try again.