diff --git a/src/components/map/TileServerChooserButton.tsx b/src/components/map/TileServerChooserButton.tsx
new file mode 100644
index 0000000..89e52bc
--- /dev/null
+++ b/src/components/map/TileServerChooserButton.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+
+import { IonButton, IonIcon } from '@ionic/react';
+import { layersOutline } from 'ionicons/icons';
+const TileServerChooserButton: React.FC<{}> = () => {
+ return (
+
+
+
+ );
+};
+
+export default TileServerChooserButton;
diff --git a/src/components/map/TileServerChooserDialog.tsx b/src/components/map/TileServerChooserDialog.tsx
new file mode 100644
index 0000000..f2eac57
--- /dev/null
+++ b/src/components/map/TileServerChooserDialog.tsx
@@ -0,0 +1,52 @@
+import {
+ IonContent,
+ IonHeader,
+ IonItem,
+ IonLabel,
+ IonList,
+ IonModal,
+ IonRadio,
+ IonRadioGroup,
+ IonTitle,
+} from '@ionic/react';
+import React from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { mapActions, MapState } from '../../store/map';
+import { tileProviders } from './tile';
+
+const TileServerChooserDialog: React.FC<{}> = () => {
+
+ const tileProvider = useSelector(
+ (state: { map: MapState }) => state.map.scope.tileProvider
+ ) as keyof typeof tileProviders;
+
+ const dispatch = useDispatch();
+
+ const changeHandler = (event: any) => {
+ dispatch(mapActions.setTileProvider(event.detail.value));
+ };
+
+ return (
+
+
+ Select your map
+
+
+
+
+ {Object.keys(tileProviders).map((provider) => {
+ return (
+
+ {tileProviders[provider].name}
+
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+export default TileServerChooserDialog;
diff --git a/src/components/map/map.tsx b/src/components/map/map.tsx
index d5ab94e..a748970 100644
--- a/src/components/map/map.tsx
+++ b/src/components/map/map.tsx
@@ -23,6 +23,8 @@ import GpxImport from './gpx-import';
import Gpxes from './gpxes';
import GpxRecord from './gpx-record';
import { initDb } from '../../db';
+import TileServerChooserButton from './TileServerChooserButton';
+import TileServerChooserDialog from './TileServerChooserDialog';
const Map: react.FC<{}> = (props: {}) => {
const dispatch = useDispatch();
@@ -48,6 +50,7 @@ const Map: react.FC<{}> = (props: {}) => {
<>
+
@@ -62,6 +65,7 @@ const Map: react.FC<{}> = (props: {}) => {
+
diff --git a/src/components/map/tile.tsx b/src/components/map/tile.tsx
index 75e0c57..1a2666f 100644
--- a/src/components/map/tile.tsx
+++ b/src/components/map/tile.tsx
@@ -1,7 +1,103 @@
import React from 'react';
+import { useSelector } from 'react-redux';
+import { MapState } from '../../store/map';
-const tileProvider = (zoom: number, x: number, y: number) =>
- 'https://tile.openstreetmap.org/' + zoom + '/' + x + '/' + y + '.png';
+export interface TileProvider {
+ name: string;
+ minZoom: number;
+ maxZoom: number;
+ getTileUrl: { (zoom: number, x: number, y: number): string };
+}
+
+const getRandomItem = (items: any[]) => {
+ const idx = Math.floor(Math.random() * items.length);
+ return items[idx];
+};
+
+const abc = ['a', 'b', 'c'];
+
+export const tileProviders: any = {
+ osm: {
+ name: 'Open Street Map',
+ minZoom: 0,
+ maxZoom: 19,
+ getTileUrl: (zoom: number, x: number, y: number) =>
+ 'https://tile.openstreetmap.org/' + zoom + '/' + x + '/' + y + '.png',
+ },
+ osmfr: {
+ name: 'Open Street Map France',
+ minZoom: 0,
+ maxZoom: 19,
+ getTileUrl: (zoom: number, x: number, y: number) =>
+ 'https://' +
+ getRandomItem(abc) +
+ '.tile.openstreetmap.fr/osmfr/' +
+ zoom +
+ '/' +
+ x +
+ '/' +
+ y +
+ '.png',
+ },
+ otm: {
+ name: 'Open Topo Map',
+ minZoom: 0,
+ maxZoom: 19,
+ getTileUrl: (zoom: number, x: number, y: number) =>
+ 'https://' +
+ getRandomItem(abc) +
+ '.tile.opentopomap.org/' +
+ zoom +
+ '/' +
+ x +
+ '/' +
+ y +
+ '.png',
+ },
+ cyclosm: {
+ name: 'CyclOSM',
+ minZoom: 0,
+ maxZoom: 19,
+ getTileUrl: (zoom: number, x: number, y: number) =>
+ 'https://' +
+ getRandomItem(abc) +
+ '.tile-cyclosm.openstreetmap.fr/cyclosm/' +
+ zoom +
+ '/' +
+ x +
+ '/' +
+ y +
+ '.png',
+ },
+ // cyclosmlite: {
+ // name: 'CyclOSM lite',
+ // minZoom: 0,
+ // maxZoom: 19,
+ // getTileUrl: (zoom: number, x: number, y: number) =>
+ // 'https://' +
+ // getRandomItem(abc) +
+ // '.tile-cyclosm.openstreetmap.fr/cyclosm-lite/' +
+ // zoom +
+ // '/' +
+ // x +
+ // '/' +
+ // y +
+ // '.png',
+ // },
+ // esrisat: {
+ // name: 'ESRI Satellite',
+ // minZoom: 0,
+ // maxZoom: 19,
+ // getTileUrl: (zoom: number, x: number, y: number) =>
+ // 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/' +
+ // zoom +
+ // '/' +
+ // x +
+ // '/' +
+ // y +
+ // '.jpg',
+ // },
+};
const Tile: React.FC<{
ix: number;
@@ -16,9 +112,13 @@ const Tile: React.FC<{
y: number;
zoom: number;
}) => {
+ const tileProvider = useSelector(
+ (state: { map: MapState }) => state.map.scope.tileProvider
+ ) as keyof typeof tileProviders;
+
return (
diff --git a/src/store/map.ts b/src/store/map.ts
index 055ec8a..e1c91d6 100644
--- a/src/store/map.ts
+++ b/src/store/map.ts
@@ -18,10 +18,12 @@ export const zoom0 = 18;
export interface MapScope {
center: geoPoint;
zoom: number;
+ tileProvider: string;
}
var initialMapScope: MapScope = {
center: { lat: -37.8403508, lon: 77.5539501 },
zoom: 15,
+ tileProvider: 'osm',
};
// Derived properties
@@ -197,6 +199,9 @@ const mapSlice = createSlice({
name: 'map',
initialState: initialMapState,
reducers: {
+ setTileProvider: (state, action) => {
+ state.scope.tileProvider = action.payload;
+ },
resize: (state) => {
evaluateStateFromScope(state);
},