|
1 | 1 | <script lang="ts">
|
2 | 2 | import { l } from '@nativescript-community/l';
|
3 |
| - import type { MapBounds, MapPos } from '@nativescript-community/ui-carto/core'; |
| 3 | + import { GenericMapPos, MapBounds, MapPos } from '@nativescript-community/ui-carto/core'; |
| 4 | + import { LineGeometry } from '@nativescript-community/ui-carto/geometry'; |
4 | 5 | import { SearchRequest, VectorTileSearchServiceOptions } from '@nativescript-community/ui-carto/search';
|
5 |
| - import { showSnack } from '~/utils/ui'; |
| 6 | + import { CollectionView } from '@nativescript-community/ui-collectionview'; |
6 | 7 | import { ApplicationSettings, ObservableArray, Screen } from '@nativescript/core';
|
7 |
| - import deburr from 'deburr'; |
8 |
| - import type { Point } from 'geojson'; |
9 | 8 | import { createEventDispatcher } from '@shared/utils/svelte/ui';
|
| 9 | + import deburr from 'deburr'; |
| 10 | + import type { Point as GeoJSONPoint } from 'geojson'; |
10 | 11 | import { Template } from 'svelte-native/components';
|
| 12 | + import { NativeViewElementNode } from 'svelte-native/dom'; |
| 13 | + import { GeoLocation } from '~/handlers/GeoHandler'; |
11 | 14 | import { formatDistance, osmicon } from '~/helpers/formatter';
|
12 |
| - import { getBoundsOfDistance, getMetersPerPixel } from '~/helpers/geolib'; |
| 15 | + import { getBoundsOfDistance, getDistance, getDistanceSimple, getMetersPerPixel } from '~/helpers/geolib'; |
13 | 16 | import { lc } from '~/helpers/locale';
|
| 17 | + import { onThemeChanged } from '~/helpers/theme'; |
14 | 18 | import { formatter } from '~/mapModules/ItemFormatter';
|
15 | 19 | import { getMapContext } from '~/mapModules/MapModule';
|
16 | 20 | import type { IItem as Item } from '~/models/Item';
|
|
19 | 23 | import type { GeoResult } from '~/services/PackageService';
|
20 | 24 | import { packageService } from '~/services/PackageService';
|
21 | 25 | import { computeDistanceBetween } from '~/utils/geo';
|
| 26 | + import { showSnack } from '~/utils/ui'; |
22 | 27 | import { arraySortOn } from '~/utils/utils';
|
23 | 28 | import { colors } from '~/variables';
|
24 | 29 | import { HereFeature, PhotonFeature } from './Features';
|
25 |
| - import { onThemeChanged } from '~/helpers/theme'; |
26 |
| - import { NativeViewElementNode } from 'svelte-native/dom'; |
27 |
| - import { CollectionView } from '@nativescript-community/ui-collectionview'; |
28 |
| - import { LineGeometry } from '@nativescript-community/ui-carto/geometry'; |
29 | 30 |
|
30 | 31 | $: ({ colorOnSurface, colorOnSurfaceVariant } = $colors);
|
31 | 32 |
|
|
38 | 39 | export let searchResultsCount = 0;
|
39 | 40 | const mapContext = getMapContext();
|
40 | 41 |
|
41 |
| -
|
42 | 42 | // export function getFilteredDataItems() {
|
43 | 43 | // return filteredDataItems;
|
44 | 44 | // }
|
|
116 | 116 | 'distance'
|
117 | 117 | ) as GeoResult[];
|
118 | 118 | }
|
119 |
| - async function searchInVectorTiles(enabled: boolean, options: SearchRequest & VectorTileSearchServiceOptions) { |
| 119 | + async function searchInVectorTiles(enabled: boolean, options: SearchRequest & VectorTileSearchServiceOptions & { bounds?: MapBounds }) { |
120 | 120 | if (!enabled) {
|
121 | 121 | return [];
|
122 | 122 | }
|
123 |
| - DEV_LOG && console.log('searchInVectorTiles', JSON.stringify(options)); |
124 | 123 | const result = await packageService.searchInVectorTiles(options);
|
125 | 124 | if (result) {
|
126 | 125 | return packageService.convertFeatureCollection(result, options);
|
|
202 | 201 | 'distance'
|
203 | 202 | );
|
204 | 203 | }
|
205 |
| - export async function instantSearch(_query, position = mapContext.getMap().focusPos) { |
| 204 | + export async function instantSearch(_query, position?: GenericMapPos<LatLonKeys>, item?: Item) { |
206 | 205 | try {
|
207 | 206 | loading = true;
|
208 | 207 | currentQuery = cleanUpString(_query);
|
209 |
| - const mpp = getMetersPerPixel(position, mapContext.getMap().getZoom()); |
210 |
| - const searchRadius = Math.min(Math.max(mpp * Screen.mainScreen.widthPixels * 2, mpp * Screen.mainScreen.heightPixels * 2), 50000); //meters; |
| 208 | + let bounds: MapBounds<LatLonKeys>; |
| 209 | + if (!position) { |
| 210 | + if (item) { |
| 211 | + if (item.properties?.zoomBounds) { |
| 212 | + bounds = item.properties.zoomBounds; |
| 213 | + } else if (item.properties?.extent) { |
| 214 | + let extent: [number, number, number, number] = item.properties.extent as [number, number, number, number]; |
| 215 | + if (typeof extent === 'string') { |
| 216 | + if (extent[0] !== '[') { |
| 217 | + extent = `[${extent as string}]` as any; |
| 218 | + } |
| 219 | + extent = JSON.parse(extent as any); |
| 220 | + } |
| 221 | + bounds = new MapBounds({ lat: extent[1], lon: extent[0] }, { lat: extent[3], lon: extent[2] }); |
| 222 | + } else if (item.route) { |
| 223 | + const geometry = packageService.getRouteItemGeometry(item); |
| 224 | + //we need to convert geometry bounds to wgs84 |
| 225 | + //not perfect as vectorTile geometry might not represent the whole entier route at higher zoom levels |
| 226 | + bounds = geometry?.getBounds(); |
| 227 | + } else { |
| 228 | + const geometry = item.geometry as GeoJSONPoint; |
| 229 | + position = { lat: geometry.coordinates[1], lon: geometry.coordinates[0] }; |
| 230 | + } |
| 231 | + if (bounds && !position) { |
| 232 | + position = { lat: bounds.southwest.lat + (bounds.northeast.lat - bounds.southwest.lat) / 2, lon: bounds.southwest.lon + (bounds.northeast.lon - bounds.southwest.lon) / 2 }; |
| 233 | + } |
| 234 | + } else { |
| 235 | + position = mapContext.getMap().focusPos; |
| 236 | + } |
| 237 | + } |
211 | 238 |
|
| 239 | + const mpp = getMetersPerPixel(position, mapContext.getMap().getZoom()); |
| 240 | + const searchRadius = bounds |
| 241 | + ? Math.max(getDistanceSimple(position, { lat: bounds.southwest.lat, lon: position.lon }), getDistanceSimple(position, { lon: bounds.southwest.lon, lat: position.lat })) + 1000 |
| 242 | + : Math.min(Math.max(mpp * Screen.mainScreen.widthPixels * 2, mpp * Screen.mainScreen.heightPixels * 2), 50000); //meters; |
| 243 | + DEV_LOG && console.log('instantSearch', currentQuery, !!item, position, bounds, searchRadius); |
212 | 244 | const options = {
|
213 | 245 | query: currentQuery,
|
214 | 246 | projection: mapContext.getProjection(),
|
|
222 | 254 | position,
|
223 | 255 | locationRadius: searchRadius,
|
224 | 256 | searchRadius,
|
225 |
| - bounds: getBoundsOfDistance(position, searchRadius) |
| 257 | + bounds: bounds || getBoundsOfDistance(position, searchRadius) // only for Photon |
226 | 258 | // locationRadius: 1000,
|
227 | 259 | };
|
228 |
| - DEV_LOG && console.log('instantSearch', JSON.stringify(position), mapContext.getMap().getZoom(), mpp, JSON.stringify(options)); |
| 260 | + // DEV_LOG && console.log('instantSearch', JSON.stringify(position), mapContext.getMap().getZoom(), mpp, JSON.stringify(options)); |
229 | 261 | let newDataItems = new ObservableArray<SearchItem>();
|
230 | 262 |
|
231 | 263 | function addItems(items: SearchItem[]) {
|
|
246 | 278 | // updateFilteredDataItems(filteringOSMKey);
|
247 | 279 | }
|
248 | 280 | if (/^(class|subclass)/.test(currentQuery)) {
|
249 |
| - const bounds = mapContext.getMap().getMapBounds(); |
| 281 | + bounds = bounds || mapContext.getMap().getMapBounds(); |
250 | 282 | DEV_LOG && console.log('bounds', bounds);
|
251 | 283 |
|
252 | 284 | const zoom = /peak|campsite/.test(currentQuery) ? 11 : 14;
|
|
257 | 289 | await searchInVectorTiles(true, {
|
258 | 290 | projection: options.projection,
|
259 | 291 | geometry,
|
| 292 | + bounds, |
260 | 293 | minZoom: zoom,
|
261 | 294 | maxZoom: zoom,
|
262 | 295 | filterExpression: `regexp_ilike(${array[0]},'.*${array[1]}.*')`
|
|
298 | 331 | }
|
299 | 332 | }
|
300 | 333 | export function clearSearch(clearQuery = true) {
|
301 |
| - DEV_LOG && console.log('clearSearch', clearQuery, new Error().stack); |
| 334 | + // DEV_LOG && console.log('clearSearch', clearQuery, new Error().stack); |
302 | 335 | networkService.clearRequests('photon', 'here');
|
303 | 336 | loading = false;
|
304 | 337 | dataItems = new ObservableArray();
|
|
0 commit comments