Select to view content in your preferred language

Arcade Pop Ups and Lists for features that intersect or are in close proximity

1906
6
Jump to solution
02-16-2023 03:36 PM
Labels (3)
ChrisSpadi
Occasional Contributor

Greetings,

I was wondering if something like this could be achievable with Arcade?

ChrisSpadi_0-1676590495032.png

 

0 Kudos
1 Solution

Accepted Solutions
JohannesLindner
MVP Frequent Contributor

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")

 

JohannesLindner_0-1677057055189.png

JohannesLindner_1-1677057080213.png

 

JohannesLindner_2-1677057096407.png

 

JohannesLindner_3-1677057110497.png

 

JohannesLindner_5-1677057205806.png

 

 

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.


Have a great day!
Johannes

View solution in original post

6 Replies
jcarlson
MVP Esteemed Contributor

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.

- Josh Carlson
Kendall County GIS
0 Kudos
JohannesLindner
MVP Frequent Contributor

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")

 

JohannesLindner_0-1677057055189.png

JohannesLindner_1-1677057080213.png

 

JohannesLindner_2-1677057096407.png

 

JohannesLindner_3-1677057110497.png

 

JohannesLindner_5-1677057205806.png

 

 

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.


Have a great day!
Johannes
ChrisSpadi
Occasional Contributor

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?

0 Kudos
JohannesLindner
MVP Frequent Contributor

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.


Have a great day!
Johannes
0 Kudos
ChrisSpadi
Occasional Contributor

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.

0 Kudos
JohannesLindner
MVP Frequent Contributor

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:

JohannesLindner_3-1678366425415.png

 

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:

JohannesLindner_2-1678366345548.png

 


Have a great day!
Johannes