2019-05-14 15:56:43 +00:00
|
|
|
var ws = new ReconnectingWebSocket( window.location.origin.replace('http', 'ws') +'/ws', null, { debug: false, reconnectInterval: 3000 } );
|
2019-04-25 17:08:27 +00:00
|
|
|
|
2019-11-11 19:34:33 +00:00
|
|
|
var seeme = true;
|
2019-11-28 17:00:26 +00:00
|
|
|
var tl ;
|
2019-11-11 19:34:33 +00:00
|
|
|
|
|
|
|
var error_audio = new Audio('siren.wav');
|
|
|
|
var playSoundOnError = true;
|
|
|
|
var checkbox_sound = document.getElementById('play_sound_on_error')
|
2019-11-12 08:54:55 +00:00
|
|
|
if(checkbox_sound != null) {
|
|
|
|
checkbox_sound.addEventListener('change', (event) => {
|
|
|
|
if (event.target.checked) {
|
|
|
|
playSoundOnError = true;
|
|
|
|
} else {
|
|
|
|
playSoundOnError = false;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-08-29 08:15:33 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
//request close before unloading
|
|
|
|
window.addEventListener('beforeunload', function(){
|
|
|
|
ws.close();
|
|
|
|
});
|
|
|
|
|
|
|
|
ws.addEventListener( 'close', function( e ) {
|
|
|
|
console.log( 'Closed connection' );
|
|
|
|
} );
|
|
|
|
|
|
|
|
class Timeline{
|
|
|
|
constructor(ws, el, nr) {
|
|
|
|
this.ws = ws;
|
|
|
|
this.el = el;
|
|
|
|
this.count = nr;
|
|
|
|
this.eventDataSet = new vis.DataSet([
|
|
|
|
{content: '.', start: new Date(), type: 'point', group: 1}
|
|
|
|
]);
|
2019-05-15 14:03:51 +00:00
|
|
|
// console.log('init timeline');
|
2019-11-28 17:00:26 +00:00
|
|
|
|
|
|
|
this.lightMap = {};
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
let groups = [];
|
|
|
|
for(let hid = 1; hid<=this.count; hid++) {
|
|
|
|
groups.push({id: parseInt(hid), content: 'Hugvey #'+hid});
|
|
|
|
this.eventDataSet.add({content: 'initiate', start: new Date(), type: 'point', group: parseInt(hid)})
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-05-15 14:03:51 +00:00
|
|
|
this.dataGroups = new vis.DataSet(groups);
|
2019-04-25 17:08:27 +00:00
|
|
|
let options = {
|
2019-05-16 14:16:44 +00:00
|
|
|
maxHeight: '100%',
|
2019-05-18 11:14:58 +00:00
|
|
|
height: '100%',
|
2019-05-16 14:16:44 +00:00
|
|
|
margin : {
|
|
|
|
item: {
|
|
|
|
horizontal: 0,
|
|
|
|
vertical: 5
|
|
|
|
}
|
|
|
|
},
|
|
|
|
zoomMax: 3600000 // 1 h
|
2019-04-25 17:08:27 +00:00
|
|
|
// 'rollingMode': {'follow': true, 'offset': .8 }
|
|
|
|
};
|
2019-05-15 14:03:51 +00:00
|
|
|
// console.log('groups', this.dataGroups, groups, options);
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-05-15 14:03:51 +00:00
|
|
|
this.timeline = new vis.Timeline(this.el, this.eventDataSet, this.dataGroups, options);
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
let tl = this.timeline;
|
|
|
|
let startDate = new Date();
|
|
|
|
startDate.setMinutes(startDate.getMinutes()-1);
|
|
|
|
let endDate = new Date();
|
|
|
|
endDate.setMinutes(endDate.getMinutes()+20);
|
|
|
|
|
2019-11-11 19:34:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
//follow the timeline or not if checkbox is checked
|
|
|
|
setTimeout(function(){
|
|
|
|
tl.setWindow(startDate, endDate);
|
|
|
|
}, 500);
|
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
this.moveInterval = setInterval(function(){
|
|
|
|
// skip movement if not visible
|
|
|
|
tl.moveTo(new Date());
|
|
|
|
}, 1000);
|
2019-11-11 19:34:33 +00:00
|
|
|
|
|
|
|
var checkbox = document.getElementById('follow_checkbox')
|
|
|
|
checkbox.addEventListener('change', (event) => {
|
|
|
|
if (event.target.checked) {
|
|
|
|
this.moveInterval = setInterval(function(){
|
|
|
|
// skip movement if not visible
|
|
|
|
tl.moveTo(new Date());
|
|
|
|
}, 1000);
|
|
|
|
} else {
|
|
|
|
clearInterval(this.moveInterval)
|
|
|
|
}
|
|
|
|
});
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
|
|
|
|
ws.addEventListener( 'message', this);
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
handleEvent(e) {
|
2019-05-15 14:03:51 +00:00
|
|
|
// console.log('handle it', e, this);
|
2019-04-25 17:08:27 +00:00
|
|
|
if(e.type == 'message') {
|
|
|
|
this.wsOnMessage(e)
|
|
|
|
}
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
wsOnMessage(e) {
|
|
|
|
let msg = JSON.parse( e.data );
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
if ( typeof msg['action'] === 'undefined' ) {
|
|
|
|
console.error( "not a valid message: " + e.data );
|
|
|
|
return;
|
|
|
|
}
|
2019-05-18 11:14:58 +00:00
|
|
|
|
2019-05-15 14:03:51 +00:00
|
|
|
if(msg['action'] == 'status') {
|
2019-11-28 17:00:26 +00:00
|
|
|
// reconstruct mapping of lights to hugveys
|
|
|
|
this.lightMap = {}
|
|
|
|
for(let hv of msg['hugveys']){
|
|
|
|
if(!this.lightMap.hasOwnProperty(hv['light_id'])) {
|
|
|
|
this.lightMap[hv['light_id']] = [];
|
|
|
|
}
|
|
|
|
this.lightMap[hv['light_id']].push(hv['id']);
|
|
|
|
}
|
|
|
|
|
|
|
|
// loop over statusses of hugveys and show them at the appropriate lights
|
2019-05-15 14:03:51 +00:00
|
|
|
for(let hv of msg['hugveys']){
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log(hv['language'], hv['status']);
|
|
|
|
let evenOdd = parseInt(hv['light_id'])%2 ? 'odd': 'even';
|
2019-11-13 22:43:02 +00:00
|
|
|
let availableClass = hv['available'] ? 'is-available' : 'is-not-available';
|
2019-11-28 17:00:26 +00:00
|
|
|
let realHugveyId = "";
|
|
|
|
if(this.lightMap[hv['light_id']].length > 1 || this.lightMap[hv['light_id']][0] != hv['light_id']) {
|
|
|
|
realHugveyId = '(#' + this.lightMap[hv['light_id']].join(' #') + ')';
|
|
|
|
}
|
|
|
|
this.dataGroups.update({id: parseInt(hv['light_id']), content: `<div class='title'>Hugvey ${hv['light_id']} ${realHugveyId}</div><div class='times'><span class='${hv['time_since_hugvey_spoke_state']}'>${hv['time_since_hugvey_spoke']}</span><span class='${hv['time_since_visitor_spoke_state']}'>${hv['time_since_visitor_spoke']}</span></div>`, className: `status-${hv['status']} ${availableClass} lang-${hv['language']} ${evenOdd}`})
|
2019-05-15 14:03:51 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
if(msg['action'] != 'log') {
|
|
|
|
return;
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
|
|
|
|
2019-11-28 17:00:26 +00:00
|
|
|
// let hv_id = parseInt(msg['id']);
|
|
|
|
let hv_machine_id = parseInt(msg['id']);
|
|
|
|
// map to light id:
|
|
|
|
let hv_id = Object.keys(this.lightMap).find(key => this.lightMap[key].indexOf(hv_machine_id) >= 0);
|
|
|
|
|
|
|
|
console.debug(msg, hv_id);
|
2019-04-25 17:08:27 +00:00
|
|
|
// {'action': 'log', 'id':hugvey_id, 'type': items[0], 'info', 'args'}
|
|
|
|
let d, parts;
|
|
|
|
switch(msg['type']){
|
|
|
|
case 'message':
|
|
|
|
// info: en-njsm8bwbd "Are you up for a conversation?"
|
|
|
|
parts = msg['info'].trim().split(' ');
|
|
|
|
let msgId = parts.shift();
|
|
|
|
let msgUuid = parts.shift();
|
|
|
|
let msgEvent = parts.shift();
|
|
|
|
let msgContent = parts.join(' ');
|
|
|
|
let mId = 'm-'+msgUuid+'-'+hv_id;
|
|
|
|
d = this.eventDataSet.get(mId);
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log(msgId, msgEvent, msgContent);
|
2019-04-25 17:08:27 +00:00
|
|
|
if(d !== null && msgEvent == 'done'){
|
|
|
|
d['end'] = new Date();
|
|
|
|
this.eventDataSet.update(d);
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log('update', d);
|
2019-04-25 17:08:27 +00:00
|
|
|
} else {
|
2019-05-17 17:06:00 +00:00
|
|
|
this.eventDataSet.add({id: mId, content: msgContent, title: `${msgContent} (${msgId})`, start: new Date(), end: new Date(Date.now()+5000), group: hv_id, 'className': 'message'});
|
2019-04-25 17:08:27 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'speaking':
|
|
|
|
// start/content/end
|
|
|
|
parts = msg['info'].trim().split(' ');
|
|
|
|
let info = parts.shift();
|
|
|
|
let id = parts.shift();
|
|
|
|
let content = parts.join(' ');
|
|
|
|
let scId = 'sc-'+id+'-'+hv_id;
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
if(info.startsWith('start')){
|
2019-05-17 17:06:00 +00:00
|
|
|
this.eventDataSet.add({content: info, start: new Date(), end: new Date(Date.now() + 1000), type: 'point', group: hv_id, 'className': 'speech'});
|
2019-04-25 17:08:27 +00:00
|
|
|
}
|
|
|
|
if(info.startsWith('content')){
|
|
|
|
d = this.eventDataSet.get(scId);
|
|
|
|
if(d !== null){
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log('alter');
|
2019-04-25 17:08:27 +00:00
|
|
|
d['content'] = content;
|
|
|
|
d['end']= new Date();
|
|
|
|
d['title'] = content;
|
|
|
|
this.eventDataSet.update(d);
|
|
|
|
} else {
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log('add');
|
2019-05-17 17:06:00 +00:00
|
|
|
this.eventDataSet.add({id: scId, content: content, title: content, start: new Date(), end: new Date(Date.now() + 1000), group: hv_id, 'className': 'speech'});
|
2019-04-25 17:08:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if(info.startsWith('end')){
|
|
|
|
d = this.eventDataSet.get(scId);
|
|
|
|
if(d !== null){
|
|
|
|
d['end'] = new Date();
|
|
|
|
this.eventDataSet.update(d);
|
|
|
|
}
|
|
|
|
}
|
2019-05-11 13:23:55 +00:00
|
|
|
|
2019-04-25 17:08:27 +00:00
|
|
|
break;
|
|
|
|
case 'story':
|
|
|
|
// 'info': 'start'/'finished'
|
2019-04-27 14:39:20 +00:00
|
|
|
this.eventDataSet.add({
|
2019-11-12 08:54:55 +00:00
|
|
|
title: msg['type'] +': ' + msg['info'] + (msg.hasOwnProperty('args')? ': '+msg['args'] : ""),
|
2019-04-27 14:39:20 +00:00
|
|
|
start: new Date(), type: 'point', group: hv_id, 'className': 'story'});
|
2019-04-25 17:08:27 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'condition':
|
|
|
|
case 'direction':
|
|
|
|
// don't draw these :-0
|
|
|
|
break;
|
|
|
|
default:
|
2019-04-27 14:39:20 +00:00
|
|
|
this.eventDataSet.add({
|
2019-11-12 08:54:55 +00:00
|
|
|
title: msg['type'] +': ' + msg['info'] + (msg.hasOwnProperty('args')? ': '+msg['args'] : ""),
|
2019-04-27 14:39:20 +00:00
|
|
|
start: new Date(), type: 'point', group: hv_id, 'className': msg['lvlname']});
|
2019-11-11 19:34:33 +00:00
|
|
|
if (msg['lvlname'] == 'CRITICAL' && playSoundOnError) {
|
|
|
|
// error_audio.play();
|
|
|
|
}
|
2019-04-25 17:08:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-28 17:00:26 +00:00
|
|
|
let req = new Request('/count');
|
|
|
|
fetch(req).then(response => response.json()).then(function(data) {
|
|
|
|
tl = new Timeline(ws, document.getElementById('line'), data.length);
|
|
|
|
});
|
2019-08-29 08:15:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.addEventListener('keypress', function(e){
|
2019-11-28 17:00:26 +00:00
|
|
|
// console.log(e.keyCode)
|
2019-08-29 08:15:33 +00:00
|
|
|
if(e.keyCode==46){
|
|
|
|
if(seeme){
|
|
|
|
seeme = false;
|
|
|
|
let options = {
|
|
|
|
showTooltips: false
|
|
|
|
};
|
|
|
|
tl.timeline.setOptions(options)
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
seeme = true;
|
|
|
|
let options = {
|
|
|
|
showTooltips: true
|
|
|
|
};
|
|
|
|
tl.timeline.setOptions(options)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|