Draw buffer around points in a feature layer

1468
3
Jump to solution
05-12-2022 10:41 AM
cptstubing16
New Contributor

Hello all.

I'm a very much new to JS and so am simply copying and pasting code from samples to make this custom widget.

This is simply a hardcoded widget that when enabled will create buffers around a points hosted feature layer in AGOL (my own content).  My end goal is to use a field with distance values for the buffer sizes, but for now I just want them to draw a uniform buffer.

When I click on Enable Buffer, I don't see anything, but I'm not getting any error messages.  I'm using this in CodePen.

This is the code I'm using. The bold parts are where I think there could be an issue.  (I removed the style and html portion).

Much appreciate any feedback.

 

JS :

require([
"esri/config",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/renderers/SimpleRenderer",
"esri/Graphic",
"esri/layers/GraphicsLayer",
"esri/geometry/geometryEngine"

], function(esriConfig, Map, MapView, FeatureLayer, SimpleRenderer, Graphic, GraphicsLayer, geometryEngine) {

esriConfig.apiKey = "deleted";

//add basemap
const map = new Map({
basemap: "arcgis-imagery" //Basemap layer service
});

//add map view
const view = new MapView({
map: map,
center: [31.205, 49.627], //Longitude, latitude
zoom: 8,
container: "viewDiv"
});

//add new graphics layers for buffers
const graphicsLayer = new GraphicsLayer();
const resultsLayer = new GraphicsLayer();
map.addMany([graphicsLayer, resultsLayer]);


// define style for GPS points layer
let GPS_Renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
size: 6,
color: "orange",
outline: { // autocasts as new SimpleLineSymbol()
width: 0.5,
color: "white"
}
}
};

// add feature layer from URL --
const hitsGPS = new FeatureLayer({
url: "https://services8.arcgis.com/39j38RHYsO16guxW/arcgis/rest/services/GPS_Hits/FeatureServer",
renderer: GPS_Renderer
});

// add GPS layer to the map
map.add(hitsGPS);

// add controls to the top of the screen
view.ui.add(document.getElementById("controls"), "top-right");
document.getElementById("buffer").addEventListener("click", createBuffer);
document.getElementById("reset").addEventListener("click", resetGraphics);

 

// create buffer function

let bufferGraphic;
function createBuffer() {
if (bufferGraphic) {
return;
}

 

// execute buffer

const buffer = geometryEngine.geodesicBuffer(
hitsGPS.geometry,
100,
"kilometers"
);

// save resulting buffer as graphic 

bufferGraphic = new Graphic({
geometry: buffer,
symbol: {
type: "simple-fill",
color: [227, 139, 79, 0.25],
outline: {
color: [255, 255, 255, 255],
},
},
});

// add graphic to map
graphicsLayer.add(bufferGraphic);
}

// reset function

function resetGraphics() {
graphicsLayer.remove(bufferGraphic);
resultsLayer.removeAll();
bufferGraphic = null;
}
});
</script>
</head>
<body>

<div id="viewDiv"></div>
<div id="controls" class="esri-widget">
<button id="buffer" class="esri-button">Enable Buffer</button>
<button id="reset" class="esri-button esri-button--secondary">Disable Buffer</button>
</div>

</body>
</html>

0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

You can not call hitsGPS.geometry. HitsGPS is a featurelayer and does not have a geometry property you have to iterate over the results of a query on the featurelayer.  Something like this (untested code)

const sym = {
  type: "simple-fill",
  color: [227, 139, 79, 0.25],
  style: "solid",
  outline: {
    color: [255, 255, 255, 255],
    width: 1
  }
};
hitsGPS.queryFeatures().then(results){
  results.features.map(feat => {
    const buffer = geometryEngine.geodesicBuffer(feat.geometry, 100, "kilometers");
    bufferGraphic = new Graphic({geometry: buffer, symbol: sym});
    // add graphic to map
    graphicsLayer.add(bufferGraphic);
  });
}

  

View solution in original post

3 Replies
RobertScheitlin__GISP
MVP Emeritus

You can not call hitsGPS.geometry. HitsGPS is a featurelayer and does not have a geometry property you have to iterate over the results of a query on the featurelayer.  Something like this (untested code)

const sym = {
  type: "simple-fill",
  color: [227, 139, 79, 0.25],
  style: "solid",
  outline: {
    color: [255, 255, 255, 255],
    width: 1
  }
};
hitsGPS.queryFeatures().then(results){
  results.features.map(feat => {
    const buffer = geometryEngine.geodesicBuffer(feat.geometry, 100, "kilometers");
    bufferGraphic = new Graphic({geometry: buffer, symbol: sym});
    // add graphic to map
    graphicsLayer.add(bufferGraphic);
  });
}

  

cptstubing16
New Contributor

Robert,

Thanks for this answer.  I added the code and it works but the range ring doesn't appear but that's an Uncaught TypeError I will figure out.  But this looks promising.

If I wanted to use a field value for the distance instead of a hardcoded distance, is it possible to use a variable in place of the '100'?

Thanks again!

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Sure you can easily do that inside the feature loop.

hitsGPS.queryFeatures().then(results){
  results.features.map(feat => {
    const buffer = geometryEngine.geodesicBuffer(feat.geometry, parseInt(feat.attributes['someFieldName']), "kilometers");
    bufferGraphic = new Graphic({geometry: buffer, symbol: sym});
    // add graphic to map
    graphicsLayer.add(bufferGraphic);
  });
}