Snippets

Piotr Szrajber Smart M.App - Make circles size dependent on the measure value

Created by Piotr Szrajber
//# sourceURL=Customizations.js

/**
 * Modify BI map behavior, so that the circles radii depend on the measure value
 * 2017-07-28 Piotr Szrajber <piotr.szrajber@hexagongeospatial.com>
 */

let CIRCLE_SIZE_RANGE = {min: 10, max: 30}, // radius is going to be from 10px to 30px
    MEASURE_NAME = "speed_avg"; // change to your measure value
    

/**
 * Finds minimal and maximal value of the given property in the data stage
 * @param {gvc.dataStage} stage GVC data stage
 * @param {String} property property name
 * @return {Object} range
 * @return {Number} range.min minimal value
 * @return {Number} range.max maximal value
 */
function getRange(stage, property) {
    return stage.rows().reduce((acc, curr) => {
        acc.min = Math.min(acc.min, curr[property]);
        acc.max = Math.max(acc.max, curr[property]);
        return acc;
    }, {
        min: Infinity,
        max: -Infinity
    });
}

/**
 * Returns radius for a given property using scale computation
 * @param {Number} value value to be scaled
 * @param {Object} domain
 * @param {Number} domain.min
 * @param {Number} domain.max
 * @param {Object} range
 * @param {Number} range.min
 * @param {Number} range.max
 * @return {Number} radius
 */
function getRadius(value, domain, range) {
    let  minX = domain.min,
        maxX = domain.max,
        minY = range.min,
        maxY = range.max;
    return Math.round(minY + value/(maxX - minX)*(maxY - minY));
}

/**
 * Returns measure id by name
 * @param {String} name measure name
 * @param {gvc.dataStage} stage GVC data stage
 * @return {String} id measure id
 */
function getMeasureIdByName(name, stage) {
    let measureDef = stage.stageModel().values.find(item => item.name === name);
    if (!measureDef) throw `No measure named ${name}`;
    return measureDef.id;
}

/**
 * Modify painter's behavior
 */
function changeMapBehavior(attempts) {
    // find the choropleth
    $GP.bi.stage.findWidgets({
        descriptors: [{
            chartM: {
                chart: "choropleth"
            }
        }]
    }, function(widgets) {
        if (!widgets || !widgets[0]) {
            setTimeout(function() {
                if (attempts > 0) {
                    changeMapBehavior(attempts - 1);
                }
            }, 300);
            return;
        }
        
        // main logic
        let painter = widgets[0].chart.painter(),
            stage = widgets[0].chart.dataStage(),
            measureId = getMeasureIdByName(MEASURE_NAME, stage),
            speedRange = getRange(stage, measureId),
            origPaintStyle = painter.paintStyle();
        
        painter.paintStyle((feature) => {
            let style = origPaintStyle.call(this, feature),
                averageSpeed = feature.value[measureId],
                circleRadius = getRadius(averageSpeed, speedRange, CIRCLE_SIZE_RANGE);
            style.radius = circleRadius;
            return style;
        });

        painter.paint();
    });
}

// launch the customization
changeMapBehavior(100);

Comments (0)

HTTPS SSH

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