Commit 74e671f7 authored by Corentin Mors's avatar Corentin Mors
Browse files

Try some OpenStreetMap Locations

parent f7d93bd3
// Setup basic express server
var express = require('express');
var app = express();
var path = require('path');
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 3000;
server.listen(port, () => {
console.log('Server listening at port %d', port);
});
// Routing
app.use(express.static(path.join(__dirname, 'public')));
// Chatroom
var numUsers = 0;
io.on('connection', (socket) => {
var addedUser = false;
// when the client emits 'new message', this listens and executes
socket.on('new message', (data) => {
// we tell the client to execute 'new message'
socket.broadcast.emit('new message', {
username: socket.username,
message: data
});
});
socket.on('geoloc', (data) => {
// we tell the client to execute 'new message'
console.log("Got data " + data + " from " + socket.username);
socket.broadcast.emit('geoloc', {
username: socket.username,
coordinates: data
});
});
// when the client emits 'add user', this listens and executes
socket.on('add user', (username) => {
if (addedUser) return;
// we store the username in the socket session for this client
socket.username = username;
++numUsers;
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
});
// when the client emits 'typing', we broadcast it to others
socket.on('typing', () => {
socket.broadcast.emit('typing', {
username: socket.username
});
});
// when the client emits 'stop typing', we broadcast it to others
socket.on('stop typing', () => {
socket.broadcast.emit('stop typing', {
username: socket.username
});
});
// when the user disconnects.. perform this
socket.on('disconnect', () => {
if (addedUser) {
--numUsers;
// echo globally that this client has left
socket.broadcast.emit('user left', {
username: socket.username,
numUsers: numUsers
});
}
});
});
\ No newline at end of file
var gulp = require('gulp'),
spawn = require('child_process').spawn,
node;
const build = ['server'];
/**
* $ gulp server
* description: launch the server. If there's a server already running, kill it
*/
gulp.task('server', function() {
if (node) node.kill()
node = spawn('node', ['app.js'], {stdio: 'inherit'})
node.on('close', function (code) {
if (code === 8) {
gulp.log('Error detected, waiting for changes...');
}
});
})
/**
* $ gulp
* description: start the development environment
*/
gulp.task('default', build, function() {
gulp.watch(['./app.js', './**/*.js', './**/*.html'], build);
});
// clean up if an error goes unhandled.
process.on('exit', function() {
if (node) node.kill()
})
\ No newline at end of file
This diff is collapsed.
{
"name": "onmap-server",
"version": "0.0.1",
"description": "A server side nodejs client for onMap system",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"cookie-parser": "~1.3.3",
"debug": "^4.1.0",
"express": "^4.16.4",
"socket.io": "^2.2.0"
}
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Socket.IO Chat Example</title>
<link rel="stylesheet" href="style.css">
<!-- OpenLayer CSS -->
<link href="/openlayer.min.css" rel="stylesheet">
</head>
<body>
<h2>Location Tracer</h2>
<div id="map" class="map"></div>
<div id="info" style="display: none;"></div>
<p>
Position accuracy : <code id="accuracy"></code>&nbsp;&nbsp;
Altitude : <code id="altitude"></code>&nbsp;&nbsp;
Altitude accuracy : <code id="altitudeAccuracy"></code>&nbsp;&nbsp;
Heading : <code id="heading"></code>&nbsp;&nbsp;
Speed : <code id="speed"></code>
</p>
<ul class="pages">
<li class="chat page">
<div class="chatArea">
<ul class="messages"></ul>
</div>
<input class="inputMessage" placeholder="Type here..."/>
</li>
<li class="login page">
<div class="form">
<h3 class="title">What's your nickname?</h3>
<input class="usernameInput" type="text" maxlength="14" />
</div>
</li>
</ul>
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="/openlayer.min.js"></script>
<script src="/main.js"></script>
</body>
</html>
\ No newline at end of file
var userPositions = [];
$(function() {
var FADE_TIME = 150; // ms
var TYPING_TIMER_LENGTH = 400; // ms
var COLORS = [
'#e21400', '#91580f', '#f8a700', '#f78b00',
'#58dc00', '#287b00', '#a8f07a', '#4ae8c4',
'#3b88eb', '#3824aa', '#a700ff', '#d300e7'
];
var socket = io();
// Initialize variables
var $window = $(window);
var $usernameInput = $('.usernameInput'); // Input for username
var $messages = $('.messages'); // Messages area
var $inputMessage = $('.inputMessage'); // Input message input box
var $loginPage = $('.login.page'); // The login page
var $chatPage = $('.chat.page'); // The chatroom page
// Prompt for setting a username
var username;
var connected = false;
var typing = false;
var lastTypingTime;
var $currentInput = $usernameInput.focus();
const addParticipantsMessage = (data) => {
var message = '';
if (data.numUsers === 1) {
message += "there's 1 participant";
} else {
message += "there are " + data.numUsers + " participants";
}
log(message);
}
// Sets the client's username
const setUsername = () => {
username = cleanInput($usernameInput.val().trim());
// If the username is valid
if (username) {
$loginPage.fadeOut();
$chatPage.show();
$loginPage.off('click');
$currentInput = $inputMessage.focus();
// Tell the server your username
socket.emit('add user', username);
}
}
// Sends a chat message
const sendMessage = () => {
var message = $inputMessage.val();
// Prevent markup from being injected into the message
message = cleanInput(message);
// if there is a non-empty message and a socket connection
if (message && connected) {
$inputMessage.val('');
addChatMessage({
username: username,
message: message
});
// tell server to execute 'new message' and send along one parameter
socket.emit('new message', message);
}
}
// Log a message
const log = (message, options) => {
var $el = $('<li>').addClass('log').text(message);
addMessageElement($el, options);
}
// Adds the visual chat message to the message list
const addChatMessage = (data, options) => {
// Don't fade the message in if there is an 'X was typing'
var $typingMessages = getTypingMessages(data);
options = options || {};
if ($typingMessages.length !== 0) {
options.fade = false;
$typingMessages.remove();
}
var $usernameDiv = $('<span class="username"/>')
.text(data.username)
.css('color', getUsernameColor(data.username));
var $messageBodyDiv = $('<span class="messageBody">')
.text(data.message);
var typingClass = data.typing ? 'typing' : '';
var $messageDiv = $('<li class="message"/>')
.data('username', data.username)
.addClass(typingClass)
.append($usernameDiv, $messageBodyDiv);
addMessageElement($messageDiv, options);
}
// Adds the visual chat typing message
const addChatTyping = (data) => {
data.typing = true;
data.message = 'is typing';
addChatMessage(data);
}
// Removes the visual chat typing message
const removeChatTyping = (data) => {
getTypingMessages(data).fadeOut(function () {
$(this).remove();
});
}
// Adds a message element to the messages and scrolls to the bottom
// el - The element to add as a message
// options.fade - If the element should fade-in (default = true)
// options.prepend - If the element should prepend
// all other messages (default = false)
const addMessageElement = (el, options) => {
var $el = $(el);
// Setup default options
if (!options) {
options = {};
}
if (typeof options.fade === 'undefined') {
options.fade = true;
}
if (typeof options.prepend === 'undefined') {
options.prepend = false;
}
// Apply options
if (options.fade) {
$el.hide().fadeIn(FADE_TIME);
}
if (options.prepend) {
$messages.prepend($el);
} else {
$messages.append($el);
}
$messages[0].scrollTop = $messages[0].scrollHeight;
}
// Prevents input from having injected markup
const cleanInput = (input) => {
return $('<div/>').text(input).html();
}
// Updates the typing event
const updateTyping = () => {
if (connected) {
if (!typing) {
typing = true;
socket.emit('typing');
}
lastTypingTime = (new Date()).getTime();
setTimeout(() => {
var typingTimer = (new Date()).getTime();
var timeDiff = typingTimer - lastTypingTime;
if (timeDiff >= TYPING_TIMER_LENGTH && typing) {
socket.emit('stop typing');
typing = false;
}
}, TYPING_TIMER_LENGTH);
}
}
// Gets the 'X is typing' messages of a user
const getTypingMessages = (data) => {
return $('.typing.message').filter(function (i) {
return $(this).data('username') === data.username;
});
}
// Gets the color of a username through our hash function
const getUsernameColor = (username) => {
// Compute hash code
var hash = 7;
for (var i = 0; i < username.length; i++) {
hash = username.charCodeAt(i) + (hash << 5) - hash;
}
// Calculate color
var index = Math.abs(hash % COLORS.length);
return COLORS[index];
}
// Keyboard events
$window.keydown(event => {
// Auto-focus the current input when a key is typed
if (!(event.ctrlKey || event.metaKey || event.altKey)) {
$currentInput.focus();
}
// When the client hits ENTER on their keyboard
if (event.which === 13) {
if (username) {
sendMessage();
socket.emit('stop typing');
typing = false;
} else {
setUsername();
}
}
});
$inputMessage.on('input', () => {
updateTyping();
});
// Click events
// Focus input when clicking anywhere on login page
$loginPage.click(() => {
$currentInput.focus();
});
// Focus input when clicking on the message input's border
$inputMessage.click(() => {
$inputMessage.focus();
});
// Socket events
// Whenever the server emits 'login', log the login message
socket.on('login', (data) => {
connected = true;
// Display the welcome message
var message = "Welcome to Socket.IO Chat – ";
log(message, {
prepend: true
});
addParticipantsMessage(data);
});
// Whenever the server emits 'new message', update the chat body
socket.on('new message', (data) => {
addChatMessage(data);
});
socket.on('geoloc', (data) => {
moveParticipantPoint(data);
});
// Whenever the server emits 'user joined', log it in the chat body
socket.on('user joined', (data) => {
log(data.username + ' joined');
addParticipantsMessage(data);
});
// Whenever the server emits 'user left', log it in the chat body
socket.on('user left', (data) => {
log(data.username + ' left');
addParticipantsMessage(data);
removeChatTyping(data);
removeParticipantPoint(data);
});
// Whenever the server emits 'typing', show the typing message
socket.on('typing', (data) => {
addChatTyping(data);
});
// Whenever the server emits 'stop typing', kill the typing message
socket.on('stop typing', (data) => {
removeChatTyping(data);
});
socket.on('disconnect', () => {
log('you have been disconnected');
});
socket.on('reconnect', () => {
log('you have been reconnected');
if (username) {
socket.emit('add user', username);
}
});
socket.on('reconnect_error', () => {
log('attempt to reconnect has failed');
});
var Map = ol.Map
var View = ol.View;
var TileLayer = ol.layer.Tile;
var OSM = ol.source.OSM;
var Feature = ol.Feature;
var Geolocation = ol.Geolocation;
var Point = ol.geom.Point;
var VectorSource = ol.source.Vector;
var VectorLayer = ol.layer.Vector;
var toStringXY = ol.coordinate.toStringXY;
var CircleStyle = ol.style.Circle, Fill = ol.style.Fill, Stroke = ol.style.Stroke, Style = ol.style.Style, Text = ol.style.Text;
var view = new View({
center: [0, 0],
zoom: 5
});
var map = new Map({
layers: [
new TileLayer({
source: new OSM()
})
],
target: 'map',
view: view
});
var geolocation = new Geolocation({
trackingOptions: {
enableHighAccuracy: true
},
projection: view.getProjection()
});
function el(id) {
return document.getElementById(id);
}
geolocation.setTracking(true);
// update the HTML page when the position changes.
geolocation.on('change', function() {
el('accuracy').innerText = geolocation.getAccuracy() + ' [m]';
el('altitude').innerText = geolocation.getAltitude() + ' [m]';
el('altitudeAccuracy').innerText = geolocation.getAltitudeAccuracy() + ' [m]';
el('heading').innerText = geolocation.getHeading() + ' [rad]';
el('speed').innerText = geolocation.getSpeed() + ' [m/s]';
});
// handle geolocation error.
geolocation.on('error', function(error) {
var info = document.getElementById('info');
info.innerHTML = error.message;
info.style.display = '';
});
var accuracyFeature = new Feature();
geolocation.on('change:accuracyGeometry', function() {
accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
map.getView().setCenter(geolocation.getPosition());
});
var positionFeature = new Feature();
positionFeature.setStyle(new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#3399CC'
}),
stroke: new Stroke({
color: '#fff',
width: 2
})
})
}));
// var positionFeature2 = new Feature();
// positionFeature2.setStyle(new Style({
// image: new CircleStyle({
// radius: 6,
// fill: new Fill({
// color: '#287b00'
// }),
// stroke: new Stroke({
// color: '#fff',
// width: 2
// })
// })
// }));
// var coord = [7.85, 47.983333];
// var out = ol.coordinate.toStringXY(coord, 1);
const urlParams = new URLSearchParams(window.location.search);
username = urlParams.get('u');
socket.emit('add user', username);
socket.emit('geoloc', [7.85, 47.983333]);
geolocation.on('change:position', function() {
var coordinates = geolocation.getPosition();
positionFeature.setGeometry(coordinates ?
new Point(coordinates) : null);
socket.emit('geoloc', coordinates);
});
var mylayer = new VectorLayer({
map: map,
source: new VectorSource({
features: [accuracyFeature, positionFeature]
})
});
//mylayer.getSource().addFeature(positionFeature2);
function moveParticipantPoint(data){
console.log("Got data " + data.coordinates + " from " + data.username);
userPositions[data.username] = new Feature();
userPositions[data.username].setStyle(new Style({
image: new CircleStyle({
radius: 6,
fill: new Fill({
color: '#ec0a0a'
}),
stroke: new Stroke({
color: '#fff',
width: 2
})
})
}));
userPositions[data.username].setGeometry(data.coordinates ?
new Point(data.coordinates) : null);
mylayer.getSource().addFeature(userPositions[data.username]);