-
Notifications
You must be signed in to change notification settings - Fork 799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix FeatureLayer.refresh for moved point layers #1304
Conversation
Dear @patrickarlt and @jwasilgeo Thank you very much for this fix! I was testing it and these are my findings after apply the fix:
and then the icon is applied based on an attribute value:
The attribute is updated after this fix, but the symbol only changes if I refresh the browser. Sometimes I also see that the symbology changes randomly after some Can you check it in your test case? Thank you very much! Best regards, |
I can reproduce the invalid symbology after an update and refresh. Below is a slightly modified debug case (starting from the debug code at the top here) that switches between 2 different attributes and symbols during the update operation. debug code <!-- https://esri.github.io/esri-leaflet/examples/simple-editing.html -->
<!-- Forked from https://codepen.io/jwasilgeo/pen/KKXVjvy?editors=1000 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Editing feature layers</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<!-- Load Leaflet from CDN -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Load Esri Leaflet from source-->
<script src="../dist/esri-leaflet-debug.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 150px;
bottom: 0;
right: 0;
left: 0;
}
</style>
</head>
<body>
<!-- Leaflet Draw -->
<style>
#info-pane {
z-index: 400;
padding: 1em;
background: white;
text-align: right;
}
#form {
display: none;
}
</style>
<div id="map"></div>
<div id="info-pane" class="leaflet-bar" style="font-size: 10px">
These do not use the Leaflet or Esri Leaflet add/edit funcitonality. They call the REST endpoints using FETCH
directly:<br />
<button id="addFeatureButton">ADD a feature within the current extent</button><br />
<button id="moveFeatureButton">MOVE one of the features within the current extent</button>
<br /><br />
This DOES call the leaflet layer.refresh() function:<br />
<button id="refreshLayerButton">Refresh the layer</button>
</div>
<script>
var testIcons = {
'decision point': L.icon({
iconUrl: 'https://esri.github.io/esri-leaflet/img/red-triangle.png',
iconSize: [20, 20],
iconAnchor: [6, 6],
popupAnchor: [-3, -5],
}),
'air control point': L.icon({
iconUrl: 'https://esri.github.io/esri-leaflet/img/orange-triangle.png',
iconSize: [20, 20],
iconAnchor: [6, 6],
popupAnchor: [-3, -5],
}),
'unmanned aerial system (uas ua)': L.icon({
iconUrl: 'https://esri.github.io/esri-leaflet/img/yellow-triangle.png',
iconSize: [20, 20],
iconAnchor: [6, 6],
popupAnchor: [-3, -5],
}),
};
// create the map
var map = L.map('map').setView([38.631, -90.199], 8);
// basemap
var OpenStreetMap_Mapnik = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
OpenStreetMap_Mapnik.addTo(map);
// add our feature layer to the map
const militaryOps = L.esri.featureLayer({
url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Military/FeatureServer/3',
pointToLayer: function (geojson, latlng) {
return L.marker(latlng, {
icon: testIcons[geojson.properties.symbolname.toLowerCase()]
});
}
}).addTo(map);
const addFeatureButton = document.querySelector("#addFeatureButton");
const moveFeatureButton = document.querySelector("#moveFeatureButton");
const refreshLayerButton = document.querySelector("#refreshLayerButton");
addFeatureButton.addEventListener("click", () => {
const latlng = getRandomPointWithinCurrentExtent(map);
const feat = L.marker(latlng).toGeoJSON();
// set the attribute value that controls the feature service symbology
feat.properties.symbolname = "Decision Point";
fetch(`${militaryOps.options.url}/addFeatures`, {
"headers": {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"body": `features=${JSON.stringify([L.esri.Util.geojsonToArcGIS(feat)])}&f=json`,
"method": "POST",
"mode": "cors"
})
.then(res => res.json())
.then(res => {
console.log(res);
// militaryOps.refresh();
});
});
moveFeatureButton.addEventListener("click", () => {
console.log('move', map.getPanes()[militaryOps.options.pane]);
const latlng = getRandomPointWithinCurrentExtent(map);
console.log("latlng", latlng);
let feat = {};
militaryOps.eachActiveFeature((feature) => {
feat.attributes = {};
feat.attributes.OBJECTID = feature.feature.id;
feat.attributes.symbolname = feature.feature.properties.symbolname === "decision point" ? "air control point" : "decision point"
feat.geometry = { "spatialReference": { "wkid": 4326 } };
feat.geometry.x = latlng.lng;
feat.geometry.y = latlng.lat;
});
console.log('sending:', feat);
// const latlng = getRandomPointWithinCurrentExtent(map);
// const feat = L.marker(latlng).toGeoJSON();
// // set the attribute value that controls the feature service symbology
// feat.properties.symbolname = "Decision Point";
fetch(`${militaryOps.options.url}/updateFeatures`, {
"headers": {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"body": `features=${JSON.stringify([feat])}&f=json`,
"method": "POST",
"mode": "cors"
})
.then(res => res.json())
.then(res => {
console.log(res);
// militaryOps.refresh();
});
});
refreshLayerButton.addEventListener("click", () => {
militaryOps.refresh();
});
function randomIntFromInterval(min, max) { // min and max included
return Math.random() * (max - min) + min;
}
const getRandomPointWithinCurrentExtent = (map) => {
const bounds = map.getBounds();
var lng = randomIntFromInterval(bounds.getEast(), bounds.getWest()).toFixed(5);
var lat = randomIntFromInterval(bounds.getSouth(), bounds.getNorth()).toFixed(5);
return L.latLng(lat, lng);
}
// when a marker is clicked, remove the feature from the service, using its id
militaryOps.on('click', function (e) {
// militaryOps.deleteFeature(e.layer.feature.id, function(err, response) {
// if (err) {
// return;
// }
// console.log(response);
// });
fetch(`${militaryOps.options.url}/deleteFeatures`, {
"headers": {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"body": `objectIds=${e.layer.feature.id}&f=json`,
"method": "POST",
"mode": "cors"
})
.then(res => res.json())
.then(res => {
console.log(res);
militaryOps.refresh();
});
// make sure map click event isn't fired.
L.DomEvent.stopPropagation(e);
});
</script>
</body>
</html> |
@patrickarlt, your thoughts on commit ef8579b, if that's the right spot--timing wise--to add a call to |
@jwasilgeo It seems to work also in my debug case! Thank you very much! |
@PedroVenancio I'm glad to hear it is working for you in your case. For your situation I recommend that your options are either:
|
Hi @jwasilgeo I've implemented your first proposal for now. If I see it causes some impact, I will change for the second proposal, but I hope you can check the impact and merge this (or a polished) PR in the meanwhile. Thank you very much! |
@PedroVenancio @jwasilgeo @gavinr I think we should merge this as is with ef8579b. There might be some performance hit because we will be updating features all the time but I think that is actually the proper behavior. |
@patrickarlt @jwasilgeo @gavinr Thank you very much for the fix. I must say that I've implemented 836caa2 and ef8579b in my applications and I'm not seeing any performance hit. Maybe the impact can be greater when editing features, but I also think this is the proper behaviour. Thanks again for your help! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
* fix layer.refresh for moved point layers * added call to `redraw` to update symbol/style after geometries are updated * also redraw features * revert Co-authored-by: jwasilgeo <[email protected]>
* fix layer.refresh for moved point layers * added call to `redraw` to update symbol/style after geometries are updated * also redraw features * revert Co-authored-by: jwasilgeo <[email protected]>
This fixes
FeatureLayer.refresh()
for layers wheresimplifyFactor
is not set. Originally this was intended to update the geometry when a higher resolution geometry came in from the service but it also means that layers with edited geometries were missed byFeatureLayer.refresh()
Can be reproudced with the following HTML in the
debug
folder (originally from @gavinr):