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());
+ }
}