From 10f4987a8a1a4e726775e1959ed929e62c39526a Mon Sep 17 00:00:00 2001 From: Stefan Forsgren Date: Thu, 23 Nov 2023 08:45:31 +0100 Subject: [PATCH 1/2] Fixed sharemap popup not displayed --- src/featureinfo.js | 6 +++--- src/maputils.js | 4 ++++ src/viewer.js | 23 +++++++++++------------ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/featureinfo.js b/src/featureinfo.js index e1bd88a7f..ad2e72e36 100644 --- a/src/featureinfo.js +++ b/src/featureinfo.js @@ -601,8 +601,8 @@ const Featureinfo = function Featureinfo(options = {}) { }; /** - * Shows the featureinfo popup/sidebar/infowindow for the provided feature and fit the view to it. - * @param {any} featureObj An object containing layerName and feature + * Shows the featureinfo popup/sidebar/infowindow for the provided features and fit the view to it. + * @param {any} featureObj An object containing layerName and feature. "feature" is either one Feature or an Array of Feature * @param {any} opts An object containing options. Supported options are : coordinate, the coordinate where popup will be shown. If omitted first feature is used. * ignorePan, do not autopan if type is overlay. Pan should be supressed if view is changed manually to avoid contradicting animations. * @returns nothing @@ -624,7 +624,7 @@ const Featureinfo = function Featureinfo(options = {}) { } if (newItems.length > 0) { render(newItems, identifyTarget, opts.coordinate || maputils.getCenter(newItems[0].getFeature().getGeometry()), opts); - viewer.getMap().getView().fit(maputils.getExtent(featureObj.feature)); + viewer.getMap().getView().fit(maputils.getExtent(newItems.map(i => i.getFeature()))); } }; diff --git a/src/maputils.js b/src/maputils.js index cbaf69115..e7f9ecf7a 100644 --- a/src/maputils.js +++ b/src/maputils.js @@ -111,6 +111,10 @@ const maputils = { } return center; }, + /** + * Gets the union extent for an array of features + * @param {any} featureArray An array of features + */ getExtent: function getCenter(featureArray) { const featureExtent = featureArray[0].getGeometry().getExtent(); let i; diff --git a/src/viewer.js b/src/viewer.js index efbd0ed76..d728c139f 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -577,9 +577,7 @@ const Viewer = function Viewer(targetOption, options = {}) { const layer = getLayer(layerName); if (layer && layer.get('type') !== 'GROUP') { const layerType = layer.get('type'); - // FIXME: postrender event is only emitted if any features from a layer is actually drawn, which means there is no feature in the default extent, - // it will not be triggered until map is panned or zoomed where a feature exists. - layer.once('postrender', () => { + layer.getSource().once('featuresloadend', () => { const clusterSource = layer.getSource().source; // Assume that id is just the second part of the argumment and adjust it for special cases later. let id = featureId.split('.')[1]; @@ -610,15 +608,16 @@ const Viewer = function Viewer(targetOption, options = {}) { } if (feature) { - const obj = {}; - obj.feature = feature; - obj.layerName = layerName; - featureinfo.showFeatureInfo(obj); - map.getView().fit(feature.getGeometry(), { - maxZoom: getResolutions().length - 2, - padding: [15, 15, 40, 15], - duration: 1000 - }); + const fidsbylayer = {}; + fidsbylayer[layerName] = [feature.getId()]; + featureinfo.showInfo(fidsbylayer, { ignorePan: true }); + if (!urlParams.zoom && !urlParams.center) { + map.getView().fit(feature.getGeometry(), { + maxZoom: getResolutions().length - 2, + padding: [15, 15, 40, 15], + duration: 1000 + }); + } } }); } From 87a3c7104b9dab4cbd71b1e38793f34e0721e7bc Mon Sep 17 00:00:00 2001 From: Stefan Forsgren Date: Thu, 23 Nov 2023 15:07:55 +0100 Subject: [PATCH 2/2] Fix for more layer kinds in urlParams.feature --- src/layer/agsfeature.js | 3 +- src/layer/geojson.js | 3 +- src/viewer.js | 96 +++++++++++++++++++++++------------------ 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/layer/agsfeature.js b/src/layer/agsfeature.js index c0bb5529e..d9f775e80 100644 --- a/src/layer/agsfeature.js +++ b/src/layer/agsfeature.js @@ -18,7 +18,7 @@ function createSource({ const esrijsonFormat = new EsriJSON(); const vectorSource = new VectorSource({ attributions: attribution, - loader(extent, resolution, projection) { + loader(extent, resolution, projection, success) { const that = this; let url = sourceUrl.endsWith('/') ? sourceUrl : `${sourceUrl}/`; url += id @@ -40,6 +40,7 @@ function createSource({ if (features.length > 0) { that.addFeatures(features); } + success(features); }).catch(error => console.warn(error)); }, strategy: loadingstrategy.bbox diff --git a/src/layer/geojson.js b/src/layer/geojson.js index 6724dbdb1..69148fada 100644 --- a/src/layer/geojson.js +++ b/src/layer/geojson.js @@ -13,7 +13,7 @@ function createSource(options) { if (options.url) { const vectorSource = new VectorSource({ attributions: options.attribution, - loader() { + loader(extent, resolution, projection, success) { fetch(options.url, { headers: options.headers }).then(response => response.json()).then((data) => { if (data.features) { vectorSource.addFeatures(vectorSource.getFormat().readFeatures(data, formatOptions)); @@ -34,6 +34,7 @@ function createSource(options) { }); } } + success(vectorSource.getFeatures()); }).catch(error => console.warn(error)); }, format: new GeoJSON() diff --git a/src/viewer.js b/src/viewer.js index d728c139f..49b331477 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -527,6 +527,26 @@ const Viewer = function Viewer(targetOption, options = {}) { return urlParams; }; + /** + * Internal helper used when urlParams.feature is set and the popup should be displayed. + * @param {any} feature + * @param {any} layerName + */ + const displayFeatureInfo = function displayFeatureInfo(feature, layerName) { + if (feature) { + const fidsbylayer = {}; + fidsbylayer[layerName] = [feature.getId()]; + featureinfo.showInfo(fidsbylayer, { ignorePan: true }); + if (!urlParams.zoom && !urlParams.center) { + map.getView().fit(feature.getGeometry(), { + maxZoom: getResolutions().length - 2, + padding: [15, 15, 40, 15], + duration: 1000 + }); + } + } + }; + return Component({ onInit() { this.render(); @@ -577,49 +597,43 @@ const Viewer = function Viewer(targetOption, options = {}) { const layer = getLayer(layerName); if (layer && layer.get('type') !== 'GROUP') { const layerType = layer.get('type'); - layer.getSource().once('featuresloadend', () => { - const clusterSource = layer.getSource().source; - // Assume that id is just the second part of the argumment and adjust it for special cases later. - let id = featureId.split('.')[1]; - let feature; - - if (layerType === 'WFS') { - // WFS uses the layername as a part of the featureId. Problem is that it what the server think is the name that matters. - // First we assume that the layername is actually correct, then take the special cases - let idLayerPart = layerName; - const layerId = layer.get('id'); - if (layerId) { - // if layer explicitly has set the id it takes precedense over name - // layer name already have popped the namespace part, but id is untouched. - idLayerPart = layerId.split(':').pop(); - } else if (layerName.includes('__')) { - // If using the __-notation to use same layer several times, we must only use the actual layer name - idLayerPart = layerName.split('__')[0]; - } - // Build the correct WFS id - id = `${idLayerPart}.${id}`; - } - // FIXME: ensure that feature is loaded. If using bbox and feature is outside default extent it will not be found. - // Workaround is to have a default extent covering the entire map with the layer in visible range or use strategy all - if (clusterSource) { - feature = clusterSource.getFeatureById(id); - } else { - feature = layer.getSource().getFeatureById(id); + const layerSource = layer.getSource().source ? layer.getSource().source : layer.getSource(); + // Assume that id is just the second part of the argumment and adjust it for special cases later. + let id = featureId.split('.')[1]; + + if (layerType === 'WFS') { + // WFS uses the layername as a part of the featureId. Problem is that it what the server think is the name that matters. + // First we assume that the layername is actually correct, then take the special cases + let idLayerPart = layerName; + const layerId = layer.get('id'); + if (layerId) { + // if layer explicitly has set the id it takes precedense over name + // layer name already have popped the namespace part, but id is untouched. + idLayerPart = layerId.split(':').pop(); + } else if (layerName.includes('__')) { + // If using the __-notation to use same layer several times, we must only use the actual layer name + idLayerPart = layerName.split('__')[0]; } + // Build the correct WFS id + id = `${idLayerPart}.${id}`; + } - if (feature) { - const fidsbylayer = {}; - fidsbylayer[layerName] = [feature.getId()]; - featureinfo.showInfo(fidsbylayer, { ignorePan: true }); - if (!urlParams.zoom && !urlParams.center) { - map.getView().fit(feature.getGeometry(), { - maxZoom: getResolutions().length - 2, - padding: [15, 15, 40, 15], - duration: 1000 - }); - } - } - }); + // Some layer types may already have been loaded, e.g. GeoJson with static configured features. As features are loaded + // on creation it is impossible to listen to the featuresloadend event, but on the other hand the features will be ready already + // when we get here. It is highly unlikely that a remote source is finished already, but that would work as well. + if (layerSource.getFeatures().length > 0) { + displayFeatureInfo(layerSource.getFeatureById(id), layerName); + } else { + // Set up an eventhandler and wait for the source to finsish loading if there are no features yet. + // Important that the source actually emits this event. + layerSource.once('featuresloadend', () => { + // FIXME: ensure that feature is loaded. If using bbox and feature is outside default extent it will not be found. + // Workaround is to have a default extent covering the entire map with the layer in visible range or use strategy all + // Most likely it will work as sharemap links contains center and zoom so extent will be visible. Most sane people + // will only share maps where the selected feature is in view + displayFeatureInfo(layerSource.getFeatureById(id), layerName); + }); + } } }