how can I select point features that are within a certain buffer zone to a mouse click on the map?
Solved! Go to Solution.
Evon,
Here is a sample:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query features in 1mile radius - 4.5</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
<script src="https://js.arcgis.com/4.5/"></script>
<script>
var flView;
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/Color",
"esri/geometry/Circle",
"esri/Graphic",
"esri/tasks/support/Query",
"esri/renderers/SimpleRenderer",
"dojo/dom",
"dojo/domReady!"
],
function(
Map, MapView,
FeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Color,
Circle, Graphic, Query, SimpleRenderer, dom
) {
var map = new Map({
basemap: "dark-gray"
});
var view = new MapView({
container: "mapDiv",
map: map,
center: [-73.950, 40.702],
zoom: 11,
padding: {
top: 32
}
});
// Create the FeatureLayer using the popupTemplate
var featureLayer = new FeatureLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0",
outFields: ["POP2000"],
visible: false
});
// Make unselected features invisible
// var nullSymbol = new SimpleMarkerSymbol();
// nullSymbol.size = 0;
// featureLayer.renderer = new SimpleRenderer(nullSymbol);
map.add(featureLayer);
var circleSymb = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_NULL,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SHORTDASHDOTDOT,
new Color([105, 105, 105]),
2
), new Color([255, 255, 0, 0.25])
);
view.whenLayerView(featureLayer).then(function(lyrView) {
flView = lyrView;
view.on("click", doBuffer);
});
function doBuffer(evt) {
dom.byId("messages").innerHTML = "Calculating…"
circle = new Circle({
center: evt.mapPoint,
geodesic: true,
radius: 1,
radiusUnit: "miles"
});
view.graphics.removeAll();
var graphic = new Graphic(circle, circleSymb);
view.graphics.add(graphic);
var query = featureLayer.createQuery();
query.geometry = circle.extent;
query.outSpatialReference = view.spatialReference;
// Use a fast bounding box query. It will only go to the server if bounding box is outside of the visible map.
featureLayer.queryFeatures(query).then(selectInBuffer);
}
function selectInBuffer(response) {
var feature;
var features = response.features;
var inBuffer = [];
// Filter out features that are not actually in buffer, since we got all points in the buffer's bounding box
for (var i = 0; i < features.length; i++) {
feature = features[i];
if (circle.contains(feature.geometry)) {
inBuffer.push(feature.attributes[featureLayer.objectIdField]);
}
}
var query = featureLayer.createQuery();
query.objectIds = inBuffer;
query.outSpatialReference = view.spatialReference;
var symbol = new SimpleMarkerSymbol(
SimpleMarkerSymbol.STYLE_CIRCLE,
12,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_NULL,
new Color([247, 34, 101, 0.9]),
1
),
new Color([207, 34, 171, 0.5])
);
// Use an objectIds selection query (should not need to go to the server)
featureLayer.queryFeatures(query).then(function(results) {
var graArr = [], graphic;
results.features.map( function(feat){
graphic = new Graphic(feat.geometry, symbol);
graArr.push(graphic);
});
view.graphics.addMany(graArr);
var totalPopulation = sumPopulation(results.features);
var r = "";
r = "<b>The total Census Block population within the buffer is <i>" + totalPopulation + "</i>.</b>";
dom.byId("messages").innerHTML = r;
});
}
function sumPopulation(features) {
var popTotal = 0;
for (var x = 0; x < features.length; x++) {
popTotal = popTotal + features[x].attributes["POP2000"];
}
return popTotal;
}
});
</script>
<style>
html,
body,
#mapDiv {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-family: sans-serif;
}
.panel-container {
position: relative;
width: 100%;
height: 100%;
}
.panel-side {
padding: 2px;
box-sizing: border-box;
width: 100%;
height: 32px;
position: absolute;
top: 0;
right: 0;
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
overflow: auto;
z-index: 60;
}
#census_div {
height: 100%
}
#messages {
line-height: 30px;
}
</style>
</head>
<body>
<div class="panel-container">
<div class="panel-side">
<div id="census_div">
<span id="messages">Click on the map to select census block points within 1 mile.</span>
</div>
</div>
<div id="mapDiv"></div>
</div>
</body>
</html>
Evon,
Here is a sample:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query features in 1mile radius - 4.5</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
<script src="https://js.arcgis.com/4.5/"></script>
<script>
var flView;
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/Color",
"esri/geometry/Circle",
"esri/Graphic",
"esri/tasks/support/Query",
"esri/renderers/SimpleRenderer",
"dojo/dom",
"dojo/domReady!"
],
function(
Map, MapView,
FeatureLayer, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Color,
Circle, Graphic, Query, SimpleRenderer, dom
) {
var map = new Map({
basemap: "dark-gray"
});
var view = new MapView({
container: "mapDiv",
map: map,
center: [-73.950, 40.702],
zoom: 11,
padding: {
top: 32
}
});
// Create the FeatureLayer using the popupTemplate
var featureLayer = new FeatureLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/0",
outFields: ["POP2000"],
visible: false
});
// Make unselected features invisible
// var nullSymbol = new SimpleMarkerSymbol();
// nullSymbol.size = 0;
// featureLayer.renderer = new SimpleRenderer(nullSymbol);
map.add(featureLayer);
var circleSymb = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_NULL,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SHORTDASHDOTDOT,
new Color([105, 105, 105]),
2
), new Color([255, 255, 0, 0.25])
);
view.whenLayerView(featureLayer).then(function(lyrView) {
flView = lyrView;
view.on("click", doBuffer);
});
function doBuffer(evt) {
dom.byId("messages").innerHTML = "Calculating…"
circle = new Circle({
center: evt.mapPoint,
geodesic: true,
radius: 1,
radiusUnit: "miles"
});
view.graphics.removeAll();
var graphic = new Graphic(circle, circleSymb);
view.graphics.add(graphic);
var query = featureLayer.createQuery();
query.geometry = circle.extent;
query.outSpatialReference = view.spatialReference;
// Use a fast bounding box query. It will only go to the server if bounding box is outside of the visible map.
featureLayer.queryFeatures(query).then(selectInBuffer);
}
function selectInBuffer(response) {
var feature;
var features = response.features;
var inBuffer = [];
// Filter out features that are not actually in buffer, since we got all points in the buffer's bounding box
for (var i = 0; i < features.length; i++) {
feature = features[i];
if (circle.contains(feature.geometry)) {
inBuffer.push(feature.attributes[featureLayer.objectIdField]);
}
}
var query = featureLayer.createQuery();
query.objectIds = inBuffer;
query.outSpatialReference = view.spatialReference;
var symbol = new SimpleMarkerSymbol(
SimpleMarkerSymbol.STYLE_CIRCLE,
12,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_NULL,
new Color([247, 34, 101, 0.9]),
1
),
new Color([207, 34, 171, 0.5])
);
// Use an objectIds selection query (should not need to go to the server)
featureLayer.queryFeatures(query).then(function(results) {
var graArr = [], graphic;
results.features.map( function(feat){
graphic = new Graphic(feat.geometry, symbol);
graArr.push(graphic);
});
view.graphics.addMany(graArr);
var totalPopulation = sumPopulation(results.features);
var r = "";
r = "<b>The total Census Block population within the buffer is <i>" + totalPopulation + "</i>.</b>";
dom.byId("messages").innerHTML = r;
});
}
function sumPopulation(features) {
var popTotal = 0;
for (var x = 0; x < features.length; x++) {
popTotal = popTotal + features[x].attributes["POP2000"];
}
return popTotal;
}
});
</script>
<style>
html,
body,
#mapDiv {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-family: sans-serif;
}
.panel-container {
position: relative;
width: 100%;
height: 100%;
}
.panel-side {
padding: 2px;
box-sizing: border-box;
width: 100%;
height: 32px;
position: absolute;
top: 0;
right: 0;
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
overflow: auto;
z-index: 60;
}
#census_div {
height: 100%
}
#messages {
line-height: 30px;
}
</style>
</head>
<body>
<div class="panel-container">
<div class="panel-side">
<div id="census_div">
<span id="messages">Click on the map to select census block points within 1 mile.</span>
</div>
</div>
<div id="mapDiv"></div>
</div>
</body>
</html>
Thanks for replying, I will take a look at this now. i have been trying to do it on my own but for the past 2 days not working as I would like it to.
Robert's answer is a good client-side method.
Another option is to do this on the backend with an IdentifyTask: IdentifyTask | API Reference | ArcGIS API for JavaScript 4.5 or just by querying a feature service with some geometry (a circle maybe).
These are only possible if your data is contained in a feature service/map service.
Yea my data was pushed by the server admins to a service which I call each layer from, not sure if server or client side way would be the most efficient but I normally make server calls when querying data rather than layer queries. Maybe I am being inefficient?
Evon,
Depends on whether you are already showing the layer in the map and have access to the layer object.
Don't forget to mark this question as answered by clicking on the "Mark Correct" link on the reply that answered your question.
Well I guess I will have to add the feature layer as well as the symbolized map image layer to the map.
Evon,
If you are using a map image layer then you would be best to continue using QueryTask and Query then.