Skip to content

Instantly share code, notes, and snippets.

@ecaldwell
Last active March 22, 2016 14:33
Show Gist options
  • Save ecaldwell/aede10fbe2bf24370c8e to your computer and use it in GitHub Desktop.
Save ecaldwell/aede10fbe2bf24370c8e to your computer and use it in GitHub Desktop.
A node script to simulate movement in a point feature service, overlay with a grid feature service, and update both.
{
"dependencies": {
"promise": "^7.0.4",
"request": "^2.65.0",
"terraformer": "^1.0.5",
"terraformer-arcgis-parser": "^1.0.4",
"turf": "^2.0.2"
}
}
var request = require("request");
var Promise = require("promise");
exports.generateToken = function(portal, username, password, expiration, referer) {
expiration = typeof expiration !== "undefined" ? expiration : 60;
referer = typeof referer !== "undefined" ? referer : "http://esri.com";
var params = {
username: username,
password: password,
client: "referer",
referer: referer,
expiration: expiration,
f: "json"
};
var promise = new Promise(function(resolve) {
request({
url: portal + "/sharing/rest/generateToken",
method: "POST",
json: true,
qs: params,
body: ""
}, function(error, response, body) {
if (error) {
console.log(error);
} else if (!error && response.statusCode == 200) {
resolve(body);
}
});
});
return promise;
};
var request = require("request");
exports.query = function(service, token, returnGeometry, outFields, definition, spatialReference) {
returnGeometry = typeof returnGeometry !== "undefined" ? returnGeometry : true;
outFields = typeof outFields !== "undefined" ? outFields : "*";
definition = typeof definition !== "undefined" ? definition : "1=1";
spatialReference = typeof spatialReference !== "undefined" ? spatialReference : 4326;
var params = {
returnGeometry: returnGeometry,
outFields: outFields,
where: definition,
outSR: spatialReference,
f: "json",
token: token
};
var promise = new Promise(function(resolve) {
request({
url: service + "/query",
method: "GET",
json: true,
qs: params
}, function(error, response, body) {
if (error) {
console.log(error);
} else if (!error && response.statusCode == 200) {
resolve(body);
}
});
});
return promise;
};
exports.updateFeatures = function(service, token, features) {
var params = {
f: "json",
token: token
};
var promise = new Promise(function(resolve) {
request({
url: service + "/updateFeatures",
method: "POST",
qs: params,
formData: {features: JSON.stringify(features)}
}, function(error, response, body) {
if (error) {
console.log(error);
} else if (!error && response.statusCode == 200) {
resolve(JSON.parse(body));
}
});
});
return promise;
};
module.exports = {
auth: require("./portal-auth"),
services: require("./portal-services")
};
var portal = require("./portal");
var Terraformer = require("terraformer");
Terraformer.ArcGIS = require("terraformer-arcgis-parser");
var turf = require("turf");
var pointService = "http://services.arcgis.com/hRUr1F8lE8Jq2uJo/ArcGIS/rest/services/Bike_Cops_Simulated/FeatureServer/0";
var overlayService = "http://services.arcgis.com/hRUr1F8lE8Jq2uJo/arcgis/rest/services/Phila_Bike_Grid_Simulated/FeatureServer/0";
var myPortal = "https://www.arcgis.com";
var username = process.env.AGO_USERNAME;
var password = process.env.AGO_PASSWORD;
var distance = 0.1;
var distanceUnits = "kilometers"; // miles, kilometers, degrees, radians
var frequency = 5; // Update interval in seconds.
function randomHeading(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
console.log("Moving points " + distance + " " + distanceUnits + " every " + frequency + " seconds.");
portal.auth.generateToken(myPortal, username, password).then(function(response) {
var token = response.token;
setInterval(function() {
// Get the current set of features from each service.
Promise.all([
portal.services.query(pointService, token),
portal.services.query(overlayService, token)
]).then(function(results) {
var pointResults = results[0];
var overlayResults = results[1];
var pointFeatures = pointResults.features;
var newPoints = [];
var pointCollection = {
type: "FeatureCollection",
features: []
};
var overlayFeatures = overlayResults.features;
var overlayCollection = {
type: "FeatureCollection",
features: []
};
overlayFeatures.forEach(function(feature) {
overlayCollection.features.push(Terraformer.ArcGIS.parse(feature).toJSON());
});
var envelope = turf.envelope(overlayCollection);
console.log("");
console.log("Processing " + pointResults.features.length + " features.");
pointFeatures.forEach(function(feature) {
var geojsonF = Terraformer.ArcGIS.parse(feature);
var destination;
var inside;
// Ensure the points stay inside the overlay extent.
do {
destination = turf.destination(geojsonF, distance, randomHeading(-180, 180), distanceUnits);
inside = turf.inside(destination, envelope);
}
while (inside !== true);
pointCollection.features.push(destination);
var newPoint = feature;
newPoint.geometry.x = destination.geometry.coordinates[0];
newPoint.geometry.y = destination.geometry.coordinates[1];
newPoint.geometry.spatialReference = {wkid: 4326};
newPoints.push(newPoint);
});
var aggregate = turf.aggregate(overlayCollection, pointCollection, [{aggregation: "count", inField: "", outField: "Count_"}]);
var newOverlay = Terraformer.ArcGIS.convert(aggregate);
newOverlay.forEach(function(feature) {
delete feature.geometry;
});
// Update everything.
Promise.all([
portal.services.updateFeatures(pointService, token, newPoints),
portal.services.updateFeatures(overlayService, token, newOverlay)
]).then(function(updates) {
var pointUpdate = updates[0];
var overlayUpdate = updates[1];
if (pointUpdate.updateResults) {
// Summarize the results.
var pointSummary = {success: 0, fail: 0};
pointUpdate.updateResults.forEach(function(result) {
if (result.success === true) {
pointSummary.success += 1;
} else {
pointSummary.fail += 1;
}
});
console.log("Updated " + pointSummary.success + " point features (" + pointSummary.fail + " failed)");
}
if (overlayUpdate.updateResults) {
// Summarize the results.
var overlaySummary = {success: 0, fail: 0};
overlayUpdate.updateResults.forEach(function(result) {
if (result.success === true) {
overlaySummary.success += 1;
} else {
overlaySummary.fail += 1;
}
});
console.log("Updated " + overlaySummary.success + " overlay features (" + overlaySummary.fail + " failed)");
}
});
});
}, frequency * 1000);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment