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 )