Several years ago, I (with help from this fine community) developed a simple app that, when a user searched for a location (address, XY, etc.) using the search widget, a featurelayer was also queried and a pop-up would provide information from that feature layer. Example: an individual would enter an address and the search widget would query a state house district layer, resulting in a pop-up with info. about the district in which the address occurs (code snippet below to show what was done).
searchWidget.on('select-result', function(evt){
let query = hsb.createQuery();
query.geometry = evt.result.feature.geometry;
query.spatialRelationship = 'within';
query.outFields = ['*'];
query.returnGeometry = true;
query.outSpatialReference = view.spatialReference;
query.maxAllowableOffset = 0;
hsb.queryFeatures(query).then(function(result){
view.popup.open({
features: result.features,
location: result.features[0].geometry.centroid
});
});
});
We now have a need to do this for taxable jurisdictions. However, a single location can fall within multiple taxable jurisdictions (e.g. county, municipality, etc.), necessitating querying multiple layers and, ideally, returning a single pop-up.
The quickest, easiest solution would be to union the various layers and then query against it, but these data are dynamic, so being able to query each layer individually and returning the results at once is a better solution.
Anyone have any examples of something comparable I could use as a potential guide?
I would approach it in two steps - querying multiple layers, and then combining those results to display in a popup.
This is a rough crude example that I quick hacked up from the popup-domnode sample found here:
https://developers.arcgis.com/javascript/latest/sample-code/sandbox/?sample=popup-domnode
I've just got a sceneView, and added two sample layers onto the map for it.
On click I get the click location, buffer simply so I can get more results, and then use that bufferedPoint geometry to query the layers I added.
Once I have the results of the query I pass it to a function that generates some simple HTML that will be set as the contents of the Popup.
It's a pretty quick and dirty example, but illustrates the two key steps, querying for features, and then passing it onto the popup to display.
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Popup with DOM node | Sample | ArcGIS Maps SDK for JavaScript 4.31</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.31/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.31/"></script>
<style>
html,
body,
#sceneViewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
.mapView {
height: 400px;
border: 1px solid #a8a8a8;
}
.esri-popup.esri-widget {
max-height: 100%;
}
.esri-view-width-xlarge .esri-popup__main-container {
width: 580px;
}
.esri-view-height-less-than-medium .esri-popup__main-container {
max-height: 500px;
}
</style>
<script>
require(["esri/layers/FeatureLayer", "esri/Map", "esri/WebScene", "esri/views/MapView", "esri/views/SceneView", "esri/geometry/geometryEngine"], (
FeatureLayer,
Map,
WebScene,
MapView,
SceneView,
geometryEngine
) => {
// Create the map from the given web scene id
const map = new WebScene({
portalItem: {
id: "5a392557cffb485f8fe004e668e9edc0"
}
});
const layer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/US_National_Parks_Annual_Visitation/FeatureServer/0",
outFields: ["*"]
});
const crimeLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/ArcGIS/rest/services/SF%20Crimes%20by%20Block%20Group/FeatureServer/0",
outFields: ["*"]
});
map.addMany([layer, crimeLayer]);
// Create the SceneView
const sceneView = new SceneView({
map: map,
container: "sceneViewDiv",
center: [-97.75188, 37.23308],
zoom: 5,
popup: {
actions: [],
dockEnabled: true,
dockOptions: {
buttonEnabled: true,
breakpoint: false
}
}
});
// Listen for when the scene view is ready
sceneView.when(() => {
// It's necessary to overwrite the default click for the popup
// behavior in order to display your own popup
sceneView.popupEnabled = false;
sceneView.on("click", async (event) => {
// Create lat/lon vars to display in popup title
const lat = Math.round(event.mapPoint.latitude * 1000) / 1000;
const lon = Math.round(event.mapPoint.longitude * 1000) / 1000;
const point = sceneView.toMap(event);
//Create a buffered point for querying features
const bufferedPoint = geometryEngine.geodesicBuffer(point, 100, "kilometers");
//Query each layer we're interested in
const firstQuery = layer.queryFeatures({
geometry: bufferedPoint,
outFields: ["*"]
});
const secondQuery = crimeLayer.queryFeatures({
geometry: bufferedPoint,
outFields: ["*"]
});
//Wait for the results of the queries
const results = await Promise.all([firstQuery, secondQuery])
//Pass those results to a popup via a function called 'setContentInfo' with the results
sceneView.openPopup({
// Set the popup's title to the coordinates of the location
title: "Map view coordinates: [" + lon + ", " + lat + "]",
location: event.mapPoint, // Set the location of the popup to the clicked location
content: setContentInfo(results)
});
});
function setContentInfo(results) {
//Create an HTML element to display our results
const popupDiv = document.createElement("div");
popupDiv.classList.add("mapView");
popupDiv.innerHTML = `Results count of first query = ${results[0].features.length},
Results count of second query = ${results[1].features.length}`
// Return a dom node
return popupDiv;
}
});
});
</script>
</head>
<body>
<div id="sceneViewDiv"></div>
</body>
</html>
Excellent. I will give it a shot and see how it works on my end.
Greatly appreciated.
Todd