diff --git a/cmd/webserver.go b/cmd/webserver.go index 31b4484a..2366942f 100644 --- a/cmd/webserver.go +++ b/cmd/webserver.go @@ -160,7 +160,8 @@ func startWebServer(c *cli.Context) error { config.MapProvider == settings.OpenTopoMapProvider || config.MapProvider == settings.OPNVKarteMapProvider || config.MapProvider == settings.CyclOSMMapProvider || - config.MapProvider == settings.TomTomMapProvider { + config.MapProvider == settings.TomTomMapProvider || + config.MapProvider == settings.CustomProvider { proxyRoute.GET("/map/tile/:zoomLevel/:coordinateX/:fileName", bindProxy(api.MapImages.MapTileImageProxyHandler)) } } diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index 5b698e79..e306545b 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -157,10 +157,11 @@ enable_export = true # "googlemap": https://map.google.com # "baidumap": https://map.baidu.com # "amap": https://amap.com +# "custom": custom map tile server url # 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", "cyclosm" or "tomtom" +# Set to true to use the ezbookkeeping server to proxy map data requests, for "openstreetmap", "openstreetmap_humanitarian", "opentopomap", "opnvkarte", "cyclosm", "tomtom" or "custom" map_data_fetch_proxy = false # For "tomtom" only, TomTom map API key, please visit https://developer.tomtom.com/how-to-get-tomtom-api-key @@ -188,6 +189,18 @@ amap_application_secret = # For "amap" only, Amap JavaScript API external proxy url, this setting must be provided when "amap_security_verification_method" is set to "external_proxy" amap_api_external_proxy_url = +# For "custom" only, the custom map tile server url, supports {x}, {y} (coordinates) and {z} (zoom level) placeholders, like "https://tile.openstreetmap.org/{z}/{x}/{y}.png" +custom_map_tile_server_url = + +# For "custom" only, the min zoom level (0 - 255) for custom map tile server, default is 1 +custom_map_tile_server_min_zoom_level = 1 + +# For "custom" only, the max zoom level (0 - 255) for custom map tile server, default is 18 +custom_map_tile_server_max_zoom_level = 18 + +# For "custom" only, the default zoom level (0 - 255) for custom map tile server, default is 14 +custom_map_tile_server_default_zoom_level = 14 + [exchange_rates] # Exchange rates data source, supports the following types: # "euro_central_bank" diff --git a/pkg/api/map_image_proxies.go b/pkg/api/map_image_proxies.go index 6b1795bd..c608a8eb 100644 --- a/pkg/api/map_image_proxies.go +++ b/pkg/api/map_image_proxies.go @@ -50,6 +50,8 @@ func (p *MapImageProxy) MapTileImageProxyHandler(c *core.Context) (*httputil.Rev if language != "" { targetUrl = targetUrl + "&language=" + language } + } else if mapProvider == settings.CustomProvider { + targetUrl = settings.Container.Current.CustomMapTileServerUrl } else { return nil, errs.ErrParameterInvalid } diff --git a/pkg/middlewares/server_settings_cookie.go b/pkg/middlewares/server_settings_cookie.go index 6eba2745..b17f4592 100644 --- a/pkg/middlewares/server_settings_cookie.go +++ b/pkg/middlewares/server_settings_cookie.go @@ -29,10 +29,19 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc { config.MapProvider == settings.OpenTopoMapProvider || config.MapProvider == settings.OPNVKarteMapProvider || config.MapProvider == settings.CyclOSMMapProvider || - config.MapProvider == settings.TomTomMapProvider) { + config.MapProvider == settings.TomTomMapProvider || + config.MapProvider == settings.CustomProvider) { settingsArr = append(settingsArr, buildBooleanSetting("mp", config.EnableMapDataFetchProxy)) } + if config.MapProvider == settings.CustomProvider { + settingsArr = append(settingsArr, buildStringSetting("cmzl", fmt.Sprintf("%d-%d-%d", config.CustomMapTileServerMinZoomLevel, config.CustomMapTileServerMaxZoomLevel, config.CustomMapTileServerDefaultZoomLevel))) + + if !config.EnableMapDataFetchProxy { + settingsArr = append(settingsArr, buildEncodedStringSetting("cmsu", config.CustomMapTileServerUrl)) + } + } + if config.MapProvider == settings.TomTomMapProvider && config.TomTomMapAPIKey != "" && !config.EnableMapDataFetchProxy { settingsArr = append(settingsArr, buildEncodedStringSetting("tmak", config.TomTomMapAPIKey)) } diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index 5caefdc6..6c6c6508 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -78,6 +78,7 @@ const ( TomTomMapProvider string = "tomtom" BaiduMapProvider string = "baidumap" AmapProvider string = "amap" + CustomProvider string = "custom" ) // Amap security verification method @@ -219,15 +220,19 @@ type Config struct { EnableDataExport bool // Map - MapProvider string - TomTomMapAPIKey string - GoogleMapAPIKey string - BaiduMapAK string - AmapApplicationKey string - AmapSecurityVerificationMethod string - AmapApplicationSecret string - AmapApiExternalProxyUrl string - EnableMapDataFetchProxy bool + MapProvider string + TomTomMapAPIKey string + GoogleMapAPIKey string + BaiduMapAK string + AmapApplicationKey string + AmapSecurityVerificationMethod string + AmapApplicationSecret string + AmapApiExternalProxyUrl string + CustomMapTileServerUrl string + CustomMapTileServerMinZoomLevel uint8 + CustomMapTileServerMaxZoomLevel uint8 + CustomMapTileServerDefaultZoomLevel uint8 + EnableMapDataFetchProxy bool // Exchange Rates ExchangeRatesDataSource string @@ -544,6 +549,8 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.MapProvider = BaiduMapProvider } else if mapProvider == AmapProvider { config.MapProvider = AmapProvider + } else if mapProvider == CustomProvider { + config.MapProvider = CustomProvider } else { return errs.ErrInvalidMapProvider } @@ -569,6 +576,11 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.AmapApplicationSecret = getConfigItemStringValue(configFile, sectionName, "amap_application_secret") config.AmapApiExternalProxyUrl = getConfigItemStringValue(configFile, sectionName, "amap_api_external_proxy_url") + config.CustomMapTileServerUrl = getConfigItemStringValue(configFile, sectionName, "custom_map_tile_server_url") + config.CustomMapTileServerMinZoomLevel = getConfigItemUint8Value(configFile, sectionName, "custom_map_tile_server_min_zoom_level", 1) + config.CustomMapTileServerMaxZoomLevel = getConfigItemUint8Value(configFile, sectionName, "custom_map_tile_server_max_zoom_level", 18) + config.CustomMapTileServerDefaultZoomLevel = getConfigItemUint8Value(configFile, sectionName, "custom_map_tile_server_default_zoom_level", 14) + return nil } func loadExchangeRatesConfiguration(config *Config, configFile *ini.File, sectionName string) error { diff --git a/src/lib/map/index.js b/src/lib/map/index.js index e1b70272..42a578c3 100644 --- a/src/lib/map/index.js +++ b/src/lib/map/index.js @@ -40,7 +40,7 @@ import { } from './amap.js'; export function loadMapAssets(language) { - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { return loadLeafletMapAssets(language); } else if (getMapProvider() === 'googlemap') { return loadGoogleMapAssets(language); @@ -52,7 +52,7 @@ export function loadMapAssets(language) { } export function createMapHolder() { - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { return createLeafletMapHolder(getMapProvider()); } else if (getMapProvider() === 'googlemap') { return createGoogleMapHolder(getMapProvider()); @@ -70,7 +70,7 @@ export function initMapInstance(mapHolder, mapContainer, options) { return; } - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { createLeafletMapInstance(mapHolder, mapContainer, options); } else if (mapHolder.mapProvider === 'googlemap') { createGoogleMapInstance(mapHolder, mapContainer, options); @@ -86,7 +86,7 @@ export function setMapCenterTo(mapHolder, center, zoomLevel) { return; } - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { setLeafletMapCenterTo(mapHolder, center, zoomLevel); } else if (mapHolder.mapProvider === 'googlemap') { setGoogleMapCenterTo(mapHolder, center, zoomLevel); @@ -102,7 +102,7 @@ export function setMapCenterMarker(mapHolder, position) { return; } - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { setLeafletMapCenterMaker(mapHolder, position); } else if (mapHolder.mapProvider === 'googlemap') { setGoogleMapCenterMaker(mapHolder, position); @@ -118,7 +118,7 @@ export function removeMapCenterMarker(mapHolder) { return; } - if (mapConstants.leafletTileSources[getMapProvider()]) { + if (mapConstants.leafletTileSources[getMapProvider()] || getMapProvider() === 'custom') { removeLeafletMapCenterMaker(mapHolder); } else if (mapHolder.mapProvider === 'googlemap') { removeGoogleMapCenterMaker(mapHolder); diff --git a/src/lib/map/leaflet.js b/src/lib/map/leaflet.js index 580e5735..090d760a 100644 --- a/src/lib/map/leaflet.js +++ b/src/lib/map/leaflet.js @@ -1,5 +1,12 @@ import mapConstants from '@/consts/map.js'; -import { isMapDataFetchProxyEnabled, getTomTomMapAPIKey } from '@/lib/server_settings.js'; +import { + isMapDataFetchProxyEnabled, + getCustomMapTileServerUrl, + getCustomMapMinZoomLevel, + getCustomMapMaxZoomLevel, + getCustomMapDefaultZoomLevel, + getTomTomMapAPIKey +} from '@/lib/server_settings.js'; import services from '@/lib/services.js'; const leafletHolder = { @@ -16,7 +23,7 @@ export function loadLeafletMapAssets() { export function createLeafletMapHolder(mapProvider) { const mapTileSource = mapConstants.leafletTileSources[mapProvider]; - if (!mapTileSource) { + if (mapProvider !== 'custom' && !mapTileSource) { return null; } @@ -24,8 +31,8 @@ export function createLeafletMapHolder(mapProvider) { mapProvider: mapProvider, dependencyLoaded: !!leafletHolder.leaflet, inited: false, - defaultZoomLevel: mapTileSource.defaultZoomLevel, - minZoomLevel: mapTileSource.minZoom, + defaultZoomLevel: mapProvider !== 'custom' ? mapTileSource.defaultZoomLevel : getCustomMapDefaultZoomLevel(), + minZoomLevel: mapProvider !== 'custom' ? mapTileSource.minZoom : getCustomMapMinZoomLevel(), leafletInstance: null, leafletTileLayer: null, leafletZoomControl: null, @@ -46,7 +53,13 @@ export function createLeafletMapInstance(mapHolder, mapContainer, options) { attributionControl: false, zoomControl: false }); - let mapTileSource = Object.assign({}, mapConstants.leafletTileSources[mapHolder.mapProvider]); + let mapTileSource = null; + + if (mapHolder.mapProvider !== 'custom') { + mapTileSource = Object.assign({}, mapConstants.leafletTileSources[mapHolder.mapProvider]); + } else { + mapTileSource = createCustomMapSource(); + } if (isMapDataFetchProxyEnabled()) { mapTileSource.tileUrlFormat = services.generateMapProxyTileImageUrl(mapHolder.mapProvider, options.language); @@ -137,3 +150,13 @@ export function removeLeafletMapCenterMaker(mapHolder) { mapHolder.leafletCenterMarker.remove(); mapHolder.leafletCenterMarker = null; } + +function createCustomMapSource() { + return { + tileUrlFormat: getCustomMapTileServerUrl(), + tileUrlSubDomains: '', + minZoom: getCustomMapMinZoomLevel(), + maxZoom: getCustomMapMaxZoomLevel(), + defaultZoomLevel: getCustomMapDefaultZoomLevel() + }; +} diff --git a/src/lib/server_settings.js b/src/lib/server_settings.js index 030f4312..1a327b7e 100644 --- a/src/lib/server_settings.js +++ b/src/lib/server_settings.js @@ -53,6 +53,25 @@ export function isMapDataFetchProxyEnabled() { return getServerSetting('mp') === '1'; } +export function getCustomMapTileServerUrl() { + return getServerDecodedSetting('cmsu'); +} + +export function getCustomMapMinZoomLevel() { + const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-'); + return (zoomLevelSettings && zoomLevelSettings[0]) ? parseInt(zoomLevelSettings[0]) : 1; +} + +export function getCustomMapMaxZoomLevel() { + const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-'); + return (zoomLevelSettings && zoomLevelSettings[1]) ? parseInt(zoomLevelSettings[1]) : 18; +} + +export function getCustomMapDefaultZoomLevel() { + const zoomLevelSettings = (getServerSetting('cmzl') || '').split('-'); + return (zoomLevelSettings && zoomLevelSettings[2]) ? parseInt(zoomLevelSettings[2]) : 14; +} + export function getTomTomMapAPIKey() { return getServerDecodedSetting('tmak'); }