Hey everyone,
I've been currently working on a JavaScript API application and I'm stuck on how to formulate a query based on a polygon's geometry...
Right now I have a layer containing a set of polygons and another layer with a set of points. I have a query that returns a set points based on the radius of a bufferGraphic.
Now I need to query these points if they fall within a polygon selection; i.e. the user clicks on the polygon which he/she wants to query and then return the same data as this current code I wrote does.
Any assistance on how to accomplish this would be a huge help! @BlakeTerhune
<html>
<body>
<button id="myButton" type>Query Selected Datasets</button>
<button id="myButton2" type>Query Selected Datasets within Polygons</button>
<div id="viewDiv"></div>
<div id="panel"></div>
<div id="mySQL"></div>
</body>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>ArcGIS API for Javascript: SCCWRP Water</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 95%;
width: 100%;
}
#titleDiv {
padding: 10px;
}
#titleText {
font-size: 20pt;
font-weight: 60;
padding-bottom: 10px;
}
</style>
<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/css/main.css">
<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script>
<script src="https://js.arcgis.com/4.21/"></script>
<script>
json_array = [];
// set distance and units - get dots within that boundary
distance = 0.5;
units = "miles";
require([
"esri/Map",
"esri/Graphic",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/widgets/LayerList",
"esri/renderers/SimpleRenderer",
"esri/symbols/SimpleFillSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/renderers/UniqueValueRenderer",
"esri/widgets/Legend",
"esri/widgets/BasemapGallery",
"esri/widgets/Expand",
"esri/core/watchUtils",
], function (Map, Graphic, MapView, FeatureLayer, LayerList, SimpleRenderer, SimpleLineSymbol, UniqueValueRenderer, SimpleFillSymbol, Legend, BasemapGallery, Expand, watchUtils) {
const map = new Map({ // creating a new map
basemap: "satellite"
});
var view = new MapView({ // take that new map we just made above and display it
container: "viewDiv",
map: map,
// center: [-118.243683, 34.052235],
// zoom: 5,
popup: {
autoOpenEnabled: false,
dockEnabled: true,
dockOptions: {
// dock popup at bottom-right side of view
buttonEnabled: true,
breakpoint: false,
position: "bottom-right"
}
}
});
// County label + renderer + feature layer + add layer
const countyLabel = ({
symbol: {
type: "text", // autocasts as new TextSymbol()
color: "white",
font: { // autocast as new Font()
family: "Playfair Display",
size: 12,
weight: "regular"
}
},
labelPlacement: "above-center",
labelExpressionInfo: {
expression: "$feature.NAME_PCASE"
},
deconflictionStrategy: "none"
});
const countyRend = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [0, 76, 115, 0.1],
outline: { // autocasts as new SimpleLineSymbol()
width: 1,
color: "white"
}
}
};
const counties = new FeatureLayer({
url: "https://gis.sccwrp.org/arcserver/rest/services/Hosted/Counties/FeatureServer",
renderer: countyRend,
title: "Counties",
labelingInfo: countyLabel
});
map.add(counties);
// Stations label + renderer + feature layer + add layer
let renderer = {
type: "unique-value",
field: "grp",
uniqueValueInfos: [{
value: "Projects",
symbol: {
size: 3,
type: "simple-marker",
color: [0, 255, 255],
outline: null
},
label: "Projects"
}, {
value: "Regional Monitoring",
symbol: {
size: 3,
type: "simple-marker",
color: [0, 0, 139],
outline: null
},
label: "Regional Monitoring"
}]
};
const layer = new FeatureLayer({
// autocasts as new PortalItem()
portalItem: {
id: "4ce8725b7968421eaa945025e2eca221"
},
renderer: renderer,
outFields: ["*"]
});
map.add(layer);
// Merging the 2 files together...
//create graphic for mouse point click
// Create graphic for distance buffer
const pointGraphic = new Graphic({
symbol: {
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
color: [0, 0, 139],
outline: {
color: [255, 255, 255],
width: 1.5
}
}
});
const bufferGraphic = new Graphic({
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [173, 216, 230, 0.2],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 1
}
}
});
layer.load().then(() => {
// Set the view extent to the data extent
view.extent = layer.fullExtent;
layer.popupTemplate = layer.createPopupTemplate();
loadLayerList();
});
view.on("click", (event) => {
view.graphics.remove(pointGraphic);
if (view.graphics.includes(bufferGraphic)) {
view.graphics.remove(bufferGraphic);
}
queryFeatures(event);
});
function findLayerByTitle(title) {
return view.map.allLayers.find(function (layer) {
console.log(layer.title);
return layer.title === title;
});
};
let layerList, analysisLayer;
function loadLayerList() {
console.log("loadLayerList");
console.log(json_array);
};
function queryFeatures(screenPoint) {
console.log("click:");
const point = view.toMap(screenPoint);
console.log(point);
console.log(point.latitude);
console.log(point.longitude);
layer
.queryFeatures({
geometry: point,
distance: distance,
units: units,
spatialRelationship: "intersects",
returnGeometry: false,
returnQueryGeometry: true,
outFields: ["*"]
})
.then((featureSet) => {
// set graphic location to mouse pointer and add to mapview
pointGraphic.geometry = point;
view.graphics.add(pointGraphic);
// open popup of query result
console.log(featureSet);
console.log(featureSet);
view.popup.open({
location: point,
features: featureSet.features,
featureMenuOpen: true
});
if (featureSet.queryGeometry) {
bufferGraphic.geometry = featureSet.queryGeometry;
view.graphics.add(bufferGraphic);
}
featureSet.features.forEach(function (item, index) {
//console.log(featureSet.features[index].attributes);
json_array.push(featureSet.features[index].attributes);
//console.log(featureSet.features[0].attributes);
});
});
};
// Query the layer view for statistics on each analysis variable in the layer
function queryLayerViewStats(layerView) {
query = layerView.layer.createQuery();
query.geometry = layerView.extent;
return layerView.queryFeatures(query).then(function (response) {
stats = response.features[0].attributes;
});
};
function formatTable(station, origin_fname, datatype, json) {
console.log("formatTable");
stationdiv = "#" + CSS.escape(station) + "-" + CSS.escape(datatype);
var el = document.querySelector(stationdiv);
console.log(el);
fieldnames = [];
fieldvalues = [];
Object.keys(json.fields).forEach(function (item) {
fieldnames.push(json.fields[item].name);
});
Object.keys(json.features).forEach(function (feature_index) {
fieldvalues[feature_index] = json.features[feature_index].attributes;
});
console.log(fieldnames);
console.log(fieldvalues);
if (json.fields != "empty") {
let table = new simpleDatatables.DataTable(stationdiv, {
data: {
headings: fieldnames,
data: fieldvalues.map(item => Object.values(item))
},
});
} else {
console.log("empty");
};
};
function retrieveData(station, origin_fname, datatype, url) {
h4 = ""
table = document.createElement("table"),
h4 = document.createElement("h4"),
table.id = station + "-" + datatype;
h4.innerHTML = table.id;
document.body.appendChild(h4);
document.body.appendChild(table);
search_url = url + "/query?where=" + origin_fname + "='" + station + "'&outFields=*&f=json";
console.log("search_url:" + search_url);
protocol = "GET";
fetch(search_url, { method: protocol, cache: "no-cache", }).then(function (response) { return response.json(); }).then(function (data) { console.log(data); formatTable(station, origin_fname, datatype, data); }).catch(function (err) { console.log("We had a problem Houston", err); });
};
document.querySelector('#myButton').addEventListener("click", function (event, ui) {
str = " ";
json_array.forEach(function (item, index) {
console.log(item);
str += retrieveData(item.stationid, item.origin_fname, item.dtp, item.link);
});
console.log(str);
});
var layerlist = new LayerList({ // this right here creates a layerlist or "dropdown" menu so that one can toggle off / on any of the layers that are present
view: view
});
var basemapGallery = new BasemapGallery({ // This right here provides the gallery of basemaps users can pull from. I think.
view: view,
container: document.createElement("div")
});
var bgExpand = new Expand({ // This gives users the ability to choose which basemap they want to use
view: view,
content: basemapGallery
});
var legend = new Expand({
content: new Legend({
view: view,
style: "classic"
}),
view: view,
expanded: true
});
view.ui.add(layerlist, { position: "bottom-right" });
view.ui.add(bgExpand, "top-left");
view.ui.add(legend, "bottom-left");
view.ui.add("titleDiv", "top-right"); // for "SCCWRP California Water Data" title on top right
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div id="titleDiv" class="esri-widget">
<div id="titleText">SCCWRP California Water Data</div>
</body>
</html>
s the data of each point
Solved! Go to Solution.
Use hittest() to get the polygon clicked. Use the geometry of the graphic returned in the HitTestResult to query the points layer just like you do with the buffer (except no distance).
Hi there,
I shared a very simple test app that showcases what you are asking a while back in one of the threads. Hopefully, you can find it helpful. https://codepen.io/U_B_U/pen/bGgaBKX?editors=1000
Hi @Anonymous User
You might help this sample https://developers.arcgis.com/javascript/latest/sample-code/highlight-features-by-geometry/
Hi @Vakhtang_Zubiashvili thanks for sharing this code sample and I will take a deep look at it.
Instead of having users draw a rectangle, would there be any way to click on a polygon and have that instead in returning the points?
Use hittest() to get the polygon clicked. Use the geometry of the graphic returned in the HitTestResult to query the points layer just like you do with the buffer (except no distance).
I didn't even consider using the hittest() functionality; thanks for bringing this to my attn. Would you happen to be aware of any sample code I can draw from? Thanks in advance
Here is the sample linked in the documentation.
Access features with pointer events | Sample Code | ArcGIS API for JavaScript 4.22 | ArcGIS Develope...
Hi there,
I shared a very simple test app that showcases what you are asking a while back in one of the threads. Hopefully, you can find it helpful. https://codepen.io/U_B_U/pen/bGgaBKX?editors=1000
Thanks @UndralBatsukh! This is helping me greatly
I saw your codepen and I am also trying to do something similar but the only difference is I want the total of the point be displayed in a pop up when I click on a state. Do you have any idea of how to do that ?
Any ideas will be welcome. @UndralBatsukh
Thank you.
also check this, might be helpfull for you:
https://developers.arcgis.com/javascript/latest/find-length-and-area/