diff --git a/angular.json b/angular.json index dcab19b..6908d43 100644 --- a/angular.json +++ b/angular.json @@ -17,15 +17,9 @@ "tsConfig": "frontend/tsconfig.app.json", "polyfills": "frontend/polyfills.ts", "assets": [ - { - "glob": "**/*", - "input": "./node_modules/leaflet/dist/images", - "output": "/" - }, "frontend/assets" ], "styles": [ - "node_modules/leaflet/dist/leaflet.css", "node_modules/ngx-toastr/toastr.css", "node_modules/bootstrap/dist/css/bootstrap.css", "node_modules/open-iconic/font/css/open-iconic-bootstrap.css", @@ -83,6 +77,7 @@ "node_modules/ngx-toastr/toastr.css", "node_modules/bootstrap/dist/css/bootstrap.css", "node_modules/open-iconic/font/css/open-iconic-bootstrap.css", + "node_modules/ngx-bootstrap/datepicker/bs-datepicker.css", "frontend/styles.css" ], "assets": [ diff --git a/backend/model/diagnostics/ConfigDiagnostics.ts b/backend/model/diagnostics/ConfigDiagnostics.ts index e261153..54c6d3e 100644 --- a/backend/model/diagnostics/ConfigDiagnostics.ts +++ b/backend/model/diagnostics/ConfigDiagnostics.ts @@ -154,8 +154,15 @@ export class ConfigDiagnostics { } - static async testMapConfig(map: ClientConfig.MapConfig) { - if (map.enabled === true && map.mapProvider === ClientConfig.MapProviders.Custom && + static async testMapConfig(map: ClientConfig.MapConfig): Promise { + if (map.enabled === false) { + return; + } + if (map.mapProvider === ClientConfig.MapProviders.Mapbox && + (!map.mapboxAccessToken || map.mapboxAccessToken.length === 0)) { + throw new Error('Mapbox needs a valid api key.'); + } + if (map.mapProvider === ClientConfig.MapProviders.Custom && (!map.tileUrl || map.tileUrl.length === 0)) { throw new Error('Custom maps need a valid tile url'); } diff --git a/backend/routes/PublicRouter.ts b/backend/routes/PublicRouter.ts index e21881a..1cf6e18 100644 --- a/backend/routes/PublicRouter.ts +++ b/backend/routes/PublicRouter.ts @@ -90,7 +90,7 @@ export class PublicRouter { ); }); - app.get('/assets/:file', + app.get('/assets/:file(*)', setLocale, (req: Request, res: Response) => { const file = path.resolve(ProjectPath.FrontendFolder, req['localePath'], 'assets', req.params.file); diff --git a/common/config/public/ConfigClass.ts b/common/config/public/ConfigClass.ts index ca7d55a..6cff3df 100644 --- a/common/config/public/ConfigClass.ts +++ b/common/config/public/ConfigClass.ts @@ -4,7 +4,7 @@ import {UserRoles} from '../../entities/UserDTO'; export module ClientConfig { export enum MapProviders { - OpenStreetMap, Custom + OpenStreetMap, Mapbox, Custom } export interface SearchConfig { @@ -29,6 +29,7 @@ export module ClientConfig { export interface MapConfig { enabled: boolean; mapProvider: MapProviders; + mapboxAccessToken: string; tileUrl: string; } @@ -107,6 +108,7 @@ export class PublicConfigClass { Map: { enabled: true, mapProvider: ClientConfig.MapProviders.OpenStreetMap, + mapboxAccessToken: '', tileUrl: '' }, RandomPhoto: { diff --git a/docs/assets/lightbox_info.jpg b/docs/assets/lightbox_info.jpg index da6320c..7c96b14 100644 Binary files a/docs/assets/lightbox_info.jpg and b/docs/assets/lightbox_info.jpg differ diff --git a/docs/assets/main_page.jpg b/docs/assets/main_page.jpg index 036149d..ce53b04 100644 Binary files a/docs/assets/main_page.jpg and b/docs/assets/main_page.jpg differ diff --git a/docs/assets/map.jpg b/docs/assets/map.jpg index 1000325..9d65f57 100644 Binary files a/docs/assets/map.jpg and b/docs/assets/map.jpg differ diff --git a/docs/assets/random_link.jpg b/docs/assets/random_link.jpg index 3b07468..40e983a 100644 Binary files a/docs/assets/random_link.jpg and b/docs/assets/random_link.jpg differ diff --git a/docs/assets/search.jpg b/docs/assets/search.jpg index cd7537c..fc0a4a6 100644 Binary files a/docs/assets/search.jpg and b/docs/assets/search.jpg differ diff --git a/docs/assets/sharing.jpg b/docs/assets/sharing.jpg index cacb215..e476cac 100644 Binary files a/docs/assets/sharing.jpg and b/docs/assets/sharing.jpg differ diff --git a/docs/index.html b/docs/index.html index be947e0..5e9b0fd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -16,7 +16,7 @@ Fork me on GitHub
@@ -66,8 +66,10 @@

Map

- PiGallery2 reads the location data of the photos and puts them on google maps. + PiGallery2 reads the location data of the photos and puts them on a nice map. The gallery also supports *.gps file to show your tracked path on the map too. + It by default supports OpenStreetMap and Mapbox, but you can also add you own favourite map provider.
diff --git a/frontend/app/app.module.ts b/frontend/app/app.module.ts index ee47f41..d0552f4 100644 --- a/frontend/app/app.module.ts +++ b/frontend/app/app.module.ts @@ -74,6 +74,7 @@ import {FixOrientationPipe} from './gallery/FixOrientationPipe'; import {VideoSettingsComponent} from './settings/video/video.settings.component'; import {DurationPipe} from './pipes/DurationPipe'; import {MapService} from './gallery/map/map.service'; +import {Icon} from 'leaflet'; import {MetaFileSettingsComponent} from './settings/metafiles/metafile.settings.component'; @@ -83,7 +84,16 @@ export class MyHammerConfig extends HammerGestureConfig { 'swipe': {direction: 31} // enable swipe up }; } - +/* +console.log(Icon); +console.log(Icon.Default); +console.log(Icon.Default.prototype); +console.log(Icon.Default.prototype.options); +Icon.Default.prototype.options.iconRetinaUrl = 'assets/leaflet/marker-icon-2x.png'; +Icon.Default.imagePath = 'assets/leaflet/marker-icon.png'; +Icon.Default.prototype.options.iconUrl = 'assets/leaflet/marker-icon.png'; +Icon.Default.prototype.options.shadowUrl = 'assets/leaflet/marker-shadow.png'; +*/ export class CustomUrlSerializer implements UrlSerializer { private _defaultUrlSerializer: DefaultUrlSerializer = new DefaultUrlSerializer(); diff --git a/frontend/app/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.html b/frontend/app/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.html index 2a89017..58b17f0 100644 --- a/frontend/app/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.html +++ b/frontend/app/gallery/lightbox/infopanel/info-panel.lightbox.gallery.component.html @@ -105,6 +105,10 @@ [lat]="PositionData.GPSData.latitude" [lng]="PositionData.GPSData.longitude"> + + diff --git a/frontend/app/gallery/map/lightbox/lightbox.map.gallery.component.html b/frontend/app/gallery/map/lightbox/lightbox.map.gallery.component.html index f29eb2b..adf3303 100644 --- a/frontend/app/gallery/map/lightbox/lightbox.map.gallery.component.html +++ b/frontend/app/gallery/map/lightbox/lightbox.map.gallery.component.html @@ -46,8 +46,9 @@ + prefix="" + [attributions]="mapService.Attributions"> + diff --git a/frontend/app/gallery/map/map.gallery.component.html b/frontend/app/gallery/map/map.gallery.component.html index b883735..3deaa43 100644 --- a/frontend/app/gallery/map/map.gallery.component.html +++ b/frontend/app/gallery/map/map.gallery.component.html @@ -12,10 +12,17 @@ *ngFor="let photo of mapPhotos" [lat]="photo.lat" [lng]="photo.lng"> + + prefix="" + [attributions]="mapService.ShortAttributions"> +
this.mapPhotos); + this.yagaMap.setView(this.mapPhotos[0], 99); + this.yagaMap.fitBounds(this.mapPhotos.map(mp => <[number, number]>[mp.lat, mp.lng])); this.yagaMap.zoom = 0; } @@ -48,8 +48,8 @@ export class GalleryMapComponent implements OnChanges, IRenderable, AfterViewIni ngAfterViewInit() { setTimeout(() => { this.height = this.mapElement.nativeElement.clientHeight; - this.yagaMap.setView(this.mapPhotos[0], 0); - this.yagaMap.fitBounds(this.mapPhotos); + this.yagaMap.setView(this.mapPhotos[0], 99); + this.yagaMap.fitBounds(this.mapPhotos.map(mp => <[number, number]>[mp.lat, mp.lng])); this.yagaMap.zoom = 0; }, 0); } diff --git a/frontend/app/gallery/map/map.service.ts b/frontend/app/gallery/map/map.service.ts index 789bad7..2a70878 100644 --- a/frontend/app/gallery/map/map.service.ts +++ b/frontend/app/gallery/map/map.service.ts @@ -2,7 +2,6 @@ import {Injectable} from '@angular/core'; import {NetworkService} from '../../model/network/network.service'; import {FileDTO} from '../../../../common/entities/FileDTO'; import {Utils} from '../../../../common/Utils'; -import {OSM_TILE_LAYER_URL} from '@yaga/leaflet-ng2'; import {Config} from '../../../../common/config/public/Config'; import {ClientConfig} from '../../../../common/config/public/ConfigClass'; @@ -29,15 +28,48 @@ export class MapService { } + public get ShortAttributions(): string[] { + const yaga = 'YAGA'; + const lf = 'leaflet-ng2'; + const OSM = 'OSM'; + const MB = 'Mapbox'; + + + if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.OpenStreetMap) { + return [yaga + ' | © ' + OSM]; + } + + if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.Mapbox) { + return [yaga + ' | ' + OSM + ' | ' + MB]; + } + return [yaga + ' | ' + lf]; + } + public get Attributions(): string[] { - return ['© OpenStreetMap']; + const yagalf = 'YAGA | ' + + 'leaflet-ng2'; + const OSM = '© OpenStreetMap'; + const MB = '© Mapbox'; + + if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.OpenStreetMap) { + return [yagalf + ' | ' + OSM]; + } + + if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.Mapbox) { + return [yagalf + ' | ' + OSM + ' | ' + MB]; + } + return [yagalf]; } public get MapLayer(): string { if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.Custom) { return Config.Client.Map.tileUrl; } - return OSM_TILE_LAYER_URL; + if (Config.Client.Map.mapProvider === ClientConfig.MapProviders.Mapbox) { + return 'https://api.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token=' + + Config.Client.Map.mapboxAccessToken; + } + return 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; } } diff --git a/frontend/app/settings/map/map.settings.component.html b/frontend/app/settings/map/map.settings.component.html index 406bbe1..0a10963 100644 --- a/frontend/app/settings/map/map.settings.component.html +++ b/frontend/app/settings/map/map.settings.component.html @@ -45,6 +45,19 @@
+
+ +
+ + + MapBox needs an access token to work, create one at https://www.mapbox.com. + +
+
+ +