Hello,
Hoping someone has some advice for how to approach this problem. Let me start with the desired design:
I've tried several approaches for this. I initially started prototyping the React component using loadModules but this wasn't very easy to manage when I needed to expose the ESRI modules in several useEffect hooks.
What I'm having trouble with is that the points do not get displayed on the map. It's as if the view does not know it needs to update.
I then tried moving the MapView to a state variable with useState but it was difficult to then manage adding Points to the GraphicsLayer because the spread operator would need to be used to deep clone the modified object back into the state variable, since view.graphics.add(newPoint) would not update the view state. I tried using the spread operator (...) but even this did not trigger the map to re-render with the point visible.
I've also tried view.goTo(newPoint) to force a re-render but this causes the entire map area to go blank.
Are there any React examples out there of a marker being dynamically updated on the map?
Approach 1:
import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
import Sketch from "@arcgis/core/widgets/Sketch";
import GraphicsLayer from "@arcgis/core/layers/GraphicsLayer";
import Graphic from "@arcgis/core/Graphic";
import Point from "@arcgis/core/geometry/Point";
import * as webMercatorUtils from "@arcgis/core/geometry/support/webMercatorUtils";
const WebMapView = ({ setWxState, mapState }) => {
const mapRef = useRef();
const [view, setView] = useState();
const simpleMarkerSymbol = {
type: "simple-marker",
color: [226, 119, 40], // Orange
outline: {
color: [255, 255, 255], // White
width: 1,
},
};
useEffect(() => {
if (mapState?.payload) {
const newLayer = new GraphicsLayer();
const point = new Point({
//Create a point
longitude: mapState?.payload?.lon,
latitude: mapState?.payload?.lat,
});
const newPoint = new Graphic({
geometry: point,
symbol: simpleMarkerSymbol,
});
newLayer.add(newPoint);
// Method 1
// map.add(newLayer);
// Method 2
view.graphics.add(newPoint);
setView({
...view,
graphics: {
...view.graphics,
items: [...view.graphics.items],
},
});
}
}, [mapState]);
useEffect(() => {
const map = new Map({
basemap: "topo-vector",
ground: "world-elevation",
});
const handleDraw = async (event) => {
if (event.state === "complete" && event.tool === "polyline") {
const convertedGeo = webMercatorUtils.webMercatorToGeographic(
event.graphic.geometry
);
const points = convertedGeo.paths[0];
// Business logic
}
};
// load the map view at the ref's DOM node
const newView = new MapView({
container: mapRef.current,
map: map,
center: [-118, 34],
zoom: 8,
});
const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer);
newView.when(() => {
// Create a new sketch widget
const sketch = new Sketch({
view: newView,
layer: graphicsLayer,
polylineSymbol: {
type: "simple-line", // autocasts as new SimpleLineSymbol()
color: [4, 90, 141],
width: 2,
// creationMode: "update"
},
});
// Add the sketch widget to the view
newView.ui.add(sketch, "top-right");
sketch.on("create", handleDraw);
sketch.on("update", handleDraw);
});
setView(newView);
return () => {
if (view) {
// destroy the map view
view.destroy();
}
};
}, []);
return <div style={{ position: "relative", height: "60%" }} ref={mapRef} />;
};
currently working on something similar do you have a solution for this ? i would appreciate it if you could share it.