Select to view content in your preferred language

Buffer tool for Survey123 Map

4243
13
11-03-2017 03:46 AM
MicheleDe_Santis
Emerging Contributor

Hi to all,

is it possible to add a buffer tool on a Suvey123 Map? I would like to draw a buffer (radius 100m) on my position when the user click on a button. The buffer should be stay fixed on map and erased when the user click on another button. How Can I implement this function?

Thanks to all

0 Kudos
13 Replies
MichelleWilliamsERM
Frequent Contributor

Thank you for your quick response. I'm relearning scripting and missed the hard-coding.

0 Kudos
MichelleWilliamsERM
Frequent Contributor

My team at ERM made some changes to get this to work for us (we opened it up for the US.  

/*
 * Javascript function to create a buffer around a last known point.
 * Script credits:
 * Modified by Ryan Rhee - Boone County Fire Protection District/MO-TF1
 * Modified by Michael Stead from ERM, and Michelle Williams Survey123 Jedi
 * DOES NOT PULL FROM XY
 */

function generateBufferCoordinates(center_Y, center_X, zone_utm, buffer_dist) {
// Single function to perform buffer algebra and return list of coordinates as string object
// *center_Y* and *center_X* must be passed into the function as UTM coordinates
// *buffer_dist* must be passed into the function in meters (m)
    var coordinates = '';
    // Empty string of coordinates to be populated
    for (var angle_deg = 0.0; angle_deg < 360.0; angle_deg+=1.0) {
    // For loop iteratesd over all angles from 0 to 359 and returns a coordinate pair for the point *buffer_dist* away at *angle_deg* degrees from the point defined by *center_X*,*center_Y*
        const pi = 3.14159265359;
        const a = 6378137;
        const e = 0.081819191;
        const e1sq = 0.006739497;
        const k0 = 0.9996;
        // Defined variables for mathematical constants
        var zone = parseFloat(zone_utm)
        var buff_Y = parseFloat(center_Y)+buffer_dist*(Math.sin(angle_deg*pi/180))
        var buff_X = parseFloat(center_X)+buffer_dist*(Math.cos(angle_deg*pi/180))
        // Gets the UTM coordinates for the point *buffer_dist* away at *angle_deg* degrees from the point defined by *center_X*,*center_Y*
        var arc = buff_Y / k0;
        var mu = arc / (a * (1 - Math.pow(e, 2) / 4.0 - 3 * Math.pow(e, 4) / 64.0 - 5 * Math.pow(e, 6) / 256.0));
        var ei = (1 - Math.pow((1 - e * e), (1 / 2.0))) / (1 + Math.pow((1 - e * e), (1 / 2.0)));
        var ca = 3 * ei / 2 - 27 * Math.pow(ei, 3) / 32.0;
        var cb = 21 * Math.pow(ei, 2) / 16 - 55 * Math.pow(ei, 4) / 32;
        var cc = 151 * Math.pow(ei, 3) / 96;
        var cd = 1097 * Math.pow(ei, 4) / 512;
        var phi1 = mu + ca * Math.sin(2 * mu) + cb * Math.sin(4 * mu) + cc * Math.sin(6 * mu) + cd * Math.sin(8 * mu);
        var n0 = a / Math.pow((1 - Math.pow((e * Math.sin(phi1)), 2)), (1 / 2.0));
        var r0 = a * (1 - e * e) / Math.pow((1 - Math.pow((e * Math.sin(phi1)), 2)), (3 / 2.0));
        var fact1 = n0 * Math.tan(phi1) / r0;
        var _a1 = 500000 - buff_X;
        var dd0 = _a1 / (n0 * k0);
        var fact2 = dd0 * dd0 / 2;
        var t0 = Math.pow(Math.tan(phi1), 2);
        var Q0 = e1sq * Math.pow(Math.cos(phi1), 2);
        var fact3 = (5 + 3 * t0 + 10 * Q0 - 4 * Q0 * Q0 - 9 * e1sq) * Math.pow(dd0, 4) / 24;
        var fact4 = (61 + 90 * t0 + 298 * Q0 + 45 * t0 * t0 - 252 * e1sq - 3 * Q0 * Q0) * Math.pow(dd0, 6) / 720;
        var lof1 = _a1 / (n0 * k0);
        var lof2 = (1 + 2 * t0 + Q0) * Math.pow(dd0, 3) / 6.0;
        var lof3 = (5 - 2 * Q0 + 28 * t0 - 3 * Math.pow(Q0, 2) + 8 * e1sq + 24 * Math.pow(t0, 2)) * Math.pow(dd0, 5) / 120;
        var _a2 = (lof1 - lof2 + lof3) / Math.cos(phi1);
        var _a3 = _a2 * 180 / Math.PI;
        var buff_lat = (180 * (phi1 - fact1 * (fact2 + fact3 + fact4)) / Math.PI).toFixed(7);
        var buff_lon = ((((zone) > 0) && (6 * (zone) - 183.0) || 3.0) - _a3).toFixed(7);
        // Performs conversion algebra to convert UTM coordinates to decimal degrees and rounds points to 7 decimal places
        var coord_pair = buff_lat+" "+buff_lon+"; ";
        coordinates += coord_pair;      
        // Concatenates strings to following format: "lat1 long1; lat2 long2; "
        // Concatenates coordinate pair to stringified list of pairs
    }
    return coordinates;
}
0 Kudos
Rebecca_LiljaFS
Occasional Contributor

This is great work!  Has anyone successfully applied this method to buffer a line?

0 Kudos
rrhee_bcfpd
Emerging Contributor

Not 100% sure, but it might be possible. You would need to find a way to pull an array of coordinates for all vertices in your line or use repeat geopoint questions to construct that array and the geotrace simultaneously (https://community.esri.com/t5/arcgis-survey123-questions/exposing-geotrace-and-geoshape-vertices-for...). JavaScript would then need to loop through that array to determine each vertex in the buffer polygon. However, the script would get substantially more complex if it needs to handle parsing the correct angle for each vertex to buffer out along.

 

If it's not required to see the buffer on the same form as the one you're collecting the line on, you can use webhooks to trigger a function hosted on AWS or Azure to generate the buffer after the survey is submitted, or even use PowerAutomate or Make.com to make a series of requests to the ArcGIS REST API's buffer & edit endpoints with JSON parsing between each step.

0 Kudos