I'm building a custom drawing component with SketchViewModel. I'm able to update graphics well. Drawing an interactive circle with radius. Whenever I delete the graphics. I always get the below error.
{
"name": "sketch:invalid-parameter",
"message": "Parameter 'graphics' contains one or more graphics missing from the supplied GraphicsLayer."
}
@ReneRubalcava @Anonymous User @ReneRubalcava2 @ReneRab,@AndyGup could you help?
https://developers.arcgis.com/javascript/latest/sample-code/featurelayerview-query-geometry/
The error could be reproducible from the below html file.
A click on the map draws a circle with radius that's interactive.
Delete button (trash icon button on the top right will delete graphics added to the sketchviewmodel).
Check the debug console on Chrome browser for errors.
<html>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,
maximum-scale=1,user-scalable=no"
/>
<title>
FeatureLayerView - query statistics by geometry | Sample | ArcGIS API for
JavaScript 4.24
</title>
<link
rel="stylesheet"
href="https://js.arcgis.com/4.24/esri/themes/light/main.css"
/>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
</style>
<!-- Load the Chart.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<script src="https://js.arcgis.com/4.24/"></script>
<script>
require([
"esri/widgets/Sketch/SketchViewModel",
"esri/geometry/Polyline",
"esri/geometry/Point",
"esri/Graphic",
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/GraphicsLayer",
"esri/geometry/geometryEngine",
"esri/widgets/Expand",
"esri/widgets/Legend",
"esri/widgets/Search",
"esri/core/reactiveUtils",
"esri/core/promiseUtils",
"esri/core/reactiveUtils"
], function(
SketchViewModel,
Polyline,
Point,
Graphic,
Map,
MapView,
FeatureLayer,
GraphicsLayer,
geometryEngine,
Expand,
Legend,
Search,
reactiveUtils,
promiseUtils,
reactiveUtils
) {
// App 'globals'
let sketchViewModel;
let count = 0,
centerGraphic,
edgeGraphic,
polylineGraphic,
bufferGraphic,
centerGeometryAtStart,
labelGraphic;
const unit = "kilometers";
// Create layers
const graphicsLayer = new GraphicsLayer();
const bufferLayer = new GraphicsLayer({
blendMode: "color-burn"
});
// Create map
const map = new Map({
basemap: "dark-gray-vector",
layers: [bufferLayer, graphicsLayer]
});
// Create view
const view = new MapView({
container: "viewDiv",
map: map,
zoom: 11,
center: [-122.083, 37.3069],
constraints: {
maxScale: 0,
minScale: 300000
}
});
view.on("click", function(evt) {
drawBufferPolygon(evt.screenPoint);
});
/*********************************************************************
* Edge or center graphics are being moved. Recalculate the buffer with
* updated geometry information and run the query stats again.
*********************************************************************/
const onMove = promiseUtils.debounce((event) => {
// If the edge graphic is moving, keep the center graphic
// at its initial location. Only move edge graphic
if (
event.toolEventInfo &&
event.toolEventInfo.mover.attributes.edge
) {
const toolType = event.toolEventInfo.type;
if (toolType === "move-start") {
centerGeometryAtStart = centerGraphic.geometry;
}
// keep the center graphic at its initial location when edge point is moving
else if (toolType === "move" || toolType === "move-stop") {
centerGraphic.geometry = centerGeometryAtStart;
}
}
// the center or edge graphic is being moved, recalculate the buffer
const vertices = [
[centerGraphic.geometry.x, centerGraphic.geometry.y],
[edgeGraphic.geometry.x, edgeGraphic.geometry.y]
];
// client-side stats query of features that intersect the buffer
calculateBuffer(vertices);
// user is clicking on the view... call update method with the center and edge graphics
if (event.state === "complete") {
sketchViewModel.update([edgeGraphic, centerGraphic], {
tool: "move"
});
}
});
/*****************************************************************
* Create SketchViewModel and wire up event listeners
*****************************************************************/
sketchViewModel = new SketchViewModel({
view: view,
layer: graphicsLayer
});
// Listen to SketchViewModel's update event so that population pyramid chart
// is updated as the graphics are updated
sketchViewModel.on("update", onMove);
/*********************************************************************
* Edge or center point is being updated. Recalculate the buffer with
* updated geometry information.
*********************************************************************/
function calculateBuffer(vertices) {
// Update the geometry of the polyline based on location of edge and center points
polylineGraphic.geometry = new Polyline({
paths: vertices,
spatialReference: view.spatialReference
});
// Recalculate the polyline length and buffer polygon
const length = geometryEngine.geodesicLength(
polylineGraphic.geometry,
unit
);
const buffer = geometryEngine.geodesicBuffer(
centerGraphic.geometry,
length,
unit
);
// Update the buffer polygon
bufferGraphic.geometry = buffer;
// Update label graphic to show the length of the polyline
labelGraphic.geometry = edgeGraphic.geometry;
labelGraphic.symbol = {
type: "text",
color: "#FFEB00",
text: length.toFixed(2) + " kilometers",
xoffset: 50,
yoffset: 10,
font: {
// autocast as Font
size: 14,
family: "sans-serif"
}
};
}
var element = document.createElement('div');
element.className = "esri-icon-trash esri-widget--button esri-widget esri-interactive";
element.addEventListener('click', function(evt) {
if (sketchViewModel) {
sketchViewModel.complete();
sketchViewModel.delete();
graphicsLayer.removeAll();
bufferLayer.removeAll();
view.graphics.removeAll();
}
})
view.ui.add(element, "top-right");
/***************************************************
* Draw the buffer polygon when application loads or
* when user searches for a new location
**************************************************/
function drawBufferPolygon(screenPoint) {
// When pause() is called on the watch handle, the callback represented by the
// watch is no longer invoked, but is still available for later use
// this watch handle will be resumed when user searches for a new location
// pausableWatchHandle.pause();
paused = false;
// Initial location for the center, edge and polylines on the view
//const viewCenter = mapPoint.clone();
const centerScreenPoint = screenPoint;
const centerPoint = view.toMap({
x: centerScreenPoint.x,
y: centerScreenPoint.y
});
const edgePoint = view.toMap({
x: centerScreenPoint.x + 24,
y: centerScreenPoint.y - 12
});
// Store updated vertices
const vertices = [
[centerPoint.x, centerPoint.y],
[edgePoint.x, edgePoint.y]
];
// Create center, edge, polyline and buffer graphics for the first time
if (!centerGraphic) {
const polyline = new Polyline({
paths: vertices,
spatialReference: view.spatialReference
});
// get the length of the initial polyline and create buffer
const length = geometryEngine.geodesicLength(polyline, unit);
const buffer = geometryEngine.geodesicBuffer(
centerPoint,
length,
unit
);
// Create the graphics representing the line and buffer
const pointSymbol = {
type: "simple-marker",
style: "circle",
size: 10,
color: [0, 255, 255, 0.5]
};
centerGraphic = new Graphic({
geometry: centerPoint,
symbol: pointSymbol,
attributes: {
center: "center"
}
});
edgeGraphic = new Graphic({
geometry: edgePoint,
symbol: pointSymbol,
attributes: {
edge: "edge"
}
});
polylineGraphic = new Graphic({
geometry: polyline,
symbol: {
type: "simple-line",
color: [254, 254, 254, 1],
width: 2.5
}
});
bufferGraphic = new Graphic({
geometry: buffer,
symbol: {
type: "simple-fill",
color: [150, 150, 150],
outline: {
color: "#FFEB00",
width: 2
}
}
});
labelGraphic = labelLength(edgePoint, length);
// Add graphics to layer used with sketchVM
graphicsLayer.addMany([
centerGraphic,
edgeGraphic,
polylineGraphic
]);
// Add label to view graphics
view.graphics.add(labelGraphic);
// once center and edge point graphics are added to the layer,
// call sketch's update method pass in the graphics so that users
// can just drag these graphics to adjust the buffer
sketchViewModel.update([edgeGraphic, centerGraphic], {
tool: "move"
});
bufferLayer.addMany([bufferGraphic]);
}
// Move the center and edge graphics to the new location returned from search
else {
centerGraphic.geometry = centerPoint;
edgeGraphic.geometry = edgePoint;
}
// Query features that intersect the buffer
calculateBuffer(vertices);
}
// Label polyline with its length
function labelLength(geom, length) {
return new Graphic({
geometry: geom,
symbol: {
type: "text",
color: "#FFEB00",
text: length.toFixed(2) + " kilometers",
xoffset: 50,
yoffset: 10,
font: {
// autocast as Font
size: 14,
family: "sans-serif"
}
}
});
}
});
</script>
</head>
<body>
<div id="viewDiv">
</div>
</body>
</html>