diff --git a/src/api/search.api.js b/src/api/search.api.js index 6acb44670..317322f89 100644 --- a/src/api/search.api.js +++ b/src/api/search.api.js @@ -280,22 +280,22 @@ async function searchLayerFeatures(outputProjection, queryString, layer, lang, c } /** - * Searches for the query string in the layer inside the provided search fields + * Searches for the query string in the feature inside the provided search fields * - * @param layer + * @param feature * @param {String} queryString * @param {String} searchFields * @returns {Boolean} */ -function isQueryInLayer(layer, queryString, searchFields) { +function isQueryInFeature(feature, queryString, searchFields) { const queryStringClean = queryString .trim() .toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') return searchFields.some((field) => { - const value = layer[field]?.toString() - return value && value.trim().toLowerCase().includes(queryStringClean) + const value = feature.values_[field]?.toString() + return !!value && value.trim().toLowerCase().includes(queryStringClean) }) } @@ -305,19 +305,20 @@ function isQueryInLayer(layer, queryString, searchFields) { * @param {CoordinateSystem} outputProjection * @param {String} queryString * @param layer - * @returns {SearchResult} + * @returns {SearchResult[]} */ async function searchKmlLayerFeatures(outputProjection, queryString, layer) { try { - const searchFields = ['name', 'description', 'id', 'kmlFileUrl'] - const isInLayer = isQueryInLayer(layer, queryString, searchFields) - if (!isInLayer) return [] + const searchFields = ['name', 'description', 'id'] const features = parseKml(layer, outputProjection, []) if (!features || !features.length) return [] + const includedFeatures = features.filter((feature) => isQueryInFeature(feature, queryString, searchFields)) + if (!includedFeatures.length) return [] + const extent = getKmlExtent(layer.kmlData) - return createSearchResultFromLayer(layer, features[0], extent, outputProjection) + return includedFeatures.map(feature => createSearchResultFromLayer(layer, feature, extent, outputProjection)) } catch (error) { log.error( `Failed to search layer features for layer ${layer.id}, fallback to empty result`, @@ -333,19 +334,20 @@ async function searchKmlLayerFeatures(outputProjection, queryString, layer) { * @param {CoordinateSystem} outputProjection * @param {String} queryString * @param layer - * @returns {SearchResult} + * @returns {SearchResult[]} */ async function searchGpxLayerFeatures(outputProjection, queryString, layer) { try { - const searchFields = ['name', 'description', 'id', 'baseUrl', 'gpxFileUrl'] - const isInLayer = isQueryInLayer(layer, queryString, searchFields) - if (!isInLayer) return [] + const searchFields = ['name', 'description', 'id'] const features = parseGpx(layer.gpxData, outputProjection, []) if (!features || !features.length) return [] + const includedFeatures = features.filter((feature) => isQueryInFeature(feature, queryString, searchFields)) + if (!includedFeatures.length) return [] + const extent = getGpxExtent(layer.gpxData) - return createSearchResultFromLayer(layer, features[0], extent, outputProjection) + return includedFeatures.map(feature => createSearchResultFromLayer(layer, feature, extent, outputProjection)) } catch (error) { log.error( `Failed to search layer features for layer ${layer.id}, fallback to empty result`, @@ -365,27 +367,27 @@ async function searchGpxLayerFeatures(outputProjection, queryString, layer) { * @returns {SearchResult} */ function createSearchResultFromLayer(layer, feature, extent, outputProjection) { - const layerName = layer.name ?? '' + const featureName = feature.values_.name || layer.name || '' const coordinates = extractOlFeatureCoordinates(feature) const zoom = outputProjection.get1_25000ZoomLevel() const point = points(coordinates) const centerPoint = center(point) - + const featureId = feature.id_ ?? feature.ol_uid const layerContent = { resultType: SearchResultTypes.LAYER, id: layer.id, - title: layerName, - sanitizedTitle: sanitizeTitle(layerName), + title: layer.name ?? '', + sanitizedTitle: sanitizeTitle(layer.name), description: layer.description ?? '', layerId: layer.id, } const locationContent = { resultType: SearchResultTypes.LOCATION, - id: layer.id, - title: layerName, - sanitizedTitle: sanitizeTitle(layerName), - description: layer.description ?? '', - featureId: layer.id ?? layer.description, + id: featureId, + title: featureName, + sanitizedTitle: sanitizeTitle(featureName), + description: feature.values_.description ?? '', + featureId: featureId, coordinate: centerPoint.geometry.coordinates, extent, zoom, @@ -394,7 +396,7 @@ function createSearchResultFromLayer(layer, feature, extent, outputProjection) { ...layerContent, ...locationContent, resultType: SearchResultTypes.FEATURE, - title: layerName, + title: featureName, layer, } } @@ -455,6 +457,7 @@ export default async function search(config) { .map((layer) => searchKmlLayerFeatures(outputProjection, queryString, layer)) ) } + if (layersToSearch.some((layer) => layer.type === LayerTypes.GPX)) { allRequests.push( ...layersToSearch diff --git a/src/store/modules/features.store.js b/src/store/modules/features.store.js index 71ac32103..dac44ebf3 100644 --- a/src/store/modules/features.store.js +++ b/src/store/modules/features.store.js @@ -34,7 +34,7 @@ const getEditableFeatureWithId = (state, featureId) => { ) } -function getFeatureCountForCoordinate(coordinate) { +export function getFeatureCountForCoordinate(coordinate) { return coordinate.length === 2 ? DEFAULT_FEATURE_COUNT_SINGLE_POINT : DEFAULT_FEATURE_COUNT_RECTANGLE_SELECTION @@ -58,7 +58,7 @@ function getFeatureCountForCoordinate(coordinate) { * @returns {Promise} A promise that will contain all feature identified by the * different requests (won't be grouped by layer) */ -const runIdentify = (config) => { +export const runIdentify = (config) => { const { layers, coordinate, diff --git a/src/store/modules/search.store.js b/src/store/modules/search.store.js index 75c473e54..49ff287fa 100644 --- a/src/store/modules/search.store.js +++ b/src/store/modules/search.store.js @@ -10,6 +10,12 @@ import { flattenExtent } from '@/utils/coordinates/coordinateUtils' import CustomCoordinateSystem from '@/utils/coordinates/CustomCoordinateSystem.class' import { parseKml } from '@/utils/kmlUtils' import log from '@/utils/logging' +import { getFeatureCountForCoordinate, runIdentify } from './features.store' +import LayerFeature from '@/api/features/LayerFeature.class' +import GeoJSON from 'ol/format/GeoJSON' +import { normalizeExtent } from '@/utils/coordinates/coordinateUtils' +import LayerTypes from '@/api/layers/LayerTypes.enum' +import { parseGpx } from '@/utils/gpxUtils' const state = { /** @@ -189,12 +195,18 @@ const actions = { }) }) } else { - const features = parseKml(entry.layer, rootState.position.projection, []) - // TODO - // fix set selectedFeatures + // For imported KML and GPX files + let features = [] + if (entry.layer.type === LayerTypes.KML) { + features = parseKml(entry.layer, rootState.position.projection, []) + } + if (entry.layer.type === LayerTypes.GPX) { + features = parseGpx(entry.layer, rootState.position.projection, []) + } + // TODO see if there is a better way of finding the feature + const layerFeatures = features.map((feature) => createLayerFeature(feature, entry.layer)).filter((feature) => feature.data.title === entry.title) dispatch('setSelectedFeatures', { - features, - paginationSize: features.length, + features: layerFeatures, dispatcher, }) } @@ -211,6 +223,32 @@ const actions = { }, } +function createLayerFeature(olFeature, layer) { + return new LayerFeature({ + layer: layer, + id: olFeature.getId(), + name: + olFeature.get('label') ?? + // exception for MeteoSchweiz GeoJSONs, we use the station name instead of the ID + // some of their layers are + // - ch.meteoschweiz.messwerte-niederschlag-10min + // - ch.meteoschweiz.messwerte-lufttemperatur-10min + olFeature.get('station_name') ?? + // GPX track feature don't have an ID but have a name ! + olFeature.get('name') ?? + olFeature.getId(), + data: { + title: olFeature.get('name'), + description: olFeature.get('description'), + }, + coordinates: olFeature.getGeometry().getCoordinates(), + geometry: new GeoJSON().writeGeometryObject( + olFeature.getGeometry() + ), + extent: normalizeExtent(olFeature.getGeometry().getExtent()), + }) +} + const mutations = { setSearchQuery: (state, { query }) => (state.query = query), setSearchResults: (state, { results }) => (state.results = results ?? []),