278 lines
8 KiB
JavaScript
278 lines
8 KiB
JavaScript
window.app = (function() {
|
|
var that = {},
|
|
coords,
|
|
foundLocation = false,
|
|
map,
|
|
marker,
|
|
username = localStorage.username || 'Anonymous',
|
|
color = randomColor(),
|
|
userlist,
|
|
users = [],
|
|
zoomLevel = 23;
|
|
|
|
window.onload = setup();
|
|
document.body && window.onload();
|
|
|
|
function createUser(data) {
|
|
var user = {
|
|
id: data.id,
|
|
name: data.name,
|
|
color: data.color,
|
|
};
|
|
if (!user.color) {
|
|
user.color = [255, 0, 0];
|
|
}
|
|
users.push(user);
|
|
if(coords) {
|
|
update({
|
|
name: username,
|
|
color: color,
|
|
coords: coords
|
|
});
|
|
}
|
|
updateUserList();
|
|
return user;
|
|
}
|
|
|
|
function getUserById(id) {
|
|
return users.filter(function(user) {
|
|
return user.id == id;
|
|
})[0];
|
|
}
|
|
|
|
function initMap() {
|
|
navigator.geolocation.watchPosition(updateLocation, locationError, {
|
|
enableHighAccuracy: true
|
|
});
|
|
}
|
|
|
|
function joinRoom(room) {
|
|
if(that.room) {
|
|
post(['leave', that.room]);
|
|
}
|
|
users.forEach(function(user) {
|
|
if (user.marker) {
|
|
map.removeLayer(user.marker);
|
|
}
|
|
});
|
|
users = [];
|
|
that.room = room;
|
|
post(['join', that.room]);
|
|
if (coords) {
|
|
update({
|
|
name: username,
|
|
coords: coords
|
|
});
|
|
} else {
|
|
initMap();
|
|
}
|
|
updateUserList();
|
|
}
|
|
|
|
function locationError(err) {
|
|
console.log(err);
|
|
}
|
|
|
|
function post(data) {
|
|
that.ws.send(JSON.stringify(data));
|
|
}
|
|
|
|
function randomColor() {
|
|
var colors = [
|
|
[128, 0, 0],
|
|
[0, 128, 0],
|
|
[0, 0, 128],
|
|
[128, 128, 0],
|
|
[0, 128, 128],
|
|
[128, 0, 128],
|
|
[128, 64, 0],
|
|
[64, 128, 0],
|
|
[0, 128, 64],
|
|
[0, 64, 128],
|
|
[64, 0, 128],
|
|
[128, 0, 64]
|
|
];
|
|
return colors[Math.floor(Math.random() * 12)];
|
|
}
|
|
|
|
function randomName() {
|
|
var name = '';
|
|
while(name.length < 14) {
|
|
name += String.fromCharCode('A'.charCodeAt(0) + Math.floor(Math.random() * 25));
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function removeUser(id) {
|
|
var user = getUserById(id);
|
|
if (user) {
|
|
if (user.marker) {
|
|
map.removeLayer(user.marker);
|
|
}
|
|
users = users.filter(function(user) {
|
|
user.id != id;
|
|
});
|
|
}
|
|
}
|
|
|
|
function setup() {
|
|
var host = (document.location.protocol == 'http:' ? 'ws' : 'wss') + '://' + document.location.host;
|
|
that.ws = new WebSocket(host + '/ws');
|
|
that.ws.onopen = function () {
|
|
window.onhashchange = function() {
|
|
var name = document.location.hash.slice(1);
|
|
if (name) {
|
|
document.title = '#' + name;
|
|
joinRoom(name);
|
|
} else {
|
|
document.location.href = '#' + randomName();
|
|
}
|
|
}
|
|
window.onhashchange();
|
|
};
|
|
that.ws.onmessage = function (event) {
|
|
var data = JSON.parse(event.data);
|
|
if (data[0] == 'leave') {
|
|
removeUser(data[1]);
|
|
} else if (data[0] == 'update') {
|
|
data[2].id = data[1];
|
|
updateUserLocation(data[2]);
|
|
}
|
|
};
|
|
that.ws.onclose = function (event) {
|
|
setTimeout(function() {
|
|
setup();
|
|
}, 1000);
|
|
};
|
|
}
|
|
|
|
function update(data) {
|
|
post(['update', that.room, data]);
|
|
}
|
|
|
|
function updateLocation(loc) {
|
|
coords = [loc.coords.latitude, loc.coords.longitude];
|
|
var options = {
|
|
title: username,
|
|
icon: L.icon({
|
|
iconUrl: MarkerIcon({
|
|
label: username[0],
|
|
color: [255, 255, 255],
|
|
background: color
|
|
})
|
|
})
|
|
};
|
|
if (!foundLocation) {
|
|
if (!map) {
|
|
L.mapbox.accessToken = config.mapboxAccessToken;
|
|
map = L.mapbox.map('map', 'mapbox.streets')
|
|
.setView(coords, zoomLevel);
|
|
}
|
|
marker = L.marker(coords, options)
|
|
.bindPopup(options.title)
|
|
.addTo(map);
|
|
map.setView(coords, zoomLevel);
|
|
foundLocation = true;
|
|
updateUserList();
|
|
} else {
|
|
map.removeLayer(marker);
|
|
marker = L.marker(coords, options)
|
|
.bindPopup(options.title)
|
|
.addTo(map);
|
|
}
|
|
update({
|
|
name: username,
|
|
coords: coords
|
|
});
|
|
}
|
|
|
|
function updateUserLocation(data) {
|
|
var user = getUserById(data.id);
|
|
if (!user) {
|
|
user = createUser(data);
|
|
}
|
|
user.coords = data.coords;
|
|
if (user.name != data.name) {
|
|
user.name = data.name;
|
|
updateUserList();
|
|
}
|
|
var options = {
|
|
title: user.name,
|
|
icon: L.icon({
|
|
iconUrl: MarkerIcon({
|
|
label: user.name[0],
|
|
background: user.color
|
|
})
|
|
})
|
|
};
|
|
if (user.marker) {
|
|
map.removeLayer(user.marker);
|
|
}
|
|
user.marker = L.marker(user.coords, options)
|
|
.bindPopup(user.name)
|
|
.addTo(map);
|
|
}
|
|
|
|
function updateUserList() {
|
|
var list = document.createElement('div');
|
|
list.id = 'users';
|
|
[{
|
|
name: username,
|
|
color: color
|
|
}].concat(users).forEach(function(user) {
|
|
var div = document.createElement('div');
|
|
div.className = 'person';
|
|
div.innerHTML = user.name;
|
|
div.style.background = 'rgb(' + user.color.join(', ') + ')';
|
|
div.style.top = '8px'
|
|
div.onclick = function() {
|
|
if (!user.id) {
|
|
var name = prompt("What is your name?", username) || 'Anonymous';
|
|
localStorage.username = username = name;
|
|
update({
|
|
name: username,
|
|
color: color,
|
|
coords: coords
|
|
});
|
|
updateUserList();
|
|
} else if (user.coords) {
|
|
map.setView(user.coords, zoomLevel);
|
|
}
|
|
}
|
|
list.appendChild(div);
|
|
});
|
|
if (userlist) {
|
|
document.body.replaceChild(list, userlist);
|
|
} else {
|
|
document.body.appendChild(list);
|
|
}
|
|
userlist = list;
|
|
}
|
|
|
|
function MarkerIcon(options) {
|
|
options = options || {};
|
|
options.background = options.background || [255, 0, 0];
|
|
options.color = options.color || [255, 255, 255];
|
|
options.label = options.label || 'A';
|
|
var size = 20;
|
|
var canvas = document.createElement('canvas')
|
|
canvas.setAttribute('width', size);
|
|
canvas.setAttribute('height', size);
|
|
var context = canvas.getContext('2d');
|
|
context.fillStyle = 'rgb(' + options.background.join(', ') + ')';
|
|
context.arc(size / 2, size / 2, size / 2 - 2, 0, 360);
|
|
context.fill();
|
|
context.beginPath();
|
|
context.lineWidth = 2;
|
|
context.strokeStyle = 'rgb(' + options.color.join(', ') + ')';
|
|
context.arc(size / 2, size / 2, size / 2 - 1, 0, 360);
|
|
context.stroke();
|
|
context.font = '14px sans-serif';
|
|
context.textAlign = 'center';
|
|
context.fillStyle = 'rgb(' + options.color.join(', ') + ')';
|
|
context.fillText(options.label, size / 2, size * 0.75);
|
|
return canvas.toDataURL();
|
|
}
|
|
|
|
return that;
|
|
})();
|