var ws = new ReconnectingWebSocket( window.location.origin.replace('http', 'ws') +'/ws', null, { debug: false, reconnectInterval: 3000 } ); var seeme = true; var tl ; var error_audio = new Audio('siren.wav'); var playSoundOnError = true; var checkbox_sound = document.getElementById('play_sound_on_error') if(checkbox_sound != null) { checkbox_sound.addEventListener('change', (event) => { if (event.target.checked) { playSoundOnError = true; } else { playSoundOnError = false; } }) } //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} ]); // console.log('init timeline'); this.lightMap = {}; 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)}) } this.dataGroups = new vis.DataSet(groups); let options = { maxHeight: '100%', height: '100%', margin : { item: { horizontal: 0, vertical: 5 } }, zoomMax: 3600000 // 1 h // 'rollingMode': {'follow': true, 'offset': .8 } }; // console.log('groups', this.dataGroups, groups, options); this.timeline = new vis.Timeline(this.el, this.eventDataSet, this.dataGroups, options); let tl = this.timeline; let startDate = new Date(); startDate.setMinutes(startDate.getMinutes()-1); let endDate = new Date(); endDate.setMinutes(endDate.getMinutes()+20); //follow the timeline or not if checkbox is checked setTimeout(function(){ tl.setWindow(startDate, endDate); }, 500); this.moveInterval = setInterval(function(){ // skip movement if not visible tl.moveTo(new Date()); }, 1000); 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) } }); ws.addEventListener( 'message', this); } handleEvent(e) { // console.log('handle it', e, this); if(e.type == 'message') { this.wsOnMessage(e) } } wsOnMessage(e) { let msg = JSON.parse( e.data ); if ( typeof msg['action'] === 'undefined' ) { console.error( "not a valid message: " + e.data ); return; } if(msg['action'] == 'status') { // 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 for(let hv of msg['hugveys']){ // console.log(hv['language'], hv['status']); let evenOdd = parseInt(hv['light_id'])%2 ? 'odd': 'even'; let availableClass = hv['available'] ? 'is-available' : 'is-not-available'; 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: `
Hugvey ${hv['light_id']} ${realHugveyId}
${hv['time_since_hugvey_spoke']}${hv['time_since_visitor_spoke']}
`, className: `status-${hv['status']} ${availableClass} lang-${hv['language']} ${evenOdd}`}) } } if(msg['action'] != 'log') { return; } // 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); // {'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); // console.log(msgId, msgEvent, msgContent); if(d !== null && msgEvent == 'done'){ d['end'] = new Date(); this.eventDataSet.update(d); // console.log('update', d); } else { this.eventDataSet.add({id: mId, content: msgContent, title: `${msgContent} (${msgId})`, start: new Date(), end: new Date(Date.now()+5000), group: hv_id, 'className': 'message'}); } 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; if(info.startsWith('start')){ this.eventDataSet.add({content: info, start: new Date(), end: new Date(Date.now() + 1000), type: 'point', group: hv_id, 'className': 'speech'}); } if(info.startsWith('content')){ d = this.eventDataSet.get(scId); if(d !== null){ // console.log('alter'); d['content'] = content; d['end']= new Date(); d['title'] = content; this.eventDataSet.update(d); } else { // console.log('add'); this.eventDataSet.add({id: scId, content: content, title: content, start: new Date(), end: new Date(Date.now() + 1000), group: hv_id, 'className': 'speech'}); } } if(info.startsWith('end')){ d = this.eventDataSet.get(scId); if(d !== null){ d['end'] = new Date(); this.eventDataSet.update(d); } } break; case 'story': // 'info': 'start'/'finished' this.eventDataSet.add({ title: msg['type'] +': ' + msg['info'] + (msg.hasOwnProperty('args')? ': '+msg['args'] : ""), start: new Date(), type: 'point', group: hv_id, 'className': 'story'}); break; case 'condition': case 'direction': // don't draw these :-0 break; default: this.eventDataSet.add({ title: msg['type'] +': ' + msg['info'] + (msg.hasOwnProperty('args')? ': '+msg['args'] : ""), start: new Date(), type: 'point', group: hv_id, 'className': msg['lvlname']}); if (msg['lvlname'] == 'CRITICAL' && playSoundOnError) { // error_audio.play(); } break; } } } let req = new Request('/count'); fetch(req).then(response => response.json()).then(function(data) { tl = new Timeline(ws, document.getElementById('line'), data.length); }); window.addEventListener('keypress', function(e){ // console.log(e.keyCode) 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) } } });