// global variables var api; var connection; var timer; var nodes = []; var currentNode; var paused = false; var sequence = 0; var plotData = []; var plotOptions = { xaxis: { mode: 'time' }, legend: { show: true } }; var updateRate = 25; var redrawPlot = true; var xDelta = 5000; var xPast = xDelta * 0.9; var xFuture = xDelta * 0.1; $(document).ready(function() { api = new Api('v1', apiConnected); $('#play').click(function(e, ui) { connection = wsConnect(currentNode); paused = false; }); $('#pause').click(function(e, ui) { connection.close(); paused = true; }); $('#timespan').slider({ min : 1000, max : 10000, value : xDelta, slide : function(e, ui) { updatePlotWindow(ui.value); } }); $('#updaterate').slider({ min : 1, max : 50, value : updateRate, slide : function(e, ui) { clearInterval(timer); timer = setInterval(updatePlot, 1000.0 / updateRate); updateRate = ui.value; } }); $('.inputs #slider').slider({ min : 0, max : 100, slide : sendData }); $('.inputs-checkboxes input').checkboxradio() .each(function(idx, elm) { $(elm).change(sendData); }); timer = setInterval(updatePlot, 1000.0 / updateRate); }); $(window).on('beforeunload', function() { connection.close(); api.close(); }); function sendData() { var slider = $('.inputs #slider'); var checkboxes = $('.inputs-checkboxes input'); var data = [ $(slider).slider('value'), 0 ]; for (var i = 0; i < checkboxes.length; i++) data[1] += (checkboxes[i].checked ? 1 : 0) << i; var msg = new Msg({ timestamp : Date.now(), sequence : sequence++, id : currentNode.id, data : data }); console.log('Sending message', msg); connection.send(msg.toArrayBuffer()); } function apiConnected() { api.request('nodes', {}, function(response) { nodes = response; console.log("Found " + nodes.length + " nodes:", nodes); for (var i = 0; i < nodes.length; i++) if (nodes[i].name == getParameterByName('node')) currentNode = nodes[i]; if (currentNode === undefined) currentNode = nodes[0]; if (currentNode !== undefined) { updateNodeList(); connection = wsConnect(currentNode); } } ); } function updateNodeList() { $('.node-selector').empty(); nodes.forEach(function(node, index) { if (node.type == 'websocket') { $('.node-selector').append( $('<button>') .addClass(node.name == currentNode.name ? 'ui-state-active' : '') .text(node.description ? node.description : node.name) .click(function() { var url = node.name; window.location = '?node=' + node.name; }) ); } }); $('.node-selector').buttonset(); } function updatePlotWindow(delta) { xDelta = delta xPast = xDelta * 0.9; xFuture = xDelta * 0.1; } function updatePlot() { var data = []; if (!redrawPlot) return; // add data to arrays for (var i = 0; i < plotData.length; i++) { var seriesOptions = nodes data[i] = { data : plotData[i], shadowSize : 0, label : 'Index ' + String(i), lines : { lineWidth: 2 } } if (currentNode.series !== undefined && currentNode.series[i] !== undefined) $.extend(true, data[i], currentNode.series[i]); } var options = { xaxis: { min: Date.now() - xPast, max: Date.now() + xFuture }, grid: { markings: [ { xaxis: { from: Date.now(), to: Date.now() }, color: '#ff0000' } ] } } /* update plot */ $.plot('.plot-container div', data, $.extend(true, options, plotOptions)); redrawPlot = false; } function wsConnect(node) { var url = wsUrl(''); var conn = new WebSocket(url, 'live'); conn.binaryType = 'arraybuffer'; conn.onopen = function() { $('#status') .text('Connected') .css('color', 'green'); console.log('WebSocket connection established'); }; conn.onclose = function(error) { console.log('WebSocket connection closed', error); $('#status') .text('Disconnected (' + error.reason + ')') .css('color', 'red'); /* Try connect if close reason was CLOSE_NORMAL */ if (error.code == 1000 || error.code == 1001) { setTimeout(function() { wsConnect(currentNode); }, 1000); } }; conn.onerror = function(error) { console.log('WebSocket connection error', error); $('#status').text('Status: Error: ' + error.message); }; conn.onmessage = function(e) { var msgs = Msg.fromArrayBufferVector(e.data); console.log('Received ' + msgs.length + ' messages with ' + msgs[0].data.length + ' values from id ' + msgs[0].id + ' with timestamp ' + msgs[0].timestamp); for (var j = 0; j < plotData.length; j++) { // remove old while (plotData[j].length > 0 && plotData[j][0][0] < (Date.now() - xPast)) plotData[j].shift() } for (var j = 0; j < msgs.length; j++) { var msg = msgs[j]; if (msg.id != currentNode.id) continue; // add empty arrays for data series while (plotData.length < msg.length) plotData.push([]); // add data to arrays for (var i = 0; i < msg.length; i++) plotData[i].push([msg.timestamp, msg.data[i]]); } redrawPlot = true; }; return conn; }; /* Helpers */ function wsUrl(endpoint) { var l = window.location; var url = ''; if (l.protocol === 'https:') url += 'wss://'; else url += 'ws://'; url += l.hostname; if ((l.port) && (l.port != 80) && (l.port != 443)) url += ':'+ l.port; url += '/' + endpoint; return url; } /* Some helpers */