From 999e5ebbe50424321c96b3da7b39830bfa5432c9 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 20 Dec 2024 04:46:02 +0900 Subject: [PATCH 01/26] Fetch the tile server URL from photo-location-map-resources repo. --- angular.webpack.ts | 1 + package-lock.json | 1 + package.json | 1 + .../map/leaflet-map/leaflet-map.component.ts | 13 ++++++++-- src/app/map/leaflet-map/tile-server-config.ts | 26 +++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/app/map/leaflet-map/tile-server-config.ts diff --git a/angular.webpack.ts b/angular.webpack.ts index dc55353c..50177880 100644 --- a/angular.webpack.ts +++ b/angular.webpack.ts @@ -5,5 +5,6 @@ import * as webpack from 'webpack'; // See https://www.npmjs.com/package/@angular-builders/custom-webpack#custom-webpack-config-function export default (config: webpack.Configuration, options: CustomWebpackBrowserSchema) => { config.target = 'electron-renderer'; + config.experiments.topLevelAwait = true; return config; }; diff --git a/package-lock.json b/package-lock.json index 4875b0df..cd7e41ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,6 +91,7 @@ "espower-typescript": "10.0.1", "exif-parser": "0.1.12", "jasmine-core": "5.2.0", + "jsonc-parser": "3.3.1", "karma": "6.4.4", "karma-coverage-istanbul-reporter": "3.0.3", "karma-electron": "7.3.0", diff --git a/package.json b/package.json index b1836577..6d1d01d5 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "espower-typescript": "10.0.1", "exif-parser": "0.1.12", "jasmine-core": "5.2.0", + "jsonc-parser": "3.3.1", "karma": "6.4.4", "karma-coverage-istanbul-reporter": "3.0.3", "karma-electron": "7.3.0", diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index 27882617..a84a6bb5 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -14,6 +14,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; +import { tileServerConfig } from './tile-server-config'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html @@ -192,8 +193,16 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private getOsmLayer() { - return L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors, CC-BY-SA', + const tileProviderName = tileServerConfig.RasterTileProvidersInUse[0]; + if (!tileProviderName) { + throw new Error(`RasterTileProvidersInUse[0] is invalid. tileProviderName: ${tileProviderName}`); + } + const tileProvider = tileServerConfig.RasterTileProvidersDefinition.find(provider => provider.Name === tileProviderName); + if (!tileProvider) { + throw new Error(`tileProvider is not found for tileProviderName "${tileProviderName}"`); + } + return L.tileLayer(tileProvider.Url, { + attribution: tileProvider.Attribution, ...this.commonLayerOptions, }); } diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts new file mode 100644 index 00000000..c553ad7f --- /dev/null +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -0,0 +1,26 @@ +import { parse as parseJsonc } from 'jsonc-parser'; + +const configFileUrl + = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@6ad4277b2488695b3daba3ea66996f39dd97f7bb/map-config/osm-tile-server-config-version-1.jsonc'; + +interface RasterTileProviderDefinition { + Name: string; + Url: string; + Attribution: string; +} + +interface TileServerConfig { + RasterTileProvidersInUse: string[]; + RasterTileProvidersDefinition: RasterTileProviderDefinition[]; +} + +async function fetchTileServerConfig(): Promise { + const response = await fetch(configFileUrl); + const jsonc = await response.text(); + const json = parseJsonc(jsonc); + return json as TileServerConfig; +} + +export const tileServerConfig = await fetchTileServerConfig(); + +console.log('tileServerConfig:', tileServerConfig); From 363910cbb2a912a51028ebfcc53d0d97a40109b6 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 21 Dec 2024 15:40:25 +0900 Subject: [PATCH 02/26] Use the latest content of main branch in photo-location-map-resources repo. --- src/app/map/leaflet-map/tile-server-config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index c553ad7f..24f5ad73 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -1,7 +1,8 @@ import { parse as parseJsonc } from 'jsonc-parser'; +// The latest content of main branch in photo-location-map-resources repo is used. const configFileUrl - = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@6ad4277b2488695b3daba3ea66996f39dd97f7bb/map-config/osm-tile-server-config-version-1.jsonc'; + = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-config/osm-tile-server-config-version-1.jsonc'; interface RasterTileProviderDefinition { Name: string; From 16c8915327fe6e552fa18b1c4d9bf7be1ca54d99 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 21 Dec 2024 15:48:38 +0900 Subject: [PATCH 03/26] Use lowerCamelCase. --- src/app/map/leaflet-map/leaflet-map.component.ts | 8 ++++---- src/app/map/leaflet-map/tile-server-config.ts | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index a84a6bb5..fafa5798 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -193,16 +193,16 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private getOsmLayer() { - const tileProviderName = tileServerConfig.RasterTileProvidersInUse[0]; + const tileProviderName = tileServerConfig.rasterTileProvidersInUse[0]; if (!tileProviderName) { throw new Error(`RasterTileProvidersInUse[0] is invalid. tileProviderName: ${tileProviderName}`); } - const tileProvider = tileServerConfig.RasterTileProvidersDefinition.find(provider => provider.Name === tileProviderName); + const tileProvider = tileServerConfig.rasterTileProvidersDefinition.find(provider => provider.name === tileProviderName); if (!tileProvider) { throw new Error(`tileProvider is not found for tileProviderName "${tileProviderName}"`); } - return L.tileLayer(tileProvider.Url, { - attribution: tileProvider.Attribution, + return L.tileLayer(tileProvider.url, { + attribution: tileProvider.attribution, ...this.commonLayerOptions, }); } diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 24f5ad73..60671b63 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -5,14 +5,14 @@ const configFileUrl = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-config/osm-tile-server-config-version-1.jsonc'; interface RasterTileProviderDefinition { - Name: string; - Url: string; - Attribution: string; + name: string; + url: string; + attribution: string; } interface TileServerConfig { - RasterTileProvidersInUse: string[]; - RasterTileProvidersDefinition: RasterTileProviderDefinition[]; + rasterTileProvidersInUse: string[]; + rasterTileProvidersDefinition: RasterTileProviderDefinition[]; } async function fetchTileServerConfig(): Promise { From 3047c1e17f2c335cd1db24e70fa76703e583b42c Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 21 Dec 2024 15:50:56 +0900 Subject: [PATCH 04/26] Sort alphabetically. --- angular.webpack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/angular.webpack.ts b/angular.webpack.ts index 50177880..f95a8488 100644 --- a/angular.webpack.ts +++ b/angular.webpack.ts @@ -4,7 +4,7 @@ import * as webpack from 'webpack'; // This is Custom Webpack Config Function. // See https://www.npmjs.com/package/@angular-builders/custom-webpack#custom-webpack-config-function export default (config: webpack.Configuration, options: CustomWebpackBrowserSchema) => { - config.target = 'electron-renderer'; config.experiments.topLevelAwait = true; + config.target = 'electron-renderer'; return config; }; From 4aee109ec467f21c26ac4d74be656a72c3dfe3a2 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 21 Dec 2024 16:09:21 +0900 Subject: [PATCH 05/26] Introduce the fallback for TileServerConfig in case of fetching it fails. --- src/app/map/leaflet-map/tile-server-config.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 60671b63..df8cbc8a 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -11,10 +11,23 @@ interface RasterTileProviderDefinition { } interface TileServerConfig { + version: string; rasterTileProvidersInUse: string[]; rasterTileProvidersDefinition: RasterTileProviderDefinition[]; } +const tileServerConfigFallback: TileServerConfig = { + version: '1', + rasterTileProvidersInUse: ['StandardTileLayer'], + rasterTileProvidersDefinition: [ + { + name: 'StandardTileLayer', + url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + attribution: '© OpenStreetMap contributors' + } + ], +}; + async function fetchTileServerConfig(): Promise { const response = await fetch(configFileUrl); const jsonc = await response.text(); @@ -22,6 +35,21 @@ async function fetchTileServerConfig(): Promise { return json as TileServerConfig; } -export const tileServerConfig = await fetchTileServerConfig(); +async function fetchTileServerConfigWithFallback(): Promise { + try { + const config = await fetchTileServerConfig(); + if (!config) { + return tileServerConfigFallback; + } + return config; + } catch (error) { + console.error('Failed to fetch tile server config. Using fallback config.', error); + return tileServerConfigFallback; + } +} + +console.log(`Fetching tile server config from ${configFileUrl}`); + +export const tileServerConfig = await fetchTileServerConfigWithFallback(); console.log('tileServerConfig:', tileServerConfig); From 4e65576c759354482f5704ba0ae35adb4ca8c009 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 21 Dec 2024 16:40:21 +0900 Subject: [PATCH 06/26] Improve logging. Introduce the fallback in case of failing to parse tileServerConfig to determine tileProvider. --- .../map/leaflet-map/leaflet-map.component.ts | 24 ++++++++++++++++--- src/app/map/leaflet-map/tile-server-config.ts | 10 ++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index fafa5798..a0e8bef6 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -4,6 +4,7 @@ import { Control, LayersControlEvent, LeafletEvent, Map, Marker, PopupEvent } fr import * as _ from 'lodash'; import { Subscription } from 'rxjs'; import { Analytics } from '../../../../src-shared/analytics/analytics'; +import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; import { UserDataStorage } from '../../../../src-shared/user-data-storage/user-data-storage'; import { UserDataStoragePath } from '../../../../src-shared/user-data-storage/user-data-stroage-path'; import { DirectoryTreeViewSelectionService } from '../../directory-tree-view/directory-tree-view-selection.service'; @@ -14,7 +15,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -import { tileServerConfig } from './tile-server-config'; +import { tileServerConfig, tileServerConfigFallback } from './tile-server-config'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html @@ -195,18 +196,35 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { private getOsmLayer() { const tileProviderName = tileServerConfig.rasterTileProvidersInUse[0]; if (!tileProviderName) { - throw new Error(`RasterTileProvidersInUse[0] is invalid. tileProviderName: ${tileProviderName}`); + logger.error(`RasterTileProvidersInUse[0] is invalid. tileProviderName: ${tileProviderName}`); + logger.error(`Using the fallback for tileProvider:\n${this.getTileProviderFallback()}`); + return this.getOsmLayerFallback(); } const tileProvider = tileServerConfig.rasterTileProvidersDefinition.find(provider => provider.name === tileProviderName); if (!tileProvider) { - throw new Error(`tileProvider is not found for tileProviderName "${tileProviderName}"`); + logger.error(`tileProvider is not found for tileProviderName "${tileProviderName}"`); + logger.error(`Using the fallback for tileProvider:\n${this.getTileProviderFallback()}`); + return this.getOsmLayerFallback(); } + logger.info(`Successfully determined tileProvider:\n${toLoggableString(tileProvider)}`); return L.tileLayer(tileProvider.url, { attribution: tileProvider.attribution, ...this.commonLayerOptions, }); } + private getOsmLayerFallback() { + const tileProviderFallback = this.getTileProviderFallback(); + return L.tileLayer(tileProviderFallback.url, { + attribution: tileProviderFallback.attribution, + ...this.commonLayerOptions, + }); + } + + private getTileProviderFallback() { + return tileServerConfigFallback.rasterTileProvidersDefinition[0]; + } + private configureRegionSelector() { this.configureRegionInfo(); this.configureLeafletGeoman(); diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index df8cbc8a..9fa7360a 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -1,4 +1,6 @@ import { parse as parseJsonc } from 'jsonc-parser'; +import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; +import { leafletMapLogger as logger } from './leaflet-map-logger'; // The latest content of main branch in photo-location-map-resources repo is used. const configFileUrl @@ -16,7 +18,7 @@ interface TileServerConfig { rasterTileProvidersDefinition: RasterTileProviderDefinition[]; } -const tileServerConfigFallback: TileServerConfig = { +export const tileServerConfigFallback: TileServerConfig = { version: '1', rasterTileProvidersInUse: ['StandardTileLayer'], rasterTileProvidersDefinition: [ @@ -43,13 +45,13 @@ async function fetchTileServerConfigWithFallback(): Promise { } return config; } catch (error) { - console.error('Failed to fetch tile server config. Using fallback config.', error); + logger.error('Failed to fetch tile server config. Using fallback config.', error); return tileServerConfigFallback; } } -console.log(`Fetching tile server config from ${configFileUrl}`); +logger.info(`Fetching tileServerConfig from ${configFileUrl}`); export const tileServerConfig = await fetchTileServerConfigWithFallback(); -console.log('tileServerConfig:', tileServerConfig); +logger.info(`Fetched tileServerConfig:\n${toLoggableString(tileServerConfig)}`); From 9ef10982a2850c17710349b022bdc241340f13eb Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 01:57:22 +0900 Subject: [PATCH 07/26] Adopt the updated format of osm-tile-server-config-version-1.jsonc in photo-location-map-resources repo. --- src/app/map/leaflet-map/leaflet-map.component.ts | 12 +++--------- src/app/map/leaflet-map/tile-server-config.ts | 14 +++++++------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index a0e8bef6..75d7742d 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -194,15 +194,9 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private getOsmLayer() { - const tileProviderName = tileServerConfig.rasterTileProvidersInUse[0]; - if (!tileProviderName) { - logger.error(`RasterTileProvidersInUse[0] is invalid. tileProviderName: ${tileProviderName}`); - logger.error(`Using the fallback for tileProvider:\n${this.getTileProviderFallback()}`); - return this.getOsmLayerFallback(); - } - const tileProvider = tileServerConfig.rasterTileProvidersDefinition.find(provider => provider.name === tileProviderName); + const tileProvider = tileServerConfig.rasterTileProviders[0]; if (!tileProvider) { - logger.error(`tileProvider is not found for tileProviderName "${tileProviderName}"`); + logger.error(`rasterTileProviders[0] is invalid. uniqueName: ${tileProvider.uniqueName}, displayName: ${tileProvider.displayName}`); logger.error(`Using the fallback for tileProvider:\n${this.getTileProviderFallback()}`); return this.getOsmLayerFallback(); } @@ -222,7 +216,7 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private getTileProviderFallback() { - return tileServerConfigFallback.rasterTileProvidersDefinition[0]; + return tileServerConfigFallback.rasterTileProviders[0]; } private configureRegionSelector() { diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 9fa7360a..9426786a 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -6,24 +6,24 @@ import { leafletMapLogger as logger } from './leaflet-map-logger'; const configFileUrl = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-config/osm-tile-server-config-version-1.jsonc'; -interface RasterTileProviderDefinition { - name: string; +interface RasterTileProvider { + uniqueName: string; + displayName: string; url: string; attribution: string; } interface TileServerConfig { version: string; - rasterTileProvidersInUse: string[]; - rasterTileProvidersDefinition: RasterTileProviderDefinition[]; + rasterTileProviders: RasterTileProvider[]; } export const tileServerConfigFallback: TileServerConfig = { version: '1', - rasterTileProvidersInUse: ['StandardTileLayer'], - rasterTileProvidersDefinition: [ + rasterTileProviders: [ { - name: 'StandardTileLayer', + uniqueName: 'StandardTileLayer', + displayName: 'OpenStreetMap', url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '© OpenStreetMap contributors' } From b2391dbc6697a1131862b9fb3de95e24b6605b2e Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 02:03:49 +0900 Subject: [PATCH 08/26] Update logging. --- src/app/map/leaflet-map/tile-server-config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 9426786a..76993032 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -41,11 +41,12 @@ async function fetchTileServerConfigWithFallback(): Promise { try { const config = await fetchTileServerConfig(); if (!config) { + logger.error('Failed to fetch the tile server config. The config object is invalid. Using fallback config.'); return tileServerConfigFallback; } return config; } catch (error) { - logger.error('Failed to fetch tile server config. Using fallback config.', error); + logger.error('Failed to fetch the tile server config with some error. Using fallback config.', error); return tileServerConfigFallback; } } From 734fbb8eb2d4b0fcccadb01401d4b1b518004d75 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 02:12:07 +0900 Subject: [PATCH 09/26] Update error handling and logging. --- src/app/map/leaflet-map/tile-server-config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 76993032..6b8e8634 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -40,13 +40,13 @@ async function fetchTileServerConfig(): Promise { async function fetchTileServerConfigWithFallback(): Promise { try { const config = await fetchTileServerConfig(); - if (!config) { - logger.error('Failed to fetch the tile server config. The config object is invalid. Using fallback config.'); + if (!config?.rasterTileProviders?.length) { + logger.error('Failed to fetch the tile server config. The config object is invalid. Using the fallback config.'); return tileServerConfigFallback; } return config; } catch (error) { - logger.error('Failed to fetch the tile server config with some error. Using fallback config.', error); + logger.error('Failed to fetch the tile server config with some error. Using the fallback config.', error); return tileServerConfigFallback; } } From 4ce197710563a9f2aa92a1ed8889693f3edd77fc Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 02:49:11 +0900 Subject: [PATCH 10/26] Handle configuring the list of layers from the fetched URL (instead of having the fixed list of layers). --- .../map/leaflet-map/leaflet-map.component.ts | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index 75d7742d..c1f51026 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -150,18 +150,16 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private configureBaseLayer() { - const bingLayer = this.getBingLayer(); - const osmLayer = this.getOsmLayer(); + const osmLayers = this.getOsmLayers(); + const bingLayers = this.getBingLayers(); const baseLayers = { - 'Bing (Road)': bingLayer.roadOnDemand, - 'Bing (Aerial)': bingLayer.aerial, - 'Bing (Aerial with Labels)': bingLayer.aerialWithLabelsOnDemand, - 'OpenStreetMap': osmLayer, + ...osmLayers, + ...bingLayers, }; L.control.layers(baseLayers, null, {position: 'topright'}).addTo(this.map); const previousBaseLayer = baseLayers[this.selectedBaseLayerName]; - const defaultBaseLayer = bingLayer.roadOnDemand; + const defaultBaseLayer = baseLayers[Object.keys(baseLayers)[0]]; const selectedBaseLayer = previousBaseLayer ?? defaultBaseLayer; selectedBaseLayer.addTo(this.map); @@ -170,7 +168,19 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { }); } - private getBingLayer() { + private getOsmLayers() { + const layers = {}; + tileServerConfig.rasterTileProviders.forEach(tileProvider => { + const tileLayer = L.tileLayer(tileProvider.url, { + attribution: tileProvider.attribution, + ...this.commonLayerOptions, + }); + layers[tileProvider.displayName] = tileLayer; + }); + return layers; + } + + private getBingLayers() { const bingMapsKey = '96S0sLgTrpX5VudevEyg~93qOp_-tPdiBcUw_Q-mpUg~AtbViWkzvmAlU9MB08o4mka92JlnRQnYHrHP8GKZBbl0caebqVS95jsvOKVHvrt3'; const bingMapsOptions = { key: bingMapsKey, @@ -180,7 +190,11 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { const roadOnDemand = new L.bingLayer(L.extend({imagerySet: 'RoadOnDemand'}, bingMapsOptions)); const aerial = new L.bingLayer(L.extend({imagerySet: 'Aerial'}, bingMapsOptions)); const aerialWithLabelsOnDemand = new L.bingLayer(L.extend({imagerySet: 'AerialWithLabelsOnDemand'}, bingMapsOptions)); - return {roadOnDemand, aerial, aerialWithLabelsOnDemand}; + return { + 'Bing (Road)': roadOnDemand, + 'Bing (Aerial)': aerial, + 'Bing (Aerial with Labels)': aerialWithLabelsOnDemand, + }; } private getCultureForBingMaps(): string { @@ -193,32 +207,6 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { return navigator.language; } - private getOsmLayer() { - const tileProvider = tileServerConfig.rasterTileProviders[0]; - if (!tileProvider) { - logger.error(`rasterTileProviders[0] is invalid. uniqueName: ${tileProvider.uniqueName}, displayName: ${tileProvider.displayName}`); - logger.error(`Using the fallback for tileProvider:\n${this.getTileProviderFallback()}`); - return this.getOsmLayerFallback(); - } - logger.info(`Successfully determined tileProvider:\n${toLoggableString(tileProvider)}`); - return L.tileLayer(tileProvider.url, { - attribution: tileProvider.attribution, - ...this.commonLayerOptions, - }); - } - - private getOsmLayerFallback() { - const tileProviderFallback = this.getTileProviderFallback(); - return L.tileLayer(tileProviderFallback.url, { - attribution: tileProviderFallback.attribution, - ...this.commonLayerOptions, - }); - } - - private getTileProviderFallback() { - return tileServerConfigFallback.rasterTileProviders[0]; - } - private configureRegionSelector() { this.configureRegionInfo(); this.configureLeafletGeoman(); From efee0e4581dbecb6b4a4172b6a6ab6b571b52c29 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 02:53:26 +0900 Subject: [PATCH 11/26] Remove unused import. --- src/app/map/leaflet-map/leaflet-map.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index c1f51026..a1336223 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -4,7 +4,6 @@ import { Control, LayersControlEvent, LeafletEvent, Map, Marker, PopupEvent } fr import * as _ from 'lodash'; import { Subscription } from 'rxjs'; import { Analytics } from '../../../../src-shared/analytics/analytics'; -import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; import { UserDataStorage } from '../../../../src-shared/user-data-storage/user-data-storage'; import { UserDataStoragePath } from '../../../../src-shared/user-data-storage/user-data-stroage-path'; import { DirectoryTreeViewSelectionService } from '../../directory-tree-view/directory-tree-view-selection.service'; @@ -15,7 +14,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -import { tileServerConfig, tileServerConfigFallback } from './tile-server-config'; +import { tileServerConfig } from './tile-server-config'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html From 13ff719b349c425838582b5b205ec34ed8386903 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Fri, 27 Dec 2024 03:30:08 +0900 Subject: [PATCH 12/26] Use "name" instead of "uniqueName" or "displayName". This is because 1) leaflet simply handles the name when the layer is changed and 2) the layer name needs to be unique anyway from the user standpoint (i.e. having layers with the same name is confusing to users). --- src/app/map/leaflet-map/leaflet-map.component.ts | 2 +- src/app/map/leaflet-map/tile-server-config.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index a1336223..a619fd9f 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -174,7 +174,7 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { attribution: tileProvider.attribution, ...this.commonLayerOptions, }); - layers[tileProvider.displayName] = tileLayer; + layers[tileProvider.name] = tileLayer; }); return layers; } diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts index 6b8e8634..ae995ba6 100644 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ b/src/app/map/leaflet-map/tile-server-config.ts @@ -7,8 +7,7 @@ const configFileUrl = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-config/osm-tile-server-config-version-1.jsonc'; interface RasterTileProvider { - uniqueName: string; - displayName: string; + name: string; url: string; attribution: string; } @@ -22,8 +21,7 @@ export const tileServerConfigFallback: TileServerConfig = { version: '1', rasterTileProviders: [ { - uniqueName: 'StandardTileLayer', - displayName: 'OpenStreetMap', + name: 'OpenStreetMap', url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', attribution: '© OpenStreetMap contributors' } From b98f04de330db6cfa9c7effe3427ca71df67801b Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 28 Dec 2024 14:35:00 +0900 Subject: [PATCH 13/26] Fetch the renamed file with the updated file format for the tile layers. --- .../map/leaflet-map/leaflet-map.component.ts | 21 +++--- .../tile-layer-configs-version-1.ts | 66 +++++++++++++++++++ src/app/map/leaflet-map/tile-server-config.ts | 56 ---------------- 3 files changed, 75 insertions(+), 68 deletions(-) create mode 100644 src/app/map/leaflet-map/tile-layer-configs-version-1.ts delete mode 100644 src/app/map/leaflet-map/tile-server-config.ts diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index a619fd9f..a3cb5ec4 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -14,7 +14,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -import { tileServerConfig } from './tile-server-config'; +import { tileLayerConfigsVersion1 } from './tile-layer-configs-version-1'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html @@ -149,10 +149,10 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private configureBaseLayer() { - const osmLayers = this.getOsmLayers(); + const tileLayers = this.getTileLayers(); const bingLayers = this.getBingLayers(); const baseLayers = { - ...osmLayers, + ...tileLayers, ...bingLayers, }; L.control.layers(baseLayers, null, {position: 'topright'}).addTo(this.map); @@ -167,16 +167,13 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { }); } - private getOsmLayers() { - const layers = {}; - tileServerConfig.rasterTileProviders.forEach(tileProvider => { - const tileLayer = L.tileLayer(tileProvider.url, { - attribution: tileProvider.attribution, - ...this.commonLayerOptions, - }); - layers[tileProvider.name] = tileLayer; + private getTileLayers() { + const tileLayers = {}; + tileLayerConfigsVersion1.tileLayerConfigs.forEach(tileLayerConfig => { + const tileLayer = L.tileLayer(tileLayerConfig.url, tileLayerConfig.options); + tileLayers[tileLayerConfig.name] = tileLayer; }); - return layers; + return tileLayers; } private getBingLayers() { diff --git a/src/app/map/leaflet-map/tile-layer-configs-version-1.ts b/src/app/map/leaflet-map/tile-layer-configs-version-1.ts new file mode 100644 index 00000000..ee74edcf --- /dev/null +++ b/src/app/map/leaflet-map/tile-layer-configs-version-1.ts @@ -0,0 +1,66 @@ +import { parse as parseJsonc } from 'jsonc-parser'; +import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; +import { leafletMapLogger as logger } from './leaflet-map-logger'; + +// The latest content of main branch in photo-location-map-resources repo is used. +const configFileUrl + = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/tile-layer-configs-version-1.jsonc'; + +interface TileLayerConfigs { + name: string; + url: string; + options?: any; +} + +interface TileLayerConfigsVersion1 { + version: string; + tileLayerConfigs: TileLayerConfigs[]; +} + +export const tileLayerConfigsVersion1Fallback: TileLayerConfigsVersion1 = { + version: '1', + tileLayerConfigs: [ + { + name: 'OpenStreetMap', + url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + attribution: '© OpenStreetMap contributors', + maxZoom: 19 + } + }, + { + name: 'Esri World Imagery', + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', + options: { + attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' + } + } + ], +}; + +async function fetchTileLayerConfigsVersion1(): Promise { + const response = await fetch(configFileUrl); + const jsonc = await response.text(); + const json = parseJsonc(jsonc); + return json as TileLayerConfigsVersion1; +} + +async function fetchTileLayerConfigsVersion1WithFallback(): Promise { + try { + const configs = await fetchTileLayerConfigsVersion1(); + if (!configs?.tileLayerConfigs?.length) { + logger.error('Failed to fetch the tile layer configs. The configs object is invalid. Using the fallback configs.'); + return tileLayerConfigsVersion1Fallback; + } + return configs; + } catch (error) { + logger.error('Failed to fetch the tile layer configs with some error. Using the fallback configs.', error); + return tileLayerConfigsVersion1Fallback; + } +} + +logger.info(`Fetching tileLayerConfigsVersion1 from ${configFileUrl}`); + +export const tileLayerConfigsVersion1 = await fetchTileLayerConfigsVersion1WithFallback(); + +logger.info(`Fetched tileLayerConfigsVersion1:\n${toLoggableString(tileLayerConfigsVersion1)}`); diff --git a/src/app/map/leaflet-map/tile-server-config.ts b/src/app/map/leaflet-map/tile-server-config.ts deleted file mode 100644 index ae995ba6..00000000 --- a/src/app/map/leaflet-map/tile-server-config.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { parse as parseJsonc } from 'jsonc-parser'; -import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; -import { leafletMapLogger as logger } from './leaflet-map-logger'; - -// The latest content of main branch in photo-location-map-resources repo is used. -const configFileUrl - = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-config/osm-tile-server-config-version-1.jsonc'; - -interface RasterTileProvider { - name: string; - url: string; - attribution: string; -} - -interface TileServerConfig { - version: string; - rasterTileProviders: RasterTileProvider[]; -} - -export const tileServerConfigFallback: TileServerConfig = { - version: '1', - rasterTileProviders: [ - { - name: 'OpenStreetMap', - url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - attribution: '© OpenStreetMap contributors' - } - ], -}; - -async function fetchTileServerConfig(): Promise { - const response = await fetch(configFileUrl); - const jsonc = await response.text(); - const json = parseJsonc(jsonc); - return json as TileServerConfig; -} - -async function fetchTileServerConfigWithFallback(): Promise { - try { - const config = await fetchTileServerConfig(); - if (!config?.rasterTileProviders?.length) { - logger.error('Failed to fetch the tile server config. The config object is invalid. Using the fallback config.'); - return tileServerConfigFallback; - } - return config; - } catch (error) { - logger.error('Failed to fetch the tile server config with some error. Using the fallback config.', error); - return tileServerConfigFallback; - } -} - -logger.info(`Fetching tileServerConfig from ${configFileUrl}`); - -export const tileServerConfig = await fetchTileServerConfigWithFallback(); - -logger.info(`Fetched tileServerConfig:\n${toLoggableString(tileServerConfig)}`); From c99646cc82c4d95320cf400e868067a9c5fbcad7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sat, 28 Dec 2024 23:14:37 +0900 Subject: [PATCH 14/26] Rename to RasterTileBaseLayerConfigs. --- .../map/leaflet-map/leaflet-map.component.ts | 14 ++-- ...raster-tile-base-layer-configs-version1.ts | 74 +++++++++++++++++++ .../tile-layer-configs-version-1.ts | 66 ----------------- 3 files changed, 81 insertions(+), 73 deletions(-) create mode 100644 src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts delete mode 100644 src/app/map/leaflet-map/tile-layer-configs-version-1.ts diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index a3cb5ec4..5e40b917 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -14,7 +14,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -import { tileLayerConfigsVersion1 } from './tile-layer-configs-version-1'; +import { rasterTileBaseLayerConfigsVersion1 } from './raster-tile-base-layer-configs-version1'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html @@ -149,10 +149,10 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { } private configureBaseLayer() { - const tileLayers = this.getTileLayers(); + const rasterTileBaseLayers = this.getRasterTileBaseLayers(); const bingLayers = this.getBingLayers(); const baseLayers = { - ...tileLayers, + ...rasterTileBaseLayers, ...bingLayers, }; L.control.layers(baseLayers, null, {position: 'topright'}).addTo(this.map); @@ -167,11 +167,11 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { }); } - private getTileLayers() { + private getRasterTileBaseLayers() { const tileLayers = {}; - tileLayerConfigsVersion1.tileLayerConfigs.forEach(tileLayerConfig => { - const tileLayer = L.tileLayer(tileLayerConfig.url, tileLayerConfig.options); - tileLayers[tileLayerConfig.name] = tileLayer; + rasterTileBaseLayerConfigsVersion1.rasterTileBaseLayerConfigs.forEach(config => { + const tileLayer = L.tileLayer(config.url, config.options); + tileLayers[config.name] = tileLayer; }); return tileLayers; } diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts new file mode 100644 index 00000000..89b28a10 --- /dev/null +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts @@ -0,0 +1,74 @@ +import { parse as parseJsonc } from 'jsonc-parser'; +import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; +import { leafletMapLogger as logger } from './leaflet-map-logger'; + +// In the production environment, the content of main branch in photo-location-map-resources repo is used. +// In the development environment, the content of the feature branch can be used as needed. +const configFileUrl + = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/raster-tile-base-layer-configs-version-1.jsonc'; + +interface RasterTileBaseLayerConfigs { + name: string; + url: string; + options?: any; +} + +interface RasterTileBaseLayerConfigsVersion1 { + version: string; + rasterTileBaseLayerConfigs: RasterTileBaseLayerConfigs[]; +} + +export const rasterTileBaseLayerConfigsVersion1Fallback: RasterTileBaseLayerConfigsVersion1 = { + version: '1', + rasterTileBaseLayerConfigs: [ + { + name: 'OpenStreetMap', + url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + options: { + attribution: '© OpenStreetMap contributors', + maxZoom: 19 + } + }, + { + name: 'Esri World Street Map', + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}', + options: { + attribution: 'Tiles © Esri — Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012' + } + }, + { + name: 'Esri World Imagery', + url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', + options: { + attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' + } + } + ], +}; + +async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { + const response = await fetch(configFileUrl); + const jsonc = await response.text(); + const json = parseJsonc(jsonc); + return json as RasterTileBaseLayerConfigsVersion1; +} + +async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise { + try { + const configs = await fetchRasterTileBaseLayerConfigsVersion1(); + if (!configs?.rasterTileBaseLayerConfigs?.length) { + logger.error('Failed to fetch RasterTileBaseLayerConfigsVersion1. The configs object is invalid. Using the fallback configs.'); + return rasterTileBaseLayerConfigsVersion1Fallback; + } + return configs; + } catch (error) { + logger.error('Failed to fetch RasterTileBaseLayerConfigsVersion1 with some error. Using the fallback configs.', error); + return rasterTileBaseLayerConfigsVersion1Fallback; + } +} + +logger.info(`Fetching RasterTileBaseLayerConfigsVersion1 from ${configFileUrl}`); + +export const rasterTileBaseLayerConfigsVersion1 = await fetchRasterTileBaseLayerConfigsVersion1WithFallback(); + +logger.info(`Fetched RasterTileBaseLayerConfigsVersion1:\n${toLoggableString(rasterTileBaseLayerConfigsVersion1)}`); diff --git a/src/app/map/leaflet-map/tile-layer-configs-version-1.ts b/src/app/map/leaflet-map/tile-layer-configs-version-1.ts deleted file mode 100644 index ee74edcf..00000000 --- a/src/app/map/leaflet-map/tile-layer-configs-version-1.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { parse as parseJsonc } from 'jsonc-parser'; -import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; -import { leafletMapLogger as logger } from './leaflet-map-logger'; - -// The latest content of main branch in photo-location-map-resources repo is used. -const configFileUrl - = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/tile-layer-configs-version-1.jsonc'; - -interface TileLayerConfigs { - name: string; - url: string; - options?: any; -} - -interface TileLayerConfigsVersion1 { - version: string; - tileLayerConfigs: TileLayerConfigs[]; -} - -export const tileLayerConfigsVersion1Fallback: TileLayerConfigsVersion1 = { - version: '1', - tileLayerConfigs: [ - { - name: 'OpenStreetMap', - url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - options: { - attribution: '© OpenStreetMap contributors', - maxZoom: 19 - } - }, - { - name: 'Esri World Imagery', - url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', - options: { - attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' - } - } - ], -}; - -async function fetchTileLayerConfigsVersion1(): Promise { - const response = await fetch(configFileUrl); - const jsonc = await response.text(); - const json = parseJsonc(jsonc); - return json as TileLayerConfigsVersion1; -} - -async function fetchTileLayerConfigsVersion1WithFallback(): Promise { - try { - const configs = await fetchTileLayerConfigsVersion1(); - if (!configs?.tileLayerConfigs?.length) { - logger.error('Failed to fetch the tile layer configs. The configs object is invalid. Using the fallback configs.'); - return tileLayerConfigsVersion1Fallback; - } - return configs; - } catch (error) { - logger.error('Failed to fetch the tile layer configs with some error. Using the fallback configs.', error); - return tileLayerConfigsVersion1Fallback; - } -} - -logger.info(`Fetching tileLayerConfigsVersion1 from ${configFileUrl}`); - -export const tileLayerConfigsVersion1 = await fetchTileLayerConfigsVersion1WithFallback(); - -logger.info(`Fetched tileLayerConfigsVersion1:\n${toLoggableString(tileLayerConfigsVersion1)}`); From ef40a4be80fa77049c0309d181c8181cc7e47ec1 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 00:15:34 +0900 Subject: [PATCH 15/26] Rename file. --- src/app/map/leaflet-map/leaflet-map.component.ts | 2 +- ...-version1.ts => raster-tile-base-layer-configs-version-1.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/app/map/leaflet-map/{raster-tile-base-layer-configs-version1.ts => raster-tile-base-layer-configs-version-1.ts} (100%) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index 5e40b917..fd69c6d5 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -14,7 +14,7 @@ import { PhotoInfoViewerContent } from '../../photo-info-viewer/photo-info-viewe import { LeafletMapForceRenderService } from './leaflet-map-force-render/leaflet-map-force-render.service'; import { createDivIconHtml } from './div-icon'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -import { rasterTileBaseLayerConfigsVersion1 } from './raster-tile-base-layer-configs-version1'; +import { rasterTileBaseLayerConfigsVersion1 } from './raster-tile-base-layer-configs-version-1'; // References to implement Bing Maps with leaflet-plugins: // - https://github.com/shramov/leaflet-plugins/blob/master/examples/bing.html diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts similarity index 100% rename from src/app/map/leaflet-map/raster-tile-base-layer-configs-version1.ts rename to src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts From 40cf91e47080749aa5a9f20fa072d547699e8b61 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 00:47:52 +0900 Subject: [PATCH 16/26] Add Analytics of fetching RasterTileBaseLayerConfigsVersion1. --- ...aster-tile-base-layer-configs-version-1.ts | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 89b28a10..698aad7b 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -1,4 +1,5 @@ import { parse as parseJsonc } from 'jsonc-parser'; +import { Analytics } from '../../../../src-shared/analytics/analytics'; import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; import { leafletMapLogger as logger } from './leaflet-map-logger'; @@ -54,21 +55,31 @@ async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { + const fetchingMessage = `Fetching RasterTileBaseLayerConfigsVersion1 from ${configFileUrl}`; + logger.info(fetchingMessage); + Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fetching BaseLayerConfigs`, fetchingMessage); + try { const configs = await fetchRasterTileBaseLayerConfigsVersion1(); if (!configs?.rasterTileBaseLayerConfigs?.length) { - logger.error('Failed to fetch RasterTileBaseLayerConfigsVersion1. The configs object is invalid. Using the fallback configs.'); + const message = `Failed to fetch RasterTileBaseLayerConfigsVersion1. The configs object is invalid. Using the fallback configs.`; + logger.error(message); + Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fallback BaseLayerConfigs`, message); return rasterTileBaseLayerConfigsVersion1Fallback; } + + const fetchedMessage = `Fetched RasterTileBaseLayerConfigsVersion1:\n${toLoggableString(configs)}`; + logger.info(fetchedMessage); + Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fetched BaseLayerConfigs`, fetchedMessage); return configs; } catch (error) { - logger.error('Failed to fetch RasterTileBaseLayerConfigsVersion1 with some error. Using the fallback configs.', error); + const message = `Failed to fetch RasterTileBaseLayerConfigsVersion1 with some error. Using the fallback configs. error.message: "${error.message}"`; + logger.error(message); + Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fallback BaseLayerConfigs`, message); return rasterTileBaseLayerConfigsVersion1Fallback; } } -logger.info(`Fetching RasterTileBaseLayerConfigsVersion1 from ${configFileUrl}`); export const rasterTileBaseLayerConfigsVersion1 = await fetchRasterTileBaseLayerConfigsVersion1WithFallback(); -logger.info(`Fetched RasterTileBaseLayerConfigsVersion1:\n${toLoggableString(rasterTileBaseLayerConfigsVersion1)}`); From df23552f167db9e3e3730a059806e3d394a3e4d7 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 01:15:57 +0900 Subject: [PATCH 17/26] Consolidate recordErrorAndGetFallback. --- .../raster-tile-base-layer-configs-version-1.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 698aad7b..cd6d2e8f 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -54,6 +54,12 @@ async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { const fetchingMessage = `Fetching RasterTileBaseLayerConfigsVersion1 from ${configFileUrl}`; logger.info(fetchingMessage); @@ -63,9 +69,7 @@ async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise Date: Sun, 29 Dec 2024 01:29:18 +0900 Subject: [PATCH 18/26] Refactor fetchRasterTileBaseLayerConfigsVersion1WithFallback. --- ...aster-tile-base-layer-configs-version-1.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index cd6d2e8f..fd33e358 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -65,21 +65,23 @@ async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise Date: Sun, 29 Dec 2024 01:43:27 +0900 Subject: [PATCH 19/26] Reorder interface/constant. Add comments. --- ...aster-tile-base-layer-configs-version-1.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index fd33e358..3d785acb 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -3,10 +3,11 @@ import { Analytics } from '../../../../src-shared/analytics/analytics'; import { toLoggableString } from '../../../../src-shared/log/to-loggable-string'; import { leafletMapLogger as logger } from './leaflet-map-logger'; -// In the production environment, the content of main branch in photo-location-map-resources repo is used. -// In the development environment, the content of the feature branch can be used as needed. -const configFileUrl - = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/raster-tile-base-layer-configs-version-1.jsonc'; +// Represents the content of raster-tile-base-layer-configs-version-1.jsonc in photo-location-map-resources repo. +interface RasterTileBaseLayerConfigsVersion1 { + version: string; + rasterTileBaseLayerConfigs: RasterTileBaseLayerConfigs[]; +} interface RasterTileBaseLayerConfigs { name: string; @@ -14,11 +15,7 @@ interface RasterTileBaseLayerConfigs { options?: any; } -interface RasterTileBaseLayerConfigsVersion1 { - version: string; - rasterTileBaseLayerConfigs: RasterTileBaseLayerConfigs[]; -} - +// The fallback configs used in case of failing to fetch the configs from photo-location-map-resources repo. export const rasterTileBaseLayerConfigsVersion1Fallback: RasterTileBaseLayerConfigsVersion1 = { version: '1', rasterTileBaseLayerConfigs: [ @@ -47,6 +44,11 @@ export const rasterTileBaseLayerConfigsVersion1Fallback: RasterTileBaseLayerConf ], }; +// In the production environment, the content of main branch in photo-location-map-resources repo is used. +// In the development environment, the content of the feature branch can be used as needed. +const configFileUrl + = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/raster-tile-base-layer-configs-version-1.jsonc'; + async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { const response = await fetch(configFileUrl); const jsonc = await response.text(); From 451a10fd2ee6a5fd7d8e1f6d191a04c2f9e3df1b Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 01:50:28 +0900 Subject: [PATCH 20/26] Rename constant. --- .../leaflet-map/raster-tile-base-layer-configs-version-1.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 3d785acb..c5a9bf44 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -46,11 +46,11 @@ export const rasterTileBaseLayerConfigsVersion1Fallback: RasterTileBaseLayerConf // In the production environment, the content of main branch in photo-location-map-resources repo is used. // In the development environment, the content of the feature branch can be used as needed. -const configFileUrl +const configsFileUrl = 'https://cdn.jsdelivr.net/gh/TomoyukiAota/photo-location-map-resources@main/map-configs/raster-tile-base-layer-configs-version-1.jsonc'; async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { - const response = await fetch(configFileUrl); + const response = await fetch(configsFileUrl); const jsonc = await response.text(); const json = parseJsonc(jsonc); return json as RasterTileBaseLayerConfigsVersion1; @@ -63,7 +63,7 @@ function recordErrorAndGetFallback(message: string): RasterTileBaseLayerConfigsV } async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise { - const fetchingMessage = `Fetching RasterTileBaseLayerConfigsVersion1 from ${configFileUrl}`; + const fetchingMessage = `Fetching RasterTileBaseLayerConfigsVersion1 from ${configsFileUrl}`; logger.info(fetchingMessage); Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fetching BaseLayerConfigs`, fetchingMessage); From c659d4014ac83e69fa4804f3fd4de7e8496d1572 Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 02:35:02 +0900 Subject: [PATCH 21/26] Update messages. --- .../leaflet-map/raster-tile-base-layer-configs-version-1.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index c5a9bf44..0ea10f77 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -71,16 +71,16 @@ async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise Date: Sun, 29 Dec 2024 03:29:52 +0900 Subject: [PATCH 22/26] Handle the case that the server responds with an error status like 404. Update messages. --- .../raster-tile-base-layer-configs-version-1.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 0ea10f77..8c14b956 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -51,6 +51,9 @@ const configsFileUrl async function fetchRasterTileBaseLayerConfigsVersion1(): Promise { const response = await fetch(configsFileUrl); + if (!response.ok) { + throw new Error(`response.status: ${response.status}, response.statusText: ${response.statusText}`); + } const jsonc = await response.text(); const json = parseJsonc(jsonc); return json as RasterTileBaseLayerConfigsVersion1; @@ -63,7 +66,7 @@ function recordErrorAndGetFallback(message: string): RasterTileBaseLayerConfigsV } async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise { - const fetchingMessage = `Fetching RasterTileBaseLayerConfigsVersion1 from ${configsFileUrl}`; + const fetchingMessage = `Fetching ${configsFileUrl}`; logger.info(fetchingMessage); Analytics.trackEvent('Leaflet Map', `[Leaflet Map] Fetching BaseLayerConfigs`, fetchingMessage); @@ -71,16 +74,16 @@ async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise Date: Sun, 29 Dec 2024 04:17:00 +0900 Subject: [PATCH 23/26] Record the invalid configs object. --- .../map/leaflet-map/raster-tile-base-layer-configs-version-1.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 8c14b956..000f9f03 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -79,7 +79,7 @@ async function fetchRasterTileBaseLayerConfigsVersion1WithFallback(): Promise Date: Sun, 29 Dec 2024 04:29:59 +0900 Subject: [PATCH 24/26] Remove "maxZoom: 19" since marker cluster does not work well. --- .../leaflet-map/raster-tile-base-layer-configs-version-1.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts index 000f9f03..a7350929 100644 --- a/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts +++ b/src/app/map/leaflet-map/raster-tile-base-layer-configs-version-1.ts @@ -23,8 +23,7 @@ export const rasterTileBaseLayerConfigsVersion1Fallback: RasterTileBaseLayerConf name: 'OpenStreetMap', url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', options: { - attribution: '© OpenStreetMap contributors', - maxZoom: 19 + attribution: '© OpenStreetMap contributors' } }, { From 5dfa92672424eace3e3ffe6c041bc30e6d63f7fb Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 04:40:53 +0900 Subject: [PATCH 25/26] Prevent the issue that marker cluster does not work at zoom level 19. --- src/app/map/leaflet-map/leaflet-map.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index fd69c6d5..2770f821 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -40,8 +40,8 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { private pinnedPhotoServiceSubscription: Subscription; private forceRenderServiceSubscription: Subscription; private readonly commonLayerOptions = { - maxNativeZoom: 19, - maxZoom: 19, + maxNativeZoom: 18, + maxZoom: 18, // To prevent the issue that marker cluster does not work at zoom level 19. }; private map: Map; private regionInfo: RegionInfo; @@ -170,7 +170,10 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { private getRasterTileBaseLayers() { const tileLayers = {}; rasterTileBaseLayerConfigsVersion1.rasterTileBaseLayerConfigs.forEach(config => { - const tileLayer = L.tileLayer(config.url, config.options); + const tileLayer = L.tileLayer(config.url, { + ...config.options, + maxZoom: 18, // To prevent the issue that marker cluster does not work at zoom level 19. + }); tileLayers[config.name] = tileLayer; }); return tileLayers; From babd85301b60a1738c47045fd15ba88a832137bc Mon Sep 17 00:00:00 2001 From: Tomoyuki Aota Date: Sun, 29 Dec 2024 05:03:45 +0900 Subject: [PATCH 26/26] Refactor how to get defaultBaseLayer. --- src/app/map/leaflet-map/leaflet-map.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/map/leaflet-map/leaflet-map.component.ts b/src/app/map/leaflet-map/leaflet-map.component.ts index 2770f821..18cb32d3 100644 --- a/src/app/map/leaflet-map/leaflet-map.component.ts +++ b/src/app/map/leaflet-map/leaflet-map.component.ts @@ -158,7 +158,7 @@ export class LeafletMapComponent implements OnDestroy, AfterViewInit { L.control.layers(baseLayers, null, {position: 'topright'}).addTo(this.map); const previousBaseLayer = baseLayers[this.selectedBaseLayerName]; - const defaultBaseLayer = baseLayers[Object.keys(baseLayers)[0]]; + const defaultBaseLayer = Object.values(baseLayers)[0]; const selectedBaseLayer = previousBaseLayer ?? defaultBaseLayer; selectedBaseLayer.addTo(this.map);