diff --git a/cmd/webserver.go b/cmd/webserver.go index fc4d4975..56840bbf 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -150,7 +150,8 @@ func startWebServer(c *cli.Context) error { config.MapProvider == settings.OpenStreetMapHumanitarianStyleProvider || config.MapProvider == settings.OpenTopoMapProvider || config.MapProvider == settings.OPNVKarteMapProvider || - config.MapProvider == settings.CyclOSMMapProvider { + config.MapProvider == settings.CyclOSMMapProvider || + config.MapProvider == settings.TomTomMapProvider { proxyRoute.GET("/map/tile/:zoomLevel/:coordinateX/:fileName", bindProxy(api.MapImages.MapTileImageProxyHandler)) } } diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index 054b7a0e..ec91c24b 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -117,15 +117,19 @@ enable_export = true # "opentopomap": https://opentopomap.org # "opnvkarte": https://publictransportmap.org # "cyclosm": https://www.cyclosm.org +# "tomtom": https://www.tomtom.com # "googlemap": https://map.google.com # "baidumap": https://map.baidu.com # "amap": https://amap.com # Leave blank if you want to disable map map_provider = openstreetmap -# Set to true to use the ezbookkeeping server to proxy map data requests, for "openstreetmap", "openstreetmap_humanitarian", "opentopomap", "opnvkarte" or "cyclosm" +# Set to true to use the ezbookkeeping server to proxy map data requests, for "openstreetmap", "openstreetmap_humanitarian", "opentopomap", "opnvkarte", "cyclosm" or "tomtom" map_data_fetch_proxy = false +# For "tomtom" only, TomTom map API key, please visit https://developer.tomtom.com/how-to-get-tomtom-api-key +tomtom_map_api_key = + # For "googlemap" only, Google map JavaScript API key, please visit https://developers.google.com/maps/get-started for more information google_map_api_key = diff --git a/pkg/api/map_image_proxies.go b/pkg/api/map_image_proxies.go index 51b7513f..6b1795bd 100644 --- a/pkg/api/map_image_proxies.go +++ b/pkg/api/map_image_proxies.go @@ -17,6 +17,7 @@ const openStreetMapHumanitarianStyleTileImageUrlFormat = "https://a.tile.openstr const openTopoMapTileImageUrlFormat = "https://tile.opentopomap.org/%s/%s/%s" // https://tile.opentopomap.org/{z}/{x}/{y}.png const opnvKarteMapTileImageUrlFormat = "https://tileserver.memomaps.de/tilegen/%s/%s/%s" // https://tileserver.memomaps.de/tilegen/{z}/{x}/{y}.png const cyclOSMMapTileImageUrlFormat = "https://a.tile-cyclosm.openstreetmap.fr/cyclosm/%s/%s/%s" // https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png +const tomtomMapTileImageUrlFormat = "https://api.tomtom.com/map/1/tile/basic/main/%s/%s/%s" // https://api.tomtom.com/map/{versionNumber}/tile/{layer}/{style}/{z}/{x}/{y}.png?key={key}&language={language} // MapImageProxy represents map image proxy type MapImageProxy struct { @@ -42,6 +43,13 @@ func (p *MapImageProxy) MapTileImageProxyHandler(c *core.Context) (*httputil.Rev targetUrl = opnvKarteMapTileImageUrlFormat } else if mapProvider == settings.CyclOSMMapProvider { targetUrl = cyclOSMMapTileImageUrlFormat + } else if mapProvider == settings.TomTomMapProvider { + targetUrl = tomtomMapTileImageUrlFormat + "?key=" + settings.Container.Current.TomTomMapAPIKey + language := c.Query("language") + + if language != "" { + targetUrl = targetUrl + "&language=" + language + } } else { return nil, errs.ErrParameterInvalid } diff --git a/pkg/middlewares/server_settings_cookie.go b/pkg/middlewares/server_settings_cookie.go index 4824dca3..f165db65 100644 --- a/pkg/middlewares/server_settings_cookie.go +++ b/pkg/middlewares/server_settings_cookie.go @@ -26,10 +26,15 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc { config.MapProvider == settings.OpenStreetMapHumanitarianStyleProvider || config.MapProvider == settings.OpenTopoMapProvider || config.MapProvider == settings.OPNVKarteMapProvider || - config.MapProvider == settings.CyclOSMMapProvider) { + config.MapProvider == settings.CyclOSMMapProvider || + config.MapProvider == settings.TomTomMapProvider) { settingsArr = append(settingsArr, buildBooleanSetting("mp", config.EnableMapDataFetchProxy)) } + if config.MapProvider == settings.TomTomMapProvider && config.TomTomMapAPIKey != "" && !config.EnableMapDataFetchProxy { + settingsArr = append(settingsArr, buildEncodedStringSetting("tmak", config.TomTomMapAPIKey)) + } + if config.MapProvider == settings.GoogleMapProvider && config.GoogleMapAPIKey != "" { settingsArr = append(settingsArr, buildEncodedStringSetting("gmak", config.GoogleMapAPIKey)) } diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index 4b028af8..3c7fea3d 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -70,6 +70,7 @@ const ( OPNVKarteMapProvider string = "opnvkarte" CyclOSMMapProvider string = "cyclosm" GoogleMapProvider string = "googlemap" + TomTomMapProvider string = "tomtom" BaiduMapProvider string = "baidumap" AmapProvider string = "amap" ) @@ -190,6 +191,7 @@ type Config struct { // Map MapProvider string + TomTomMapAPIKey string GoogleMapAPIKey string BaiduMapAK string AmapApplicationKey string @@ -466,6 +468,8 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.MapProvider = CyclOSMMapProvider } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == GoogleMapProvider { config.MapProvider = GoogleMapProvider + } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == TomTomMapProvider { + config.MapProvider = TomTomMapProvider } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == BaiduMapProvider { config.MapProvider = BaiduMapProvider } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == AmapProvider { @@ -475,6 +479,7 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri } config.EnableMapDataFetchProxy = getConfigItemBoolValue(configFile, sectionName, "map_data_fetch_proxy", false) + config.TomTomMapAPIKey = getConfigItemStringValue(configFile, sectionName, "tomtom_map_api_key") config.GoogleMapAPIKey = getConfigItemStringValue(configFile, sectionName, "google_map_api_key") config.BaiduMapAK = getConfigItemStringValue(configFile, sectionName, "baidu_map_ak") config.AmapApplicationKey = getConfigItemStringValue(configFile, sectionName, "amap_application_key") diff --git a/src/components/mobile/MapSheet.vue b/src/components/mobile/MapSheet.vue index b598a7fe..295be4f9 100644 --- a/src/components/mobile/MapSheet.vue +++ b/src/components/mobile/MapSheet.vue @@ -104,7 +104,10 @@ export default { } if (!this.mapHolder.inited) { + const languageInfo = this.$locale.getCurrentLanguageInfo(); + initMapInstance(this.mapHolder, this.$refs.map, { + language: languageInfo ? languageInfo.code : null, initCenter: this.initCenter, zoomLevel: this.zoomLevel, text: { diff --git a/src/consts/map.js b/src/consts/map.js index bbe7656f..3e51e29d 100644 --- a/src/consts/map.js +++ b/src/consts/map.js @@ -38,6 +38,24 @@ const leafletTileSources = { maxZoom: 19, defaultZoomLevel: 14, attribution : 'CyclOSM | Map data: © OpenStreetMap contributors' + }, + 'tomtom': { + tileUrlFormat: 'https://{s}.api.tomtom.com/map/1/tile/basic/main/{z}/{x}/{y}.png', + tileUrlSubDomains: 'abcd', + tileUrlExtraParams: [ + { + paramName: 'key', + paramValueType: 'tomtom_key' + }, + { + paramName: 'language', + paramValueType: 'language' + } + ], + minZoom: 1, + maxZoom: 19, + defaultZoomLevel: 14, + attribution : '© 1992 - 2023 TomTom.' } } diff --git a/src/lib/map/leaflet.js b/src/lib/map/leaflet.js index 42029f3b..8c99420d 100644 --- a/src/lib/map/leaflet.js +++ b/src/lib/map/leaflet.js @@ -46,14 +46,27 @@ export function createLeafletMapInstance(mapHolder, mapContainer, options) { attributionControl: false, zoomControl: false }); - let mapTileSource = mapConstants.leafletTileSources[mapHolder.mapProvider]; + let mapTileSource = Object.assign({}, mapConstants.leafletTileSources[mapHolder.mapProvider]); if (settings.isMapDataFetchProxyEnabled()) { - const mapProxyTileImageUrl = services.generateMapProxyTileImageUrl(mapHolder.mapProvider); - mapTileSource = Object.assign({}, mapTileSource, { - tileUrlFormat: mapProxyTileImageUrl, - tileUrlSubDomains: '' - }); + mapTileSource.tileUrlFormat = services.generateMapProxyTileImageUrl(mapHolder.mapProvider, options.language); + mapTileSource.tileUrlSubDomains = ''; + } else if (mapTileSource.tileUrlExtraParams) { + const params = []; + + for (let i = 0; i < mapTileSource.tileUrlExtraParams.length; i++) { + const param = mapTileSource.tileUrlExtraParams[i]; + + if (param.paramValueType === 'tomtom_key') { + params.push('key=' + settings.getTomTomMapAPIKey()); + } else if (param.paramValueType === 'language' && options.language) { + params.push('language=' + options.language); + } + } + + if (params.length) { + mapTileSource.tileUrlFormat = mapTileSource.tileUrlFormat + '?' + params.join('&'); + } } const tileLayer = leaflet.tileLayer(mapTileSource.tileUrlFormat, { diff --git a/src/lib/services.js b/src/lib/services.js index da5eaa93..9cb519c0 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -396,9 +396,15 @@ export default { ignoreError: !!ignoreError }); }, - generateMapProxyTileImageUrl: (mapProvider) => { + generateMapProxyTileImageUrl: (mapProvider, language) => { const token = userState.getToken(); - return `${api.baseProxyUrlPath}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`; + let url = `${api.baseProxyUrlPath}/map/tile/{z}/{x}/{y}.png?provider=${mapProvider}&token=${token}`; + + if (language) { + url = url + `&language=${language}`; + } + + return url; }, generateGoogleMapJavascriptUrl: (language, callbackFnName) => { if (language) { diff --git a/src/lib/settings.js b/src/lib/settings.js index 8c83410d..f3aa89b5 100644 --- a/src/lib/settings.js +++ b/src/lib/settings.js @@ -181,6 +181,7 @@ export default { isDataExportingEnabled: () => getServerSetting('e') === '1', getMapProvider: () => getServerSetting('m'), isMapDataFetchProxyEnabled: () => getServerSetting('mp') === '1', + getTomTomMapAPIKey: () => getServerDecodedSetting('tmak'), getGoogleMapAPIKey: () => getServerDecodedSetting('gmak'), getBaiduMapAK: () => getServerDecodedSetting('bmak'), getAmapApplicationKey: () => getServerDecodedSetting('amak'),