Skip to content

Commit

Permalink
PB-1023: select searched feature
Browse files Browse the repository at this point in the history
  • Loading branch information
sommerfe committed Oct 10, 2024
1 parent 5ff9cbe commit e246119
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 32 deletions.
53 changes: 28 additions & 25 deletions src/api/search.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}

Expand All @@ -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`,
Expand All @@ -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`,
Expand All @@ -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,
Expand All @@ -394,7 +396,7 @@ function createSearchResultFromLayer(layer, feature, extent, outputProjection) {
...layerContent,
...locationContent,
resultType: SearchResultTypes.FEATURE,
title: layerName,
title: featureName,
layer,
}
}
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/store/modules/features.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -58,7 +58,7 @@ function getFeatureCountForCoordinate(coordinate) {
* @returns {Promise<LayerFeature[]>} 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,
Expand Down
48 changes: 43 additions & 5 deletions src/store/modules/search.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
/**
Expand Down Expand Up @@ -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,
})
}
Expand All @@ -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 ?? []),
Expand Down

0 comments on commit e246119

Please sign in to comment.