diff --git a/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts b/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts index 7a4070fe..141241d8 100644 --- a/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts +++ b/src/frontend/app/ui/gallery/map/lightbox/lightbox.map.gallery.component.ts @@ -15,12 +15,12 @@ import { Control, DivIcon, divIcon, + featureGroup, + FeatureGroup, icon, latLng, - latLngBounds, + LatLngBounds, LatLngLiteral, - layerGroup, - LayerGroup, Map, MapOptions, Marker, @@ -72,18 +72,18 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { defLayer: TileLayer; darkLayer: TileLayer; private smallIconSize = new Point( - Config.Media.Thumbnail.iconSize * 0.75, - Config.Media.Thumbnail.iconSize * 0.75 + Config.Media.Thumbnail.iconSize * 0.75, + Config.Media.Thumbnail.iconSize * 0.75 ); private iconSize = new Point( - Config.Media.Thumbnail.iconSize, - Config.Media.Thumbnail.iconSize + Config.Media.Thumbnail.iconSize, + Config.Media.Thumbnail.iconSize ); private usedIconSize = this.iconSize; private mapLayersControlOption: LeafletControlLayersConfig & { overlays: { Photos: MarkerClusterGroup; - [name: string]: LayerGroup; + [name: string]: FeatureGroup; }; } = { baseLayers: {}, @@ -117,7 +117,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { // ordered list private pathLayersConfigOrdered: { name: string, - layer: LayerGroup, + layer: FeatureGroup, themes?: { matchers?: RegExp[], theme?: { color: string, dashArray: string }, @@ -132,10 +132,10 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { private longPathSEPairs: { [key: string]: number } = {}; // stores how often a long distance path pair comes up constructor( - public fullScreenService: FullScreenService, - private thumbnailService: ThumbnailManagerService, - public mapService: MapService, - private themeService: ThemeService + public fullScreenService: FullScreenService, + private thumbnailService: ThumbnailManagerService, + public mapService: MapService, + private themeService: ThemeService ) { this.setUpPathLayers(); this.mapOptions.layers = [this.mapLayersControlOption.overlays.Photos]; @@ -157,9 +157,9 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { this.mapOptions.layers.push(this.themeService.darkMode.value ? this.darkLayer : this.defLayer); this.mapLayerControl = control.layers( - this.mapLayersControlOption.baseLayers, - this.mapLayersControlOption.overlays, - {position: 'bottomright'} + this.mapLayersControlOption.baseLayers, + this.mapLayersControlOption.overlays, + {position: 'bottomright'} ); // update map theme on dark theme @@ -184,7 +184,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { } const pl = { name: nameI18n, - layer: layerGroup([]), + layer: featureGroup([]), themes: conf.matchers.map(ths => { return { matchers: ths.matchers.map(s => new RegExp(s, 'i')), @@ -202,7 +202,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { }); if (this.pathLayersConfigOrdered.length === 0) { - this.pathLayersConfigOrdered.push({name: $localize`Other paths`, layer: layerGroup([])}); + this.pathLayersConfigOrdered.push({name: $localize`Other paths`, layer: featureGroup([])}); } this.pathLayersConfigOrdered.forEach(pl => { @@ -297,9 +297,9 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { // if target image out of screen -> scroll to there if ( - PageHelper.ScrollY > to.top || - PageHelper.ScrollY + GalleryMapLightboxComponent.getScreenHeight() < - to.top + PageHelper.ScrollY > to.top || + PageHelper.ScrollY + GalleryMapLightboxComponent.getScreenHeight() < + to.top ) { PageHelper.ScrollY = to.top; } @@ -320,106 +320,106 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { // make sure to enable photos layers when opening map if ( - this.leafletMap && - !this.leafletMap.hasLayer(this.mapLayersControlOption.overlays.Photos) + this.leafletMap && + !this.leafletMap.hasLayer(this.mapLayersControlOption.overlays.Photos) ) { this.leafletMap.addLayer(this.mapLayersControlOption.overlays.Photos); } this.thumbnailsOnLoad = []; this.photos - .filter((p): number => { - return ( - p.metadata && - p.metadata.positionData && - p.metadata.positionData.GPSData && - p.metadata.positionData.GPSData.latitude && - p.metadata.positionData.GPSData.longitude - ); - }) - .forEach((p): void => { - const mkr = marker({ - lat: p.metadata.positionData.GPSData.latitude, - lng: p.metadata.positionData.GPSData.longitude, - }); - this.mapLayersControlOption.overlays.Photos.addLayer(mkr); - let width = 500; - let height = 500; - const size = p.metadata.size; - if (size.width > size.height) { - height = width * (size.height / size.width); + .filter((p): number => { + return ( + p.metadata && + p.metadata.positionData && + p.metadata.positionData.GPSData && + p.metadata.positionData.GPSData.latitude && + p.metadata.positionData.GPSData.longitude + ); + }) + .forEach((p): void => { + const mkr = marker({ + lat: p.metadata.positionData.GPSData.latitude, + lng: p.metadata.positionData.GPSData.longitude, + }); + this.mapLayersControlOption.overlays.Photos.addLayer(mkr); + let width = 500; + let height = 500; + const size = p.metadata.size; + if (size.width > size.height) { + height = width * (size.height / size.width); + } else { + width = height * (size.width / size.height); + } + const photoTh = this.thumbnailService.getLazyThumbnail( + new Media(p, width, height) + ); + this.thumbnailsOnLoad.push(photoTh); + + // Setting popup photo + const setPopUpPhoto = () => { + const photoPopup = + `preview`; + if (!mkr.getPopup()) { + mkr.bindPopup(photoPopup, {minWidth: width}); } else { - width = height * (size.width / size.height); + mkr.setPopupContent(photoPopup); } - const photoTh = this.thumbnailService.getLazyThumbnail( - new Media(p, width, height) - ); - this.thumbnailsOnLoad.push(photoTh); + }; - // Setting popup photo - const setPopUpPhoto = () => { - const photoPopup = - `preview`; - if (!mkr.getPopup()) { - mkr.bindPopup(photoPopup, {minWidth: width}); - } else { - mkr.setPopupContent(photoPopup); - } - }; - - if (photoTh.Available) { - setPopUpPhoto(); - } else { - const noPhotoPopup = ``; - mkr.bindPopup(noPhotoPopup, {minWidth: width}); - mkr.on('popupopen', () => { - photoTh.load(); - photoTh.CurrentlyWaiting = true; - }); - photoTh.OnLoad = setPopUpPhoto; - } + mkr.bindPopup(noPhotoPopup, {minWidth: width}); + mkr.on('popupopen', () => { + photoTh.load(); + photoTh.CurrentlyWaiting = true; + }); + photoTh.OnLoad = setPopUpPhoto; + } - mkr.setIcon(MarkerFactory.defIcon); - // Setting photo icon - if (Config.Map.useImageMarkers === true) { - mkr.on('add', () => { - mkr.off('add'); - const iconTh = this.thumbnailService.getIcon(new MediaIcon(p)); - this.thumbnailsOnLoad.push(iconTh); - iconTh.Visible = true; - const setIcon = () => { - mkr.setIcon( - icon({ - iconUrl: iconTh.Src, - iconSize: this.usedIconSize, // size of the icon - className: 'photo-icon', - }) - ); - mkr.options.alt = p.name; - mkr.on('mouseover', () => { - mkr.getIcon().options.iconSize = [ - this.usedIconSize.x * 1.5, - this.usedIconSize.y * 1.5, - ]; - mkr.setIcon(mkr.getIcon()); - }); - mkr.on('mouseout', () => { - mkr.getIcon().options.iconSize = this.usedIconSize; - mkr.setIcon(mkr.getIcon()); - }); - }; - if (iconTh.Available === true) { - setIcon(); - } else { - iconTh.OnLoad = setIcon; - } - }); - } - }); + mkr.setIcon(MarkerFactory.defIcon); + // Setting photo icon + if (Config.Map.useImageMarkers === true) { + mkr.on('add', () => { + mkr.off('add'); + const iconTh = this.thumbnailService.getIcon(new MediaIcon(p)); + this.thumbnailsOnLoad.push(iconTh); + iconTh.Visible = true; + const setIcon = () => { + mkr.setIcon( + icon({ + iconUrl: iconTh.Src, + iconSize: this.usedIconSize, // size of the icon + className: 'photo-icon', + }) + ); + mkr.options.alt = p.name; + mkr.on('mouseover', () => { + mkr.getIcon().options.iconSize = [ + this.usedIconSize.x * 1.5, + this.usedIconSize.y * 1.5, + ]; + mkr.setIcon(mkr.getIcon()); + }); + mkr.on('mouseout', () => { + mkr.getIcon().options.iconSize = this.usedIconSize; + mkr.setIcon(mkr.getIcon()); + }); + }; + if (iconTh.Available === true) { + setIcon(); + } else { + iconTh.OnLoad = setIcon; + } + }); + } + }); if (this.gpxFiles) { this.loadGPXFiles().catch(console.error); } @@ -448,7 +448,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { this.pathLayersConfigOrdered.forEach(p => { p.layer.clearLayers(); this.mapLayerControl.removeLayer( - p.layer + p.layer ); }); this.longPathSEPairs = {}; @@ -487,17 +487,17 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { return; } if ( - (this.leafletMap.getZoom() < 15 && - this.usedIconSize === this.smallIconSize) || - (this.leafletMap.getZoom() >= 15 && this.usedIconSize === this.iconSize) + (this.leafletMap.getZoom() < 15 && + this.usedIconSize === this.smallIconSize) || + (this.leafletMap.getZoom() >= 15 && this.usedIconSize === this.iconSize) ) { // all set no change needed return; } this.usedIconSize = - this.leafletMap.getZoom() < 15 ? this.smallIconSize : this.iconSize; + this.leafletMap.getZoom() < 15 ? this.smallIconSize : this.iconSize; ( - this.mapLayersControlOption.overlays.Photos.getLayers() as Marker[] + this.mapLayersControlOption.overlays.Photos.getLayers() as Marker[] ).forEach((mkr) => { // if alt is not present icon is not yet set, so do not change the size if (!mkr.options.alt) { @@ -509,16 +509,22 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { } private centerMap(): void { - if (this.mapLayersControlOption.overlays.Photos.getLayers().length === 0) { + let bounds: LatLngBounds = null; + for (const k of Object.keys(this.mapLayersControlOption.overlays)) { + const b = this.mapLayersControlOption?.overlays?.[k]?.getBounds(); + if (!b) { + continue; + } + if (!bounds) { + bounds = b; + continue; + } + bounds.extend(b); + } + if (!bounds) { return; } - this.leafletMap.fitBounds( - latLngBounds( - ( - this.mapLayersControlOption.overlays.Photos.getLayers() as Marker[] - ).map((m) => m.getLatLng()) - ) - ); + this.leafletMap.fitBounds(bounds); } private addArchForLongDistancePaths(path: LatLngLiteral[]) { @@ -526,7 +532,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { for (let i = 0; i < path.length - 1; ++i) { const dst = (a: LatLngLiteral, b: LatLngLiteral) => { return Math.sqrt(Math.pow(a.lat - b.lat, 2) + - Math.pow(a.lng - b.lng, 2)); + Math.pow(a.lng - b.lng, 2)); }; /** @@ -616,7 +622,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { const loadAFile = async (file: FileDTO) => { const parsedGPX = await this.mapService.getMapCoordinates(file); - let pathLayer: { layer: LayerGroup, icon?: DivIcon, theme?: { color?: string, dashArray?: string } }; + let pathLayer: { layer: FeatureGroup, icon?: DivIcon, theme?: { color?: string, dashArray?: string } }; for (const pl of this.pathLayersConfigOrdered) { pathLayer = {layer: pl.layer, icon: MarkerFactory.defIcon}; if (!pl.themes || pl.themes.length === 0) { @@ -624,8 +630,8 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { } const th = pl.themes.find((th) => { return !th.matchers || th.matchers.length == 0 || // null/empty matchers match everything - (parsedGPX.name && - th.matchers.findIndex(m => m.test(parsedGPX.name)) !== -1); + (parsedGPX.name && + th.matchers.findIndex(m => m.test(parsedGPX.name)) !== -1); }); if (th) { pathLayer.theme = th.theme; @@ -651,12 +657,12 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { parsedGPX.path.forEach(p => { this.addArchForLongDistancePaths(p); pathLayer.layer.addLayer( - polyline(p, { - smoothFactor: 3, - interactive: false, - color: pathLayer?.theme?.color, - dashArray: pathLayer?.theme?.dashArray - }) + polyline(p, { + smoothFactor: 3, + interactive: false, + color: pathLayer?.theme?.color, + dashArray: pathLayer?.theme?.dashArray + }) ); }); @@ -676,17 +682,20 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy { this.pathLayersConfigOrdered.filter(pl => pl.layer.getLayers().length > 0).forEach((pl) => { this.mapLayerControl.addOverlay( - pl.layer, - pl.name + pl.layer, + pl.name ); if ( - this.leafletMap && - !this.leafletMap.hasLayer(pl.layer) + this.leafletMap && + !this.leafletMap.hasLayer(pl.layer) ) { this.leafletMap.addLayer(pl.layer); } }); - + // center map on paths if no photos to center map on + if (!this.photos?.length) { + this.centerMap(); + } } }