Beekeeper
view release on metacpan or search on metacpan
examples/dashboard/js/dashboard.js view on Meta::CPAN
service: this.service,
level: this.level,
after: this.after,
count: 200
};
ui.backend.get_logs( params, function(result) {
let log_entries = $('#log_entries');
if (!result.length) {
if (!update) log_entries.empty();
if (!this.after) this.after = 0;
return;
}
let labels = this.labels;
let html = '';
result.forEach(function(entry) {
let type = labels[entry.level];
let tstamp = new Date(entry.tstamp*1000).toISOString().replace('T',' ').replace('Z','');
html += `<div class="entry"><div class="level l${entry.level}">${type}</div><div class="tstamp">${tstamp}<br/>${entry.service}</div><div class="msg">${entry.message}</div></div>`;
});
if (update) {
log_entries.append(html);
this.entries += result.length;
let remove = this.entries - 1000;
if (remove > 0) {
this.entries -= remove;
log_entries.children().slice(0,remove).remove();
}
}
else {
log_entries.html(html);
this.entries = result.length;
}
if (autoscroll) $(window).scrollTop( $('#logs').innerHeight() );
this.after = result[result.length - 1].tstamp;
}.bind(this));
},
update_logs: function() {
this.get_logs('update');
}
}}
function realTimeLineChart(id, data, points) { return {
id: id,
data: data,
points: points,
margin: { top: 20, right: 20, bottom: 20, left: 50 },
width: null,
height: null,
timer: null,
draw: function() {
let target_element = document.getElementById(this.id);
let cs = getComputedStyle(target_element);
if (!this.width) this.width = cs.width.replace(/px/,"") || 800;
if (!this.height) this.height = cs.height.replace(/px/,"") || 150;
let margin = this.margin;
let width = this.width;
let height = this.height;
let data = this.data;
let chartWidth = width - margin.left - margin.right;
let chartHeight = height - margin.top - margin.bottom;
let xMin = new Date( d3.min(data, function(d) { return d[0] }) );
let xMax = new Date( d3.max(data, function(d) { return d[0] }) );
let yMin = d3.min(data, function(d) { return d[1] });
let yMax = d3.max(data, function(d) { return d[1] });
yMin -= yMax * .05; if (yMin < 0) yMin = 0;
yMax += yMax * .05; if (yMax < 1) yMax = 1;
let xScale = d3.scaleTime().rangeRound([ 0, chartWidth ]).domain([xMin, xMax]);
let yScale = d3.scaleLinear().rangeRound([ chartHeight, 0 ]).domain([yMin, yMax]);
// Create svg
let div = d3.select("#"+this.id);
let svg = div.html("")
.append("svg")
.attr("width", width)
.attr("height", height);
// Main group
let main = svg.append("g")
.attr("class", "rtchart")
.attr("transform", "translate (" + margin.left + "," + margin.top + ")");
// Draw background
main.append("rect")
.attr("class", "canvas")
.attr("x", 0)
.attr("y", 0)
.attr("width", chartWidth )
.attr("height", chartHeight );
let xAxis = d3.axisBottom(xScale).ticks(width > 600 ? 10 : 5);
let yAxis = d3.axisLeft(yScale).ticks(5);
// Draw x axis
main.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0," + chartHeight + ")")
.call(xAxis);
// Draw y axis
main.append("g")
.attr("class", "axis y")
.call(yAxis);
// Clip path
main.append("defs")
.append("clipPath")
.attr("id", "clip" + this.id )
.append("rect")
.attr("width", chartWidth - 1)
.attr("height", chartHeight )
.attr("transform", "translate(1,0)");
// Line path
let path = main.append("g")
.append("path")
.attr("class", "data")
.attr("clip-path", "url(#clip" + this.id + ")")
.style("fill", "none");
// Line function
let line = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return xScale(d[0]); })
.y(function(d) { return yScale(d[1]); });
// Draw line
path.attr("d", line(data) );
this.refresh = function() {
let xMin = d3.min(data, function(d) { return d[0] });
let xMax = new Date( d3.max(data, function(d) { return d[0] }) );
let yMin = d3.min(data, function(d) { return d[1] });
let yMax = d3.max(data, function(d) { return d[1] });
yMin -= yMax * .05; if (yMin < 0) yMin = 0;
yMax += yMax * .05; if (yMax < 1) yMax = 1;
// Update ranges
xScale.domain([xMin, xMax]);
yScale.domain([yMin, yMax]);
// Refresh axis
main.select(".x").call(xAxis);
main.select(".y").call(yAxis);
// Refresh line
path.attr("d", line(data) );
};
if (this.timer) clearInterval(this.timer);
this.timer = setInterval( this.refresh, 1000 );
},
clear: function() {
clearInterval(this.timer);
},
set_data: function(data) {
this.data.length = 0;
this.data.push(data);
this.refresh();
},
add_data: function(data) {
this.data.push(data);
if (this.data.length > this.points) {
this.data.splice(0, this.data.length - this.points);
}
this.refresh();
}
}}
function BeekeeperClient () { return {
mqtt: null,
host: null,
client_id: null,
response_topic: null,
request_seq: 1,
subscr_seq: 1,
pending_req: {},
subscr_cb: {},
subscr_re: {},
connect: function(args) {
const This = this;
if (!this.client_id) this._generate_client_id();
if ('debug' in args) this.debug(args.debug);
this._debug(`Connecting to MQTT broker at ${args.url}`);
// It is possible to iterate over a list of servers specifying:
// url: [{ host: 'localhost', port: 1883 }, ... ]
// Connect to MQTT broker using websockets
this.mqtt = mqtt.connect( args.url, {
username: args.username || 'guest',
password: args.password || 'guest',
clientId: this.client_id,
protocolVersion: 5,
clean: true,
keepalive: 60,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000
});
this.mqtt.on('connect', function (connack) {
This.host = This.mqtt.options.host;
This._debug("Connected to MQTT broker at " + This.host);
This._create_response_topic();
if (args.on_connect) args.on_connect(connack.properties);
});
( run in 2.476 seconds using v1.01-cache-2.11-cpan-6aa56a78535 )