Snippets

Piotr Szrajber Smart M.App - Add custom datatable row action zoomToFeature

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

/**
* Add a custom row action in the data table that zooms on particular feature
* It depends on a BI Map with
* - choropleth
* - datatable
* - one additional row chart
* 2017-09-13 Piotr Szrajber <piotr.szrajber@hexagongeospatial.com>
*/

const KEY_PROPERTY = "GEO_ID", // change to your geometry ID
    BUFFER_SIZE = 100;

let GLOBALS = {},
    TIMEOUT;

// waits until choropleth widget is ready
function waitForChoropleth(callback) {
    gsp.bi.stage.findWidgets({
        descriptors: [{
            chartM: {
                chart: "choropleth"
            }
        }]
    }, function(widgets) {
        if (!widgets || !widgets[0]) {
            TIMEOUT = setTimeout(function() {
                waitForChoropleth(callback);
            }, 500);
        } else {
            clearTimeout(TIMEOUT);
            callback(widgets[0]);
        }
    });
}

// waits until dc charts are filled with SVG - that means they are already initialized
// this method is not perfect as it depends on at least one chart with SVG...
// @param {Function} fn callback
function chartsReady(fn) {
    let observer = new MutationObserver(function(mutations, me) {
        let chartWithSvg = document.querySelector(".widget-chart.dc-chart>svg");
        if (chartWithSvg) {
            fn();
            me.disconnect();
        }
    });

    observer.observe(document, {
        childList: true,
        subtree: true
    });
}

function zoomToBBox(bottomLeftCorner, topRightCorner, callback, errback) {
    // transform sample points to current CRS
    gsp.crs.transform({
        points: [bottomLeftCorner, topRightCorner],
        sourceCrsId: "EPSG:4326",
        targetCrsId: gsp.crs.getCurrent()
    }, function(transformationResult) {
        // get BBOX in form minx, miny, maxx, maxy
        var points = transformationResult.points,
            bbox = [points[0].x, points[0].y, points[1].x, points[1].y];
        gsp.map.zoom({
            bbox: bbox
        });
    });
}

// zoom to feature
// note: it uses internal GVC's turf reference
function zoomToFeature(featureId) {
    if (!GLOBALS.geochart) return;

    let feature = GLOBALS.geochart.geoJson().features.find(function(f) {
        return f.properties[KEY_PROPERTY] === featureId;
    });
    if (!feature) {
        gsp.ui.info("This row has no associated geometry");
        return;
    }

    gsp.bi.stage.requireLibraries(function(gvc) {
        let geom = feature.geometry.type === "Point" ? gvc.turf.buffer(feature.geometry, BUFFER_SIZE) : feature.geometry;
        let bbox = gvc.turf.bbox(geom);
        zoomToBBox({
            x: bbox[0],
            y: bbox[1]
        }, {
            x: bbox[2],
            y: bbox[3]
        }, function() {
            gsp.ui.info(`Successfully centered on [${bbox.join(",")}]`);
        }, function() {
            gsp.ui.info("Could not zoom on this feature");
        });
    });
}

// add custom row action zoomToFeature
function reformatTable(chart) {
    let columns = chart.columns();
    chart.columns(columns.concat([{
        label: "Tools",
        format: function(d) {
            let featureId = d[KEY_PROPERTY];
            if (!window.zoomToFeature) {
                window.zoomToFeature = zoomToFeature;
            }
            return `<a href="#" onClick=window.zoomToFeature("${featureId}")>ZOOM</a>`;
        }
    }]));
}

// customize charts
chartsReady(function() {
    gsp.bi.stage.findStage(null, function(stage) {
        gsp.bi.stage.findWidgets({
            descriptors: [{
                chartM: {
                    chart: "table"
                }
            }]
        }, function(widgets) {
            let table = widgets[0];
            console.log(table);
            if (!table) return;
            reformatTable(table.chart);
        });
    });
});

// lets you modify the choropleth behavior 
waitForChoropleth(function(widget) {
    let geochart = widget.chart;
    GLOBALS.geochart = geochart;
    // do other changes with the choropleth
});

Comments (0)

HTTPS SSH

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