I'm using OpenLayers display a map which can include vector layers with dynamic features (ie, the lines/points change frequently). These vector layers use GeoJSON in a vector source and use javascript promises to query/return the new GeoJSON features.
This was all working fine in OpenLayers v3.x but stopped working after upgrading to v6.5. If I swap v3 back in, then it all works correctly again, so I am 100% confident that the problem is related to some difference between v3 and v6. I can't see anything in the documentation that has changed enough to break this, but I'm sure I must have missed something.
With v6, these vector layers simply never appear on the map at all, and no errors are logged.
Below is the code that works fine in v3 but no longer works in v6 of OpenLayers.
Calling the redrawLayer()
function is what triggers the vector layer to refresh its source.
Any ideas on what I'm doing wrong here, or what has changed between v3 and v6 that causes this to no longer work?
UPDATE ONE - Another notable oddity: When one of these vector layers is present in the map in v6, even the basemap raster tile layer (eg, OSM) misbehaves. Some (random?) tiles don't load! When none of these vector layers are present, all the raster tiles load fine. So is there something larger at play here that I've missed that could be beyond simply the vector layer/source? Anybody seen behaviour like this before?
UPDATE TWO - Fixed in JS Fiddle but not in app: The "ADDED FEATURES FROM PROMISED JSON:..."
message in the Vector Source loader
function is now being logged correctly, after uncommenting the redraw function's refresh
line and commenting out the other two lines (as per comments below). See actual JSON content in an example full log message below.
However, the layer still never appears on the map. (The JS Fiddle at jsfiddle.net/nsands/sxfh2k09/20 DOES work, so I'm still trying to figure out the relevant differences.)
UPDATE THREE - added previously excluded relevant code after resolving the app issue:
As is often the case, it turns out that the cause of the problem was not where I thought it was, so the actual problem code was not included in the original version of this post. I've updated the code now, to include all relevant portions (now that I've solved it and know what the relevant parts actually are).
I'll also post my solution as an answer, in case it helps anybody else upgrading from OLv3 to OLv6.
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
],
target: 'map',
view: new ol.View({
center: [-13583700, 4486300],
zoom: 17,
}),
});
var vectorLayers = {};
var dpi = 72;
function mapScale() {
var unit = map.getView().getProjection().getUnits();
var resolution = map.getView().getResolution();
var inchesPerMetre = 39.37;
return resolution * ol.proj.METERS_PER_UNIT[unit] * inchesPerMetre * dpi;
}
var layerStyles = function (feature, resolution) {
if ( mapScale() < 1000000 ) {
return [
new ol.style.Style({stroke: new ol.style.Stroke({color: '#000000', width: 6.000000})}),
new ol.style.Style({stroke: new ol.style.Stroke({color: '#FFFF00', width: 2.000000})}),
new ol.style.Style({text: new ol.style.Text({text: feature.get('label')['1000000'], font: ' 20pt sans-serif', fill: new ol.style.Fill({color: '#FFFF00'}), stroke: new ol.style.Stroke({color: '#000000', width: 4.0}), offsetX: 14, textAlign: 'start', textBaseline: 'alphabetic'})})
]
}
};
var json0 = '{"type":"FeatureCollection","features":[]}'
var json1 = '{"type":"FeatureCollection","features":[{"geometry":{"type":"LineString","coordinates":[[-122.02320166,37.337513659999999,0],[-122.02327787,37.337692109999999,0]]},"type":"Feature","properties":{"label":{"1000000":""}}}]}'
var json2 = '{"type":"FeatureCollection","features":[{"geometry":{"type":"LineString","coordinates":[[-122.02320166,37.337513659999999,0],[-122.02327787,37.337692109999999,0],[-122.02363136,37.33769392,0],[-122.02421372000001,37.337723150000002,0]]},"type":"Feature","properties":{"label":{"1000000":""}}}]}'
var json3 = '{"type":"FeatureCollection","features":[{"geometry":{"type":"LineString","coordinates":[[-122.02320166,37.337513659999999,0],[-122.02327787,37.337692109999999,0],[-122.02363136,37.33769392,0],[-122.02421372000001,37.337723150000002,0],[-122.02439493,37.337724039999998,0]]},"type":"Feature","properties":{"label":{"1000000":""}}}]}'
var testJSON = json0
function addVectorLayer(layerIndex, layerProj, styles) {
// var geoJSONFormat = new ol.format.GeoJSON({defaultDataProjection: layerProj});
var geoJSONFormat = new ol.format.GeoJSON({dataProjection: layerProj});
var newLayer = new ol.layer.Vector({
style: styles,
source: new ol.source.Vector({
strategy: ol.loadingstrategy.bbox,
loader: function(extent, resolution, proj) {
var convertedExtent = ol.proj.transformExtent(extent, proj, layerProj);
var vectorSource = this
// var promise = jsonPromise(layerIndex, convertedExtent)
// promise.then(function(jsonString, errorString) {
// if ( jsonString ) {
jsonString = testJSON;
var features = [];
try {
features = geoJSONFormat.readFeatures(jsonString, {
featureProjection: proj,
});
if ( features.length ) {
vectorSource.addFeatures(features);
console.log("ADDED FEATURES FROM PROMISED JSON: " + jsonString)
}
} catch (err) {
console.log("Failed to add features from JSON:");
console.log(jsonString);
console.log(err);
}
// } else if ( errorString ) {
// console.log(errorString)
// }
// }, function(err) {
// console.log(err)
// });
},
}),
});
vectorLayers[layerIndex] = newLayer; // NB: Integer is automatically converted to string here for dictionary indexing
map.addLayer(newLayer);
return newLayer;
}
function redrawLayer(layer) {
console.log("REDRAWING LAYER");
layer.getSource().clear(true);
layer.getSource().changed();
// layer.getSource().refresh();
}
var vectorLayer = addVectorLayer('0', 'EPSG:4326', layerStyles);
ADDED FEATURES FROM PROMISED JSON: {"type":"FeatureCollection","features":[{"geometry":{"type":"LineString","coordinates":[[-122.03478142,37.332149149999999,0],[-122.03479307000001,37.331697120000001,0],[-122.0347866,37.3312174,0],[-122.03473296,37.331086509999999,0]]},"properties":{"label":{"1000000":""}},"type":"Feature"}]}
setTimeout
function with small delay to make it work correctly.layer.getSource().clear(true);
andlayer.getSource().changed();
and uncomment linelayer.getSource().refresh()
, it seems to work OK.