Skip to content

Instantly share code, notes, and snippets.

@pramsey
Last active September 13, 2022 23:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pramsey/7f93a43db1c9a091f48722c34f028786 to your computer and use it in GitHub Desktop.
Save pramsey/7f93a43db1c9a091f48722c34f028786 to your computer and use it in GitHub Desktop.
// Try as I might, I cannot get the location of the dots to update.
// The first time a payload is received, I get a point, and thereafter,
// the original point will not move (if I send in the same id) nor will a
// a second point be added (if I send in new ids).
// I just want to manipulate the data, and see the map view of the data
// change.
var objectServer = "ws://localhost:7700/objects";
var objectSource = new ol.source.Vector({
wrapX: false
});
var objectLayer = new ol.layer.Vector({
source: objectSource,
style: new ol.style.Style({
image: new ol.style.RegularShape({
fill: new ol.style.Fill({
color: 'red'
}),
stroke: new ol.style.Stroke({
width: 1,
color: 'grey'
}),
points: 16,
radius: 4,
angle: Math.PI / 4
})
})
});
var baseLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: "https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png"
})
});
var map = new ol.Map({
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
}),
layers: [baseLayer, objectLayer]
});
var outputField = document.getElementById("wsPayload");
var outputStatus = document.getElementById("wsStatus")
var ws = new WebSocket(objectServer);
ws.onopen = function () {
outputStatus.innerHTML = "Connected\n";
};
ws.onmessage = function (e) {
try {
var payload = JSON.parse(e.data);
outputField.innerHTML = JSON.stringify(payload, null, 2) + "\n";
}
catch (e) {
outputField.innerHTML = "[ERROR: Unable to parse JSON payload]\n";
outputField.innerHTML += e.data;
return;
}
if ("object_id" in payload && "events" in payload && "location" in payload) {
var oid = payload["object_id"];
var lng = payload["location"]["longitude"];
var lat = payload["location"]["latitude"];
var coord = ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857');
// var coord = [lng, lat];
var objectFeature = new ol.Feature({
geometry: new ol.geom.Point(coord),
timeStamp: payload["location"]["ts"],
props: payload["props"]
});
objectFeature.setId(oid);
console.log(objectFeature);
if(objectSource.hasFeature(objectFeature)) {
objectSource.removeFeature(objectFeature);
console.log("removeFeature");
}
objectSource.addFeature(objectFeature);
console.log("addFeature");
objectSource.changed();
objectLayer.changed();
map.render();
console.log(objectSource);
console.log(coord);
// update the map!
}
else {
outputField.innerHTML = outputField.innerHTML + "\n[ERROR: Payload is not moving object]\n";
}
@tschaub
Copy link

tschaub commented Sep 13, 2022

Only guessing, but I don't think objectSource.removeFeature(objectFeature) will do what you think it will do (objectFeature can not be one of the features in the source's collection because you just created it).

Maybe instead you want something like this:

const oldFeature = objectSource.getFeatureById(oid);
if (oldFeature) {
  objectSource.removeFeature(oldFeature);
}

objectSource.addFeature(objectFeature);

Then you might also decide that instead of adding always creating and adding a new feature and sometimes removing an old feature, you want to either update an existing feature or add a new one. So maybe something like this:

const geometry = new ol.geom.Point(coord);
const properties = {
  timeStamp: payload.location.ts,
  props: payload.props,
};

const oldFeature = objectSource.getFeatureById(oid);
if (oldFeature) {
  oldFeature.setGeometry(geometry);
  oldFeature.setProperties(properties);
} else {
  const feature = new ol.Feature({
    ...properties,
    geometry,
  });
  feature.setId(oid);
  objectSource.addFeature(feature);
}

@rowanwins
Copy link

This is completely untested given it's a little tricky to setup a socket service, but I'm guessing that rather than creating a new object feature every time perhaps you need to do something like

if ("object_id" in payload && "events" in payload && "location" in payload) {
    var oid = payload["object_id"];
    var lng = payload["location"]["longitude"];
    var lat = payload["location"]["latitude"];
    var coord = ol.proj.transform([lng, lat], 'EPSG:4326', 'EPSG:3857');

   // See if there is already a matching feature
   const alreadyCreatedFeature = objectSource.getFeatureById(oid)
   if (alreadyCreatedFeature !== null) {
        alreadyCreatedFeature.setGeometry(new ol.geom.Point(coord))
  } else {
     // do the rest of your creation routine for when you first receive a point
  }

@pramsey
Copy link
Author

pramsey commented Sep 13, 2022

objectFeature can not be one of the features in the source's collection because you just created it

This is the missing piece... I was assuming (making an ass of me) that identity was controlled by the "id", so that removeFeature would work. Strange thing though... hasFeature() did return true... because it is using the "id" property?
I think you're right, doing the update would be nicer.

@tschaub
Copy link

tschaub commented Sep 13, 2022

Strange thing though... hasFeature() did return true... because it is using the "id" property?

Yeah, that had me scratching my head for a while too. See https://github.com/openlayers/openlayers/blob/v7.1.0/src/ol/source/Vector.js#L926-L939

For consistency, source.removeFeature() could behave the same way. Seems like a bug to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment