From 782e3a85f90beb1e080f6614436ba3cbc2efe899 Mon Sep 17 00:00:00 2001 From: MaysWind Date: Sat, 17 Jun 2023 17:48:39 +0800 Subject: [PATCH] support baidu map --- conf/ezbookkeeping.ini | 5 +- pkg/middlewares/server_settings_cookie.go | 1 + pkg/settings/setting.go | 5 + src/MobileApp.vue | 2 +- src/components/mobile/MapSheet.vue | 2 +- src/consts/api.js | 4 +- src/lib/map/baidumap.js | 116 ++++++++++++++++++++++ src/lib/map/index.js | 85 ++++++++++++++++ src/lib/{map.js => map/openstreetmap.js} | 97 +++++------------- src/lib/misc.js | 68 +++++++++++++ src/lib/services.js | 3 + src/lib/settings.js | 1 + 12 files changed, 312 insertions(+), 77 deletions(-) create mode 100644 src/lib/map/baidumap.js create mode 100644 src/lib/map/index.js rename src/lib/{map.js => map/openstreetmap.js} (53%) diff --git a/conf/ezbookkeeping.ini b/conf/ezbookkeeping.ini index cf8f9e4c..d60f4867 100644 --- a/conf/ezbookkeeping.ini +++ b/conf/ezbookkeeping.ini @@ -111,12 +111,15 @@ enable_register = true enable_export = true [map] -# Map provider, supports `openstreetmap` +# Map provider, supports "openstreetmap", "baidumap". 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" map_data_fetch_proxy = false +# For "baidumap" only, Baidu map javascript api application key, please visit https://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/getkey for more information +baidu_map_ak = + [exchange_rates] # Exchange rates data source, supports the following types: # "euro_central_bank" diff --git a/pkg/middlewares/server_settings_cookie.go b/pkg/middlewares/server_settings_cookie.go index 61582533..a61d18c5 100644 --- a/pkg/middlewares/server_settings_cookie.go +++ b/pkg/middlewares/server_settings_cookie.go @@ -18,6 +18,7 @@ func ServerSettingsCookie(config *settings.Config) core.MiddlewareHandlerFunc { buildBooleanSetting("e", config.EnableDataExport), buildStringSetting("m", config.MapProvider), buildBooleanSetting("mp", config.EnableMapDataFetchProxy), + buildStringSetting("bmak", config.BaiduMapAK), } bundledSettings := strings.Join(settingsArr, "_") diff --git a/pkg/settings/setting.go b/pkg/settings/setting.go index dc42f449..e1bd87a2 100644 --- a/pkg/settings/setting.go +++ b/pkg/settings/setting.go @@ -65,6 +65,7 @@ const ( // Map provider types const ( OpenStreetMapProvider string = "openstreetmap" + BaiduMapProvider string = "baidumap" ) // Exchange rates data source types @@ -176,6 +177,7 @@ type Config struct { // Map MapProvider string + BaiduMapAK string EnableMapDataFetchProxy bool // Exchange Rates @@ -436,11 +438,14 @@ func loadMapConfiguration(config *Config, configFile *ini.File, sectionName stri config.MapProvider = "" } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == OpenStreetMapProvider { config.MapProvider = OpenStreetMapProvider + } else if getConfigItemStringValue(configFile, sectionName, "map_provider") == BaiduMapProvider { + config.MapProvider = BaiduMapProvider } else { return errs.ErrInvalidMapProvider } config.EnableMapDataFetchProxy = getConfigItemBoolValue(configFile, sectionName, "map_data_fetch_proxy", false) + config.BaiduMapAK = getConfigItemStringValue(configFile, sectionName, "baidu_map_ak") return nil } diff --git a/src/MobileApp.vue b/src/MobileApp.vue index 8a8c1639..a4d34bdb 100644 --- a/src/MobileApp.vue +++ b/src/MobileApp.vue @@ -13,7 +13,7 @@ import { mapStores } from 'pinia'; import { useTokensStore } from '@/stores/token.js'; import { useExchangeRatesStore } from '@/stores/exchangeRates.js'; -import { loadMapAssets } from '@/lib/map.js'; +import { loadMapAssets } from '@/lib/map/index.js'; import { isModalShowing, setAppFontSize } from '@/lib/ui.mobile.js'; export default { diff --git a/src/components/mobile/MapSheet.vue b/src/components/mobile/MapSheet.vue index 51e79b66..94be5ba8 100644 --- a/src/components/mobile/MapSheet.vue +++ b/src/components/mobile/MapSheet.vue @@ -32,7 +32,7 @@ import { setMapCenterTo, setMapCenterMarker, removeMapCenterMarker -} from '@/lib/map.js'; +} from '@/lib/map/index.js'; export default { props: [ diff --git a/src/consts/api.js b/src/consts/api.js index f8b7bb7d..93e0039b 100644 --- a/src/consts/api.js +++ b/src/consts/api.js @@ -1,7 +1,9 @@ const baseApiUrlPath = '/api'; const baseProxyUrlPath = '/proxy'; +const baiduMapJavascriptUrl = 'https://api.map.baidu.com/api?v=3.0'; export default { baseApiUrlPath: baseApiUrlPath, - baseProxyUrlPath: baseProxyUrlPath + baseProxyUrlPath: baseProxyUrlPath, + baiduMapJavascriptUrl: baiduMapJavascriptUrl } diff --git a/src/lib/map/baidumap.js b/src/lib/map/baidumap.js new file mode 100644 index 00000000..339047af --- /dev/null +++ b/src/lib/map/baidumap.js @@ -0,0 +1,116 @@ +import { asyncLoadAssets } from "@/lib/misc.js"; +import services from "@/lib/services.js"; +import logger from '@/lib/logger.js'; + +const baiduMapHolder = { + BMap: null, + BMAP_NAVIGATION_CONTROL_ZOOM: window.BMAP_NAVIGATION_CONTROL_ZOOM || 3, + BMAP_ANCHOR_TOP_LEFT: window.BMAP_ANCHOR_TOP_LEFT || 0, + COORDINATES_WGS84: window.COORDINATES_WGS84 || 1, + COORDINATES_BD09: window.COORDINATES_BD09 || 5 +}; + +export function loadBaiduMapAssets() { + if (baiduMapHolder.BMap) { + return; + } + + if (!window.onBMapCallback) { + window.onBMapCallback = () => { + baiduMapHolder.BMap = window.BMap; + }; + } + + return asyncLoadAssets('js', services.generateBaiduMapJavascriptUrl('onBMapCallback')); +} + +export function createBaiduMapHolder() { + return { + mapProvider: 'baidumap', + dependencyLoaded: !!baiduMapHolder.BMap, + inited: false, + defaultZoomLevel: 15, + minZoomLevel: 1, + baiduMapInstance: null, + baiduMapConverter: null, + baiduMapNavigationControl: null, + baiduMapCenterMarker: null + }; +} + +export function createBaiduMapInstance(mapHolder, mapContainer) { + if (!baiduMapHolder.BMap) { + return null; + } + + const BMap = baiduMapHolder.BMap; + const baiduMapInstance = new BMap.Map(mapContainer, { + maxZoom: 19 + }); + baiduMapInstance.enableScrollWheelZoom(); + + const baiduMapNavigationControl = new BMap.NavigationControl({ + type: baiduMapHolder.BMAP_NAVIGATION_CONTROL_ZOOM, + anchor: baiduMapHolder.BMAP_ANCHOR_TOP_LEFT + }); + baiduMapInstance.addControl(baiduMapNavigationControl); + + mapHolder.baiduMapInstance = baiduMapInstance; + mapHolder.baiduMapConverter = new BMap.Convertor(); + mapHolder.inited = true; +} + +export function setBaiduMapCenterTo(mapHolder, center, zoomLevel) { + if (!baiduMapHolder.BMap || !mapHolder.baiduMapInstance) { + return; + } + + const BMap = baiduMapHolder.BMap; + const centerPoint = new BMap.Point(center.longitude, center.latitude); + + if (mapHolder.baiduMapConverter) { + mapHolder.baiduMapConverter.translate([ centerPoint ], baiduMapHolder.COORDINATES_WGS84, baiduMapHolder.COORDINATES_BD09, data => { + if (data.status !== 0) { + logger.warn('baidu map geo position convert failed'); + } + + const actualPoint = (data.status === 0 ? data.points[0] : centerPoint); + mapHolder.baiduMapInstance.centerAndZoom(actualPoint, zoomLevel); + }); + } else { + mapHolder.baiduMapInstance.centerAndZoom(centerPoint, zoomLevel); + } +} + +export function setBaiduMapCenterMaker(mapHolder, position) { + if (!baiduMapHolder.BMap || !mapHolder.baiduMapInstance) { + return; + } + + const BMap = baiduMapHolder.BMap; + const markerPoint = new BMap.Point(position.longitude, position.latitude); + + mapHolder.baiduMapConverter.translate([ markerPoint ], baiduMapHolder.COORDINATES_WGS84, baiduMapHolder.COORDINATES_BD09, data => { + if (data.status !== 0) { + logger.warn('baidu map geo position convert failed'); + } + + const actualPoint = (data.status === 0 ? data.points[0] : markerPoint); + + if (!mapHolder.baiduMapCenterMarker) { + mapHolder.baiduMapCenterMarker = new BMap.Marker(actualPoint); + mapHolder.baiduMapInstance.addOverlay(mapHolder.baiduMapCenterMarker); + } else { + mapHolder.baiduMapCenterMarker.setPosition(actualPoint); + } + }); +} + +export function removeBaiduMapCenterMaker(mapHolder) { + if (!mapHolder.baiduMapInstance || !mapHolder.baiduMapCenterMarker) { + return; + } + + mapHolder.baiduMapInstance.removeOverlay(mapHolder.baiduMapCenterMarker); + mapHolder.baiduMapCenterMarker = null; +} diff --git a/src/lib/map/index.js b/src/lib/map/index.js new file mode 100644 index 00000000..d04ff5f5 --- /dev/null +++ b/src/lib/map/index.js @@ -0,0 +1,85 @@ +import settings from "@/lib/settings.js"; + +import { + loadLeafletMapAssets, + createLeafletMapHolder, + createLeafletMapInstance, + setLeafletMapCenterTo, + setLeafletMapCenterMaker, + removeLeafletMapCenterMaker +} from './openstreetmap.js'; + +import { + loadBaiduMapAssets, + createBaiduMapHolder, + createBaiduMapInstance, + setBaiduMapCenterTo, + setBaiduMapCenterMaker, + removeBaiduMapCenterMaker +} from './baidumap.js'; + +export function loadMapAssets() { + if (settings.getMapProvider() === 'openstreetmap') { + return loadLeafletMapAssets(); + } else if (settings.getMapProvider() === 'baidumap') { + return loadBaiduMapAssets(); + } +} + +export function createMapHolder() { + if (settings.getMapProvider() === 'openstreetmap') { + return createLeafletMapHolder(); + } else if (settings.getMapProvider() === 'baidumap') { + return createBaiduMapHolder(); + } else { + return null; + } +} + +export function initMapInstance(mapHolder, mapContainer, options) { + if (!mapHolder) { + return; + } + + if (mapHolder.mapProvider === 'openstreetmap') { + createLeafletMapInstance(mapHolder, mapContainer, options); + } else if (mapHolder.mapProvider === 'baidumap') { + createBaiduMapInstance(mapHolder, mapContainer, options); + } +} + +export function setMapCenterTo(mapHolder, center, zoomLevel) { + if (!mapHolder) { + return; + } + + if (mapHolder.mapProvider === 'openstreetmap') { + setLeafletMapCenterTo(mapHolder, center, zoomLevel); + } else if (mapHolder.mapProvider === 'baidumap') { + setBaiduMapCenterTo(mapHolder, center, zoomLevel); + } +} + +export function setMapCenterMarker(mapHolder, position) { + if (!mapHolder) { + return; + } + + if (mapHolder.mapProvider === 'openstreetmap') { + setLeafletMapCenterMaker(mapHolder, position); + } else if (mapHolder.mapProvider === 'baidumap') { + setBaiduMapCenterMaker(mapHolder, position); + } +} + +export function removeMapCenterMarker(mapHolder) { + if (!mapHolder) { + return; + } + + if (mapHolder.mapProvider === 'openstreetmap') { + removeLeafletMapCenterMaker(mapHolder); + } else if (mapHolder.mapProvider === 'baidumap') { + removeBaiduMapCenterMaker(mapHolder); + } +} diff --git a/src/lib/map.js b/src/lib/map/openstreetmap.js similarity index 53% rename from src/lib/map.js rename to src/lib/map/openstreetmap.js index 0abe31ab..0164675b 100644 --- a/src/lib/map.js +++ b/src/lib/map/openstreetmap.js @@ -1,18 +1,32 @@ -import services from "./services.js"; -import settings from "./settings.js"; +import services from "@/lib/services.js"; const leafletHolder = { leaflet: null }; -function loadLeafletMapAssets() { +export function loadLeafletMapAssets() { return Promise.all([ import('leaflet/dist/leaflet.css'), import('leaflet/dist/leaflet-src.esm.js').then(leaflet => leafletHolder.leaflet = leaflet) ]); } -function createLeafletMapInstance(mapHolder, mapContainer, options) { +export function createLeafletMapHolder() { + return { + mapProvider: 'openstreetmap', + dependencyLoaded: !!leafletHolder.leaflet, + inited: false, + defaultZoomLevel: 14, + minZoomLevel: 1, + leafletInstance: null, + leafletTileLayer: null, + leafletZoomControl: null, + leafletAttribution: null, + leafletCenterMarker: null + }; +} + +export function createLeafletMapInstance(mapHolder, mapContainer, options) { if (!leafletHolder.leaflet) { return null; } @@ -50,7 +64,7 @@ function createLeafletMapInstance(mapHolder, mapContainer, options) { mapHolder.inited = true; } -function setLeafletMapCenterTo(mapHolder, center, zoomLevel) { +export function setLeafletMapCenterTo(mapHolder, center, zoomLevel) { if (!mapHolder.leafletInstance) { return; } @@ -58,7 +72,7 @@ function setLeafletMapCenterTo(mapHolder, center, zoomLevel) { mapHolder.leafletInstance.setView([ center.latitude, center.longitude ], zoomLevel); } -function setLeafletMapCenterMaker(mapHolder, position) { +export function setLeafletMapCenterMaker(mapHolder, position) { if (!leafletHolder.leaflet || !mapHolder.leafletInstance) { return; } @@ -83,74 +97,11 @@ function setLeafletMapCenterMaker(mapHolder, position) { } } -function removeLeafletMapCenterMaker(mapHolder) { - if (!mapHolder.leafletInstance || mapHolder.leafletCenterMarker) { - mapHolder.leafletCenterMarker.remove(); - mapHolder.leafletCenterMarker = null; - } -} - -export function loadMapAssets() { - if (settings.getMapProvider() === 'openstreetmap') { - return loadLeafletMapAssets(); - } -} - -export function createMapHolder() { - if (settings.getMapProvider() === 'openstreetmap') { - return { - mapProvider: 'openstreetmap', - dependencyLoaded: !!leafletHolder.leaflet, - inited: false, - defaultZoomLevel: 14, - minZoomLevel: 1, - leafletInstance: null, - leafletTileLayer: null, - leafletZoomControl: null, - leafletAttribution: null, - leafletCenterMarker: null - } - } else { - return null; - } -} - -export function initMapInstance(mapHolder, mapContainer, options) { - if (!mapHolder) { +export function removeLeafletMapCenterMaker(mapHolder) { + if (!mapHolder.leafletInstance || !mapHolder.leafletCenterMarker) { return; } - if (mapHolder.mapProvider === 'openstreetmap') { - createLeafletMapInstance(mapHolder, mapContainer, options); - } -} - -export function setMapCenterTo(mapHolder, center, zoomLevel) { - if (!mapHolder) { - return; - } - - if (mapHolder.mapProvider === 'openstreetmap') { - setLeafletMapCenterTo(mapHolder, center, zoomLevel); - } -} - -export function setMapCenterMarker(mapHolder, position) { - if (!mapHolder) { - return; - } - - if (mapHolder.mapProvider === 'openstreetmap') { - setLeafletMapCenterMaker(mapHolder, position); - } -} - -export function removeMapCenterMarker(mapHolder) { - if (!mapHolder) { - return; - } - - if (mapHolder.mapProvider === 'openstreetmap') { - removeLeafletMapCenterMaker(mapHolder); - } + mapHolder.leafletCenterMarker.remove(); + mapHolder.leafletCenterMarker = null; } diff --git a/src/lib/misc.js b/src/lib/misc.js index 14659ce9..ea1076f8 100644 --- a/src/lib/misc.js +++ b/src/lib/misc.js @@ -2,6 +2,74 @@ import Clipboard from 'clipboard'; import CryptoJS from 'crypto-js'; import uaParser from 'ua-parser-js'; +export function asyncLoadAssets(type, assetUrl) { + return new Promise(function (resolve, reject) { + let addElement = false; + let el = null; + + if (type === 'js') { + el = document.querySelector('script[src="' + assetUrl + '"]'); + } else if (type === 'css') { + el = document.querySelector('link[href="' + assetUrl + '"]'); + } else { + reject({ + type: type, + assetUrl: assetUrl, + error: 'notsupport' + }); + return; + } + + if (!el) { + if (type === 'js') { + el = document.createElement('script'); + el.setAttribute('type', 'text/javascript'); + el.setAttribute('async', 'true'); + el.setAttribute('src', assetUrl); + } else if (type === 'css') { + el = document.createElement('link'); + el.setAttribute('rel', 'stylesheet'); + el.setAttribute('type', 'text/css'); + el.setAttribute('href', assetUrl); + } + + addElement = true; + } else if (el.hasAttribute('data-loaded')) { + resolve({ + type: type, + assetUrl: assetUrl + }); + return; + } + + el.addEventListener('load', () => { + el.setAttribute('data-loaded', true); + resolve({ + type: type, + assetUrl: assetUrl + }); + }); + el.addEventListener('error', () => { + reject({ + type: type, + assetUrl: assetUrl, + error: 'error' + }); + }); + el.addEventListener('abort', () => { + reject({ + type: type, + assetUrl: assetUrl, + error: 'abort' + }); + }); + + if (addElement) { + document.head.appendChild(el); + } + }); +} + export function generateRandomString() { const baseString = 'ebk_' + Math.round(new Date().getTime() / 1000) + '_' + Math.random(); return CryptoJS.SHA256(baseString).toString(); diff --git a/src/lib/services.js b/src/lib/services.js index 340b081e..467e8eca 100644 --- a/src/lib/services.js +++ b/src/lib/services.js @@ -411,4 +411,7 @@ export default { }; } }, + generateBaiduMapJavascriptUrl: (callbackFnName) => { + return `${api.baiduMapJavascriptUrl}&ak=${settings.getBaiduMapAK()}&callback=${callbackFnName}`; + } }; diff --git a/src/lib/settings.js b/src/lib/settings.js index 4d28c78e..917ea3ab 100644 --- a/src/lib/settings.js +++ b/src/lib/settings.js @@ -169,5 +169,6 @@ export default { isDataExportingEnabled: () => getServerSetting('e') === '1', getMapProvider: () => getServerSetting('m'), isMapDataFetchProxyEnabled: () => getServerSetting('mp') === '1', + getBaiduMapAK: () => getServerSetting('bmak'), clearSettings: clearSettings };