Exract timeline to sepearte page
This commit is contained in:
parent
997eeff663
commit
a286bbf1fa
5 changed files with 204 additions and 144 deletions
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
146
www/js/hugvey_timeline.js
Normal 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
53
www/timeline.html
Normal 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>
|
Loading…
Reference in a new issue