Greetings,
I was wondering if something like this could be achievable with Arcade?
Solved! Go to Solution.
I have a map that has multiple feature classes/services. They are project locations for different groups with basic attribute information like Project ID, Name, Type, Description, Project Manager, Estimated Begin and End date.
I was originally thinking of using the intersect and proximity functions in Arcade to create a pop up for projects that intersect or come within a certain proximity of each other and have overlapping dates.
Now thinking about it (it would be too busy with too many pop ups), it would probably be better to have a list generated that calls out projects that overlap or come within close proximity of each other and have overlapping dates instead of single pop ups for the whole map area.
Is this possible with just Arcade? Are there any existing similar examples of this? And how would one go about this?
Or would this need to be a web app with custom Java/Python scripting?
Thanks for any insight.
You can list the overlapping projects in a popup:
// load all project layers (including this one!)
var other_project_fcs = [
FeaturesetByName($map, "TestPoints"),
FeaturesetByName($map, "TestLines"),
FeaturesetByName($map, "TestPolygons"),
]
// buffer your project geometry
var project_buffer = Buffer($feature, 250, "feet")
var other_projects = []
// iterate over the project layers
for(var i in other_project_fcs) {
// find all projects intersecting the current project (buffered)
var nearby_projects = Intersects(project_buffer, other_project_fcs[i])
// iterate over those projects
for(var project in nearby_projects) {
// skip if the intersecting project is the current $feature
if($feature.ProjectID == project.ProjectID) { continue }
// get start and end dates
var start1 = $feature.BeginDate
var end1 = $feature.EndDate
var start2 = project.BeginDate
var end2 = project.EndDate
// skip if there is no time overlap
if(start1 > end2 || start2 > end1) { continue }
// calculate the time overlap
var overlap_start = Date(Max([Number(start1), Number(start2)]))
var overlap_end = Date(Min([Number(end1), Number(end2)]))
var overlap = DateDiff(overlap_end, overlap_start, "days") + 1
// describe the overlapping project
var dist = Round(Distance($feature, project, "feet"), 0)
var runtime = Text(start2, "MM/DD/Y") + " - " + Text(end2, "MM/DD/Y")
var project_text = [
"Project: " + project.Project,
"Contact: " + project.Contact,
"Distance: " + dist + " feet",
"Runstime: " + runtime,
"Overlap: " + overlap + " days"
]
// append the desription to the array
Push(other_projects, Concatenate(project_text, "\n"))
}
}
// concatenate the descriptions and return
return Concatenate(other_projects, "\n\n")
You can modify the expression to fill a featureset with all pairs of overlapping projects and feed that featureset into a list widget in a Dashboard or Experience, no custom javascript neccessary.
Absolutely! Take a look at the Intersects function, as it's what you'll need to identify features that touch one another. For the proximity part, you can just buffer the input feature 250ft, and use the Distance function to get the distance between.
I have a map that has multiple feature classes/services. They are project locations for different groups with basic attribute information like Project ID, Name, Type, Description, Project Manager, Estimated Begin and End date.
I was originally thinking of using the intersect and proximity functions in Arcade to create a pop up for projects that intersect or come within a certain proximity of each other and have overlapping dates.
Now thinking about it (it would be too busy with too many pop ups), it would probably be better to have a list generated that calls out projects that overlap or come within close proximity of each other and have overlapping dates instead of single pop ups for the whole map area.
Is this possible with just Arcade? Are there any existing similar examples of this? And how would one go about this?
Or would this need to be a web app with custom Java/Python scripting?
Thanks for any insight.
You can list the overlapping projects in a popup:
// load all project layers (including this one!)
var other_project_fcs = [
FeaturesetByName($map, "TestPoints"),
FeaturesetByName($map, "TestLines"),
FeaturesetByName($map, "TestPolygons"),
]
// buffer your project geometry
var project_buffer = Buffer($feature, 250, "feet")
var other_projects = []
// iterate over the project layers
for(var i in other_project_fcs) {
// find all projects intersecting the current project (buffered)
var nearby_projects = Intersects(project_buffer, other_project_fcs[i])
// iterate over those projects
for(var project in nearby_projects) {
// skip if the intersecting project is the current $feature
if($feature.ProjectID == project.ProjectID) { continue }
// get start and end dates
var start1 = $feature.BeginDate
var end1 = $feature.EndDate
var start2 = project.BeginDate
var end2 = project.EndDate
// skip if there is no time overlap
if(start1 > end2 || start2 > end1) { continue }
// calculate the time overlap
var overlap_start = Date(Max([Number(start1), Number(start2)]))
var overlap_end = Date(Min([Number(end1), Number(end2)]))
var overlap = DateDiff(overlap_end, overlap_start, "days") + 1
// describe the overlapping project
var dist = Round(Distance($feature, project, "feet"), 0)
var runtime = Text(start2, "MM/DD/Y") + " - " + Text(end2, "MM/DD/Y")
var project_text = [
"Project: " + project.Project,
"Contact: " + project.Contact,
"Distance: " + dist + " feet",
"Runstime: " + runtime,
"Overlap: " + overlap + " days"
]
// append the desription to the array
Push(other_projects, Concatenate(project_text, "\n"))
}
}
// concatenate the descriptions and return
return Concatenate(other_projects, "\n\n")
You can modify the expression to fill a featureset with all pairs of overlapping projects and feed that featureset into a list widget in a Dashboard or Experience, no custom javascript neccessary.
Thanks Johannes. This is awesome. How would I generate the overlap feature and table that met the spatial and date conditions?
Was curious if a field like contact existed with an email, would it be possible to generate a notification to both project contacts if the conditions of location and dates is met?
How would I generate the overlap feature and table that met the spatial and date conditions?
Not sure what you're asking. Can you clarify?
if a field like contact existed with an email, would it be possible to generate a notification to both project contacts if the conditions of location and dates is met?
Probably, but not with Arcade. You can whip up a Python script that sends the mails. I think you could execute the script via a webhook when a new project is inserted, but I don't know anything about that.
Hi Johannes,
You mentioned towards the end of the response that its possible to modify the expression to fill a featureset with all pairs of overlapping projects and feed that featureset into a dashboard widget.
I was just asking how to modify the code to create that project overlap feature class and table.
Ah.
You can use this expression in a dashboard list/table:
// load all project layers (change to you layer ids)
var project_layers = [
FeaturesetByPortalItem(Portal("https://arcgis.com"), "b0d335151aad48a5883326b9aed69cdd", 0),
FeaturesetByPortalItem(Portal("https://arcgis.com"), "b0d335151aad48a5883326b9aed69cdd", 1),
FeaturesetByPortalItem(Portal("https://arcgis.com"), "b0d335151aad48a5883326b9aed69cdd", 2),
]
// read the project data (change to yoour fields)
var projects = []
for(var i in project_layers) {
for(var p in project_layers[i]) {
var project = {
name: p.TextField1,
contact: p.TextField2,
start: p.DateField1,
end: p.DateField2,
geo: Geometry(p),
b_geo: Buffer(p, 250, "feet"),
}
Push(projects, project)
}
}
// create the output dictionary
var out_dict = {
fields: [
{name: "Project1", type: "esriFieldTypeString"},
{name: "Contact1", type: "esriFieldTypeString"},
{name: "Runtime1", type: "esriFieldTypeString"},
{name: "Project2", type: "esriFieldTypeString"},
{name: "Contact2", type: "esriFieldTypeString"},
{name: "Runtime2", type: "esriFieldTypeString"},
{name: "Distance", type: "esriFieldTypeDouble"},
{name: "Overlap", type: "esriFieldTypeInteger"},
],
geometryType: "",
features: []
}
// find overlapping projects
for(var p in projects) {
for(var q = p + 1; q < Count(projects); q++) {
var p1 = projects[p]
var p2 = projects[q]
// skip if no spatial overlap
if(!Intersects(p1.b_geo, p2.geo)) { continue }
// skip if no temporal overlap
if(p1.start > p2.end || p2.start > p1.end) { continue }
// calculate temporal overlap
var overlap_start = Date(Max([Number(p1.start), Number(p2.start)]))
var overlap_end = Date(Min([Number(p1.end), Number(p2.end)]))
var overlap = DateDiff(overlap_end, overlap_start, "days") + 1
// append the project pair to output
var pair = {
Project1: p1.name,
Contact1: p1.contact,
Runtime1: Text(p1.start, "MM/DD/Y") + " - " + Text(p1.end, "MM/DD/Y"),
Project2: p2.name,
Contact2: p2.contact,
Runtime2: Text(p2.start, "MM/DD/Y") + " - " + Text(p2.end, "MM/DD/Y"),
Distance: Distance(p1.geo, p2.geo),
Overlap: overlap,
}
Push(out_dict.features, {attributes: pair})
}
}
// convert to Featrueset and return
return Featureset(Text(out_dict))
With the expression set up like this, it will return one entry for each pair of overlapping projects:
You can replace line 41 with this:
for(var q in projects) {
if(p == q) { continue }
Then you will get two entries for each pair of overlapping projects: