Anyone successfully set up a watch event (using watchUtils or some other kind of listener) on changes in the Graphics Layer? I got what I wanted working by watching the mapView for "updating" (code below) but that seems overkill because it fires with every map event, even ones that have nothing to do with graphics. I tried the following but it doesn't work:
watchUtils.on(graphicsLayer,"graphics","change",function(){
...
});
...and watchUtils.when(graphicsLayer.... only fired once, when the layer was added.
Here's what worked, just curious if it can be optimized/improved:
Solved! Go to Solution.
When you say the watchUtil didn't work, did nothing happen? When I used that in one of the samples, it fired once after all the graphics were added
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Add Graphics to a SceneView | Sample | ArcGIS API for JavaScript 4.19</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.19/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require(["esri/Map", "esri/views/SceneView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/core/watchUtils"], (
Map,
SceneView,
GraphicsLayer,
Graphic,
watchUtils
) => {
const map = new Map({
basemap: "hybrid"
});
const view = new SceneView({
container: "viewDiv",
map: map,
camera: {
// autocasts as new Camera()
position: {
// autocasts as new Point()
x: -0.17746710975334712,
y: 51.44543992422466,
z: 1266.7049653716385
},
heading: 0.34445102566290225,
tilt: 82.95536300536367
}
});
/*********************
* Add graphics layer
*********************/
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
watchUtils.on(graphicsLayer, "graphics", "change", () => {console.log('Graphics added!');});
/*************************
* Add a 3D point graphic
*************************/
// London
const point = {
type: "point", // autocasts as new Point()
x: -0.178,
y: 51.48791,
z: 1010
};
const markerSymbol = {
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
color: [226, 119, 40],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 2
}
};
const pointGraphic = new Graphic({
geometry: point,
symbol: markerSymbol
});
console.log('Add point');
graphicsLayer.add(pointGraphic);
/****************************
* Add a 3D polyline graphic
****************************/
const polyline = {
type: "polyline", // autocasts as new Polyline()
paths: [[-0.178, 51.48791, 0], [-0.178, 51.48791, 1000]]
};
const lineSymbol = {
type: "simple-line", // autocasts as SimpleLineSymbol()
color: [226, 119, 40],
width: 4
};
const polylineGraphic = new Graphic({
geometry: polyline,
symbol: lineSymbol
});
console.log('Add polyline');
graphicsLayer.add(polylineGraphic);
/***************************
* Add a 3D polygon graphic
***************************/
const polygon = {
type: "polygon", // autocasts as new Polygon()
rings: [
[-0.184, 51.48391, 400],
[-0.184, 51.49091, 500],
[-0.172, 51.49091, 500],
[-0.172, 51.48391, 400],
[-0.184, 51.48391, 400]
]
};
const fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 2
}
};
const polygonGraphic = new Graphic({
geometry: polygon,
symbol: fillSymbol
});
console.log('Add polygon');
graphicsLayer.add(polygonGraphic);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
When you say the watchUtil didn't work, did nothing happen? When I used that in one of the samples, it fired once after all the graphics were added
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Add Graphics to a SceneView | Sample | ArcGIS API for JavaScript 4.19</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.19/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.19/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require(["esri/Map", "esri/views/SceneView", "esri/layers/GraphicsLayer", "esri/Graphic", "esri/core/watchUtils"], (
Map,
SceneView,
GraphicsLayer,
Graphic,
watchUtils
) => {
const map = new Map({
basemap: "hybrid"
});
const view = new SceneView({
container: "viewDiv",
map: map,
camera: {
// autocasts as new Camera()
position: {
// autocasts as new Point()
x: -0.17746710975334712,
y: 51.44543992422466,
z: 1266.7049653716385
},
heading: 0.34445102566290225,
tilt: 82.95536300536367
}
});
/*********************
* Add graphics layer
*********************/
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
watchUtils.on(graphicsLayer, "graphics", "change", () => {console.log('Graphics added!');});
/*************************
* Add a 3D point graphic
*************************/
// London
const point = {
type: "point", // autocasts as new Point()
x: -0.178,
y: 51.48791,
z: 1010
};
const markerSymbol = {
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
color: [226, 119, 40],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 2
}
};
const pointGraphic = new Graphic({
geometry: point,
symbol: markerSymbol
});
console.log('Add point');
graphicsLayer.add(pointGraphic);
/****************************
* Add a 3D polyline graphic
****************************/
const polyline = {
type: "polyline", // autocasts as new Polyline()
paths: [[-0.178, 51.48791, 0], [-0.178, 51.48791, 1000]]
};
const lineSymbol = {
type: "simple-line", // autocasts as SimpleLineSymbol()
color: [226, 119, 40],
width: 4
};
const polylineGraphic = new Graphic({
geometry: polyline,
symbol: lineSymbol
});
console.log('Add polyline');
graphicsLayer.add(polylineGraphic);
/***************************
* Add a 3D polygon graphic
***************************/
const polygon = {
type: "polygon", // autocasts as new Polygon()
rings: [
[-0.184, 51.48391, 400],
[-0.184, 51.49091, 500],
[-0.172, 51.49091, 500],
[-0.172, 51.48391, 400],
[-0.184, 51.48391, 400]
]
};
const fillSymbol = {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [227, 139, 79, 0.8],
outline: {
// autocasts as new SimpleLineSymbol()
color: [255, 255, 255],
width: 2
}
};
const polygonGraphic = new Graphic({
geometry: polygon,
symbol: fillSymbol
});
console.log('Add polygon');
graphicsLayer.add(polygonGraphic);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Dang. I don't remember what happened when I tried it in my code, which is a spaghetti mess of course. But I just tried it in the SketchWidget sample (clicking to create graphics is more like my use case) and it worked fine.
watchUtils.on(graphicsLayer,"graphics","change",function(){
console.log("Graphics Changed!");
});
At least this confirms for me that I was on the right track with that methodology...now I just have to debug why it failed with my code at the time. Thanks!
Update for anyone struggling similarly to me, I got that method working:
watchUtils.on(graphicsLayer, "graphics", "change", function (evt) {
The reason it wasn't working was that I had graphics being added/created via app.MapView.graphics instead of the graphicsLayer. They are two separate containers! So the watch was working, but not detecting anything because I was adding graphics to the "wrong" place. Making sure each graphic creation took place within graphicsLayer did the trick.
Of course, now I'm struggling to make sure I can detect creation of graphics from several methods. Search result graphics appear to be created in the app.MapView by default...I can override that, but then I need to customize each type. And it appears that featureLayer sources create additional graphics (probably in the app.MapView!) that I can't detect/clear!