diff --git a/CHANGELOG.md b/CHANGELOG.md index 336147aea..75c520486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Changed - Viewer: allow setting default outside video player +- Map: fit to most recent items if all items cannot fit on screen ## [v1.7.7] - 2022-11-27 diff --git a/lib/widgets/common/map/geo_map.dart b/lib/widgets/common/map/geo_map.dart index 7427df121..44d079d4c 100644 --- a/lib/widgets/common/map/geo_map.dart +++ b/lib/widgets/common/map/geo_map.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:math'; +import 'dart:ui'; import 'package:aves/model/entry.dart'; import 'package:aves/model/entry_images.dart'; @@ -320,18 +321,25 @@ class _GeoMapState extends State { } } if (bounds == null) { - // fit map to located items + LatLng? centerToSave; final initialCenter = widget.initialCenter; - final points = initialCenter != null ? {initialCenter} : entries.map((v) => v.latLng!).toSet(); - if (points.isNotEmpty) { + if (initialCenter != null) { + // fit map for specified center and user zoom bounds = ZoomedBounds.fromPoints( - points: points, + points: {initialCenter}, collocationZoom: settings.infoMapZoom, ); - final center = bounds.projectedCenter; + centerToSave = initialCenter; + } else { + // fit map for all located items if possible, falling back to most recent items + bounds = _initBoundsForEntries(entries: entries); + centerToSave = bounds?.projectedCenter; + } + + if (centerToSave != null) { WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; - settings.mapDefaultCenter = center; + settings.mapDefaultCenter = centerToSave; }); } } @@ -353,6 +361,29 @@ class _GeoMapState extends State { ); } + ZoomedBounds? _initBoundsForEntries({required List entries, int? recentCount}) { + if (recentCount != null) { + entries = List.of(entries)..sort(AvesEntry.compareByDate); + entries = entries.take(recentCount).toList(); + } + + if (entries.isEmpty) return null; + + final points = entries.map((v) => v.latLng!).toSet(); + var bounds = ZoomedBounds.fromPoints( + points: points, + collocationZoom: settings.infoMapZoom, + ); + bounds = bounds.copyWith(zoom: max(minInitialZoom, bounds.zoom.floorToDouble())); + + final availableSize = window.physicalSize / window.devicePixelRatio; + final neededSize = bounds.toDisplaySize(); + if (neededSize.longestSide > availableSize.shortestSide) { + return _initBoundsForEntries(entries: entries, recentCount: (recentCount ?? 10000) ~/ 10); + } + return bounds; + } + void _onCollectionChanged() { _defaultMarkerCluster = _buildFluster(); _slowMarkerCluster = null; diff --git a/plugins/aves_map/lib/src/zoomed_bounds.dart b/plugins/aves_map/lib/src/zoomed_bounds.dart index 0f835e3f4..5741186b5 100644 --- a/plugins/aves_map/lib/src/zoomed_bounds.dart +++ b/plugins/aves_map/lib/src/zoomed_bounds.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'dart:ui'; import 'package:aves_map/src/geo_utils.dart'; import 'package:equatable/equatable.dart'; @@ -89,4 +90,10 @@ class ZoomedBounds extends Equatable { } bool contains(LatLng point) => GeoUtils.contains(sw, ne, point); + + Size toDisplaySize() { + final swPoint = _crs.latLngToPoint(sw, zoom); + final nePoint = _crs.latLngToPoint(ne, zoom); + return Size((swPoint.x - nePoint.x).abs().toDouble(), (swPoint.y - nePoint.y).abs().toDouble()); + } }