var ws = new ReconnectingWebSocket( window.location.origin.replace('http', 'ws') +'/ws', null, { debug: false, reconnectInterval: 3000 } ); //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'); 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') { for(let hv of msg['hugveys']){ console.log(hv['language'], hv['status']); let evenOdd = parseInt(hv['id'])%2 ? 'odd': 'even'; let availableClass = hv['available'] ? 'is-available' : 'is-not-available' this.dataGroups.update({id: parseInt(hv['id']), content: 'Hugvey #'+hv['id'], className: `status-${hv['status']} ${availableClass} lang-${hv['language']} ${evenOdd}`}) } } if(msg['action'] != 'log') { return; } console.debug(msg, this); let hv_id = parseInt(msg['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({ content: 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({ content: msg['type'] +': ' + msg['info'] + (msg.hasOwnProperty('args')? ': '+msg['args'] : ""), start: new Date(), type: 'point', group: hv_id, 'className': msg['lvlname']}); break; } } } var tl = new Timeline(ws, document.getElementById('line'), 26);