Snippets

Piotr Szrajber Smart M.App - add custom computation results to Custom Container Widget

Created by Piotr Szrajber
let GLOBALS = {},
    TIMEOUTS = {};

// recompute values using aggregation mechanisms and custom statistics on raw data
function recomputeAggregations(callback, errback) {
    const attribute1 = "WAGES_TOTAL",
        attribute2 = "POPULATION_TOTAL";

    gsp.bi.stage.findStage(null, function(stage) {
        if (!stage) return;

        // use BI aggregation mechanism. Here I'm using a weighted average of attribute1 by attribute2
        let aggregationResult = stage.tryAggregation(`round($sum(${attribute1}*${attribute2})/$sum(${attribute2}))`);

        if (!aggregationResult.success) return;

        let value = aggregationResult.value.test;

        // custom statistical operations on raw rows. I am using Array.prototype.reduce function
        // but feel free to use plain for loop or whatever

        let customAcc = stage.rows().reduce(function(accumulated, current) {
            accumulated.min = Math.min(accumulated.min, current[attribute1]);
            accumulated.max = Math.max(accumulated.max, current[attribute1]);
            return accumulated;
        }, {
            min: Infinity,
            max: -Infinity
        });

        let output = `Weighted average of ${attribute1} by ${attribute2} is ${value} while min=${customAcc.min} and max=${customAcc.max}`;
        if (typeof callback === "function")
            callback(output);

    }, function(err) {
        if (typeof errback === "function")
            errback(err);
    });
}


// recompute statistics and update the custom chart
function update() {
    recomputeAggregations(updateCustomChart);
}


// update the custom chart
function updateCustomChart(html) {
    document.querySelector(".custom-chart > div.widget-chart > div.widget-content").innerHTML = html;
}

function onRenderlet(chart, filter) {
    update();
}

// wait for the pointmap layer, store reference to it and apply customizations
waitFor("choropleth", function(widget) {
    let geochart = widget.chart;
    GLOBALS.geochart = geochart;
    // attach an event to the choropleth so each time it is refreshed our onRenderlet function will execute
    geochart.on("renderlet", onRenderlet);
    // initial values
    update();
});

// waits until the widget of particular type is on stage
// this is simplified and it should be used just once for particular chartType
// @param {String} chartType - "choropleth", "pointmap", "table", "row", "bar", "pie", etc.
// @param {Function} callback callback function
// @param {Object} callback.widget first widget of particular type
// @return {void}
function waitFor(chartType, callback) {
    gsp.bi.stage.findWidgets({
        descriptors: [{
            chartM: {
                chart: chartType
            }
        }]
    }, function(widgets) {
        if (!widgets || !widgets[0]) {
            TIMEOUTS[chartType] = setTimeout(function() {
                waitFor(chartType, callback);
            }, 500);
        } else {
            clearTimeout(TIMEOUTS[chartType]);
            callback(widgets[0]);
        }
    });
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.