Exract timeline to sepearte page

This commit is contained in:
Ruben van de Ven 2019-04-25 19:08:27 +02:00
parent 997eeff663
commit a286bbf1fa
5 changed files with 204 additions and 144 deletions

View File

@ -425,6 +425,7 @@ class HugveyState(object):
self.status = status
lightOn = status in [self.STATE_AWAITING, self.STATE_PAUSE, self.STATE_GONE]
self.setLightStatus(lightOn)
self.eventLogger.info(f"status: {self.status}")
def config(self, hostname, ip):
@ -605,6 +606,7 @@ class HugveyState(object):
def shutdown(self, definitive = False):
self.logger.info(f"Start shutdown sequence {definitive}")
self.eventLogger.critical(f"error: shutting down")
if self.streamer:
self.streamer.stop()
if self.story:

View File

@ -7,13 +7,12 @@
<script src="/js/moment.min.js"></script>
<script src="/js/d3.v5.min.js"></script>
<script src="/js/crel.min.js"></script>
<script src="/js/vis.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<link rel="stylesheet" href="/css/vis.min.css"></link>
<link rel="stylesheet" href="/css/styles.css"></link>
</head>
<body class='showTimeline dark'>
<body class='dark'>
<div id="interface" class='showStatus'>
<div id='status'>
<div id='overview'>
@ -29,7 +28,6 @@
:class="['flag-icon', lang.code]"></span> {{lang.code}}</li>
</ul>
<div class='btn' id='toggleTimeline'>Timeline</div>
</div>
<div class='hugvey' v-for="hv in hugveys"
:class="[{'hugvey--on': hv.status != 'off'},'hugvey--' + hv.status]"
@ -99,7 +97,6 @@
</g>
</svg>
</div>
<div id='timeline'></div>
</div>
<script type='application/javascript' src="/js/hugvey_console.js"></script>
</body>

View File

@ -53,7 +53,6 @@ class Panopticon {
return panopticon.change_language(hv.id, lang_code);
},
showHugvey: function(hv) {
document.body.classList.remove('showTimeline');
panopticon.hugveys.selectedId = hv.language ? hv.id : null;
panopticon.updateSelectedHugvey();
}
@ -65,16 +64,7 @@ class Panopticon {
this.socket = new ReconnectingWebSocket( "ws://localhost:8888/ws", null, { debug: false, reconnectInterval: 3000 } );
this.graph = new Graph();
this.eventDataSet = new vis.DataSet([
{content: '.', start: new Date(), type: 'point', group: 1}
]);
this.timeline = false;
document.getElementById('toggleTimeline').addEventListener('click', function(){
document.body.classList.toggle('showTimeline');
});
this.socket.addEventListener( 'open', ( e ) => {
this.send( { action: 'init' } );
} );
@ -110,112 +100,9 @@ class Panopticon {
if(this.hugveys.selectedId) {
this.updateSelectedHugvey();
}
if(!this.timeline) {
console.log('init timeline');
let groups = [];
for(let hid of msg['hugvey_ids']) {
groups.push({id: parseInt(hid), content: 'Hugvey #'+hid});
this.eventDataSet.add({content: 'initiate', start: new Date(), type: 'point', group: parseInt(hid)})
}
let dataGroups = new vis.DataSet(groups);
let options = {
// 'rollingMode': {'follow': true, 'offset': .8 }
};
console.log('groups', dataGroups, groups, options);
this.timeline = new vis.Timeline(document.getElementById('timeline'), this.eventDataSet, dataGroups, options);
//
let startDate = new Date();
startDate.setMinutes(startDate.getMinutes()-1);
let endDate = new Date();
endDate.setMinutes(endDate.getMinutes()+20);
setTimeout(function(){
panopticon.timeline.setWindow(startDate, endDate);
}, 500);
console.log(startDate, endDate);
this.timelineInterval = setInterval(function(){
// skip movement if not visible
if(!document.body.classList.contains('showTimeline'))
return;
panopticon.timeline.moveTo(new Date());
}, 1000);
}
break;
case 'log':
let hv_id = parseInt(msg['id']);
if(this.timeline) {
// {'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(), 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(), 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(), 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['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['args'], start: new Date(), type: 'point', group: hv_id});
break;
}
}
break;
}
} );
@ -224,11 +111,6 @@ class Panopticon {
updateSelectedHugvey() {
let hv = null;
if(document.body.classList.contains('showTimeline')) {
// skip at all if no hugvey is visbile anyway due to the timeline
return;
}
if(this.hugveys.selectedId) {
hv = this.getHugvey(this.hugveys.selectedId);
if(hv.language && this.graph.language_code != hv.language) {
@ -2055,24 +1937,4 @@ class Graph {
}
}
//
//class Timeline {
// constructor(el, hugvey_ids) {
// this.el = el;
// this.logbook = []
// this.hugvey_ids = hugvey_ids;
//
// this.el.innerHTML = "";
// for(id of this.hugvey_ids) {
// this.el.appendChild(crel(
// 'div', {
//
// }
// ));
// }
// }
//
// log(msg) {
//// {"action": "log", "id": "3", "type": "story", "info": " start"}
// console.log('log!', msg);
// }
//}
//

146
www/js/hugvey_timeline.js Normal file
View File

@ -0,0 +1,146 @@
var ws = new ReconnectingWebSocket( "ws://localhost:8888/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)})
}
let dataGroups = new vis.DataSet(groups);
let options = {
// 'rollingMode': {'follow': true, 'offset': .8 }
};
console.log('groups', dataGroups, groups, options);
this.timeline = new vis.Timeline(this.el, this.eventDataSet, dataGroups, options);
let tl = this.timeline;
let startDate = new Date();
startDate.setMinutes(startDate.getMinutes()-1);
let endDate = new Date();
endDate.setMinutes(endDate.getMinutes()+20);
setTimeout(function(){
tl.setWindow(startDate, endDate);
}, 500);
this.moveInterval = setInterval(function(){
// skip movement if not visible
tl.moveTo(new Date());
}, 1000);
ws.addEventListener( 'message', this);
}
handleEvent(e) {
console.log('handle', 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'] != '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(), 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(), 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(), 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['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['args'], start: new Date(), type: 'point', group: hv_id});
break;
}
}
}
var tl = new Timeline(ws, document.getElementById('line'), 25);

53
www/timeline.html Normal file
View File

@ -0,0 +1,53 @@
<html>
<head>
<title>Pillow Talk - Timeline</title>
<link rel="stylesheet" href="/css/vis.min.css"></link>
<script src="/js/reconnecting-websocket.js"></script>
<script src="/js/vis.min.js"></script>
<style type="text/css">
body{
margin:0;
background: #333;
color:#999;
font-family:sans-serif;
overflow-x: hidden;
}
#line{
width: 180%;
}
.vis-item{
color:#999;
}
.vis-item.message {
background: lightgray;
color:#333;
}
.vis-item.message.vis-range{
background-color: darkgray;
border-color: green;
}
.vis-item.speech {
background-color: greenyellow;
border-color: green;
}
.vis-text,.vis-labelset .vis-label {
color: #999;
}
.vis-time-axis .vis-text{
color: #999;
}
.vis-grid, .vis-foreground .vis-group{
border-color:#666 !important;
}
</style>
</head>
<body id='timeline'>
<div id='line'></div>
<script type='application/javascript' src="/js/hugvey_timeline.js"></script>
</body>
</html>