mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Add OSM backend for map browser
This commit is contained in:
parent
812c8eee9c
commit
3c94741da3
5 changed files with 189 additions and 1 deletions
|
@ -49,6 +49,9 @@ class _MapViewState extends State<_MapView> {
|
|||
},
|
||||
googleClusterBuilder: (context, dataPoints) =>
|
||||
_GoogleMarkerBuilder(context).build(dataPoints),
|
||||
osmClusterBuilder: (context, dataPoints) => _OsmMarker(
|
||||
count: dataPoints.length,
|
||||
),
|
||||
contentPadding: EdgeInsets.only(
|
||||
top: MediaQuery.of(context).padding.top,
|
||||
bottom: MediaQuery.of(context).padding.bottom,
|
||||
|
@ -68,6 +71,30 @@ class _MapViewState extends State<_MapView> {
|
|||
InteractiveMapController? _controller;
|
||||
}
|
||||
|
||||
class _OsmMarker extends StatelessWidget {
|
||||
const _OsmMarker({
|
||||
required this.count,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
count.toString(),
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final int count;
|
||||
}
|
||||
|
||||
class _PanelContainer extends StatefulWidget {
|
||||
const _PanelContainer({
|
||||
required this.isShow,
|
||||
|
|
|
@ -26,6 +26,14 @@ packages:
|
|||
url: "https://gitlab.com/nc-photos/plus_plugins"
|
||||
source: git
|
||||
version: "3.1.1"
|
||||
animated_stack_widget:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: animated_stack_widget
|
||||
sha256: ce4788dd158768c9d4388354b6fb72600b78e041a37afc4c279c63ecafcb9408
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -545,6 +553,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
flutter_map_marker_cluster:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_map_marker_cluster
|
||||
sha256: a324f48da5ee83a3f29fd8d08b4b1e6e3114ff5c6cab910124d6a2e1f06f08cc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.6"
|
||||
flutter_map_marker_popup:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_map_marker_popup
|
||||
sha256: ec563bcbae24a18ac16815fb75ac5ab33ccba609e14db70e252a67de19c6639c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:np_gps_map/src/gps_map.dart';
|
||||
import 'package:np_gps_map/src/interactive_map/google.dart';
|
||||
import 'package:np_gps_map/src/interactive_map/osm.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
import 'package:np_gps_map/src/util.dart';
|
||||
import 'package:np_platform_util/np_platform_util.dart';
|
||||
|
@ -26,6 +27,7 @@ class InteractiveMap extends StatelessWidget {
|
|||
this.initialZoom,
|
||||
this.dataPoints,
|
||||
this.onClusterTap,
|
||||
this.osmClusterBuilder,
|
||||
this.googleClusterBuilder,
|
||||
this.contentPadding,
|
||||
this.onMapCreated,
|
||||
|
@ -35,7 +37,15 @@ class InteractiveMap extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
if (providerHint == GpsMapProvider.osm ||
|
||||
(getRawPlatform() == NpPlatform.android && !isNewGMapsRenderer())) {
|
||||
return const SizedBox.shrink();
|
||||
return OsmInteractiveMap(
|
||||
initialPosition: initialPosition,
|
||||
initialZoom: initialZoom,
|
||||
dataPoints: dataPoints,
|
||||
onClusterTap: onClusterTap,
|
||||
clusterBuilder: osmClusterBuilder,
|
||||
contentPadding: contentPadding,
|
||||
onMapCreated: onMapCreated,
|
||||
);
|
||||
} else {
|
||||
return GoogleInteractiveMap(
|
||||
initialPosition: initialPosition,
|
||||
|
@ -57,6 +67,7 @@ class InteractiveMap extends StatelessWidget {
|
|||
final List<DataPoint>? dataPoints;
|
||||
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
||||
final GoogleClusterBuilder? googleClusterBuilder;
|
||||
final OsmClusterBuilder? osmClusterBuilder;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
||||
}
|
||||
|
|
125
np_gps_map/lib/src/interactive_map/osm.dart
Normal file
125
np_gps_map/lib/src/interactive_map/osm.dart
Normal file
|
@ -0,0 +1,125 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_gps_map/src/interactive_map.dart';
|
||||
import 'package:np_gps_map/src/map_coord.dart';
|
||||
|
||||
typedef OsmClusterBuilder = Widget Function(
|
||||
BuildContext context, List<DataPoint> dataPoints);
|
||||
|
||||
class OsmInteractiveMap extends StatefulWidget {
|
||||
const OsmInteractiveMap({
|
||||
super.key,
|
||||
this.initialPosition,
|
||||
this.initialZoom,
|
||||
this.dataPoints,
|
||||
this.clusterBuilder,
|
||||
this.onClusterTap,
|
||||
this.contentPadding,
|
||||
this.onMapCreated,
|
||||
});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _OsmInteractiveMapState();
|
||||
|
||||
final MapCoord? initialPosition;
|
||||
final double? initialZoom;
|
||||
final List<DataPoint>? dataPoints;
|
||||
final OsmClusterBuilder? clusterBuilder;
|
||||
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
||||
final EdgeInsets? contentPadding;
|
||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
||||
}
|
||||
|
||||
class _OsmInteractiveMapState extends State<OsmInteractiveMap> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (_parentController == null) {
|
||||
_parentController = _ParentController(_controller);
|
||||
widget.onMapCreated?.call(_parentController!);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FlutterMap(
|
||||
mapController: _controller,
|
||||
options: MapOptions(
|
||||
initialCenter: widget.initialPosition?.toLatLng() ?? const LatLng(0, 0),
|
||||
initialZoom: max(2.5, widget.initialZoom ?? 2.5),
|
||||
minZoom: 2.5,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
),
|
||||
if (widget.dataPoints != null)
|
||||
MarkerClusterLayerWidget(
|
||||
options: MarkerClusterLayerOptions(
|
||||
markers: widget.dataPoints!
|
||||
.map((e) => _OsmDataPoint(
|
||||
original: e,
|
||||
child: _buildMarker(context, [e]),
|
||||
))
|
||||
.toList(),
|
||||
builder: (context, markers) => _buildMarker(
|
||||
context,
|
||||
markers.cast<_OsmDataPoint>().map((e) => e.original).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: widget.contentPadding ?? EdgeInsets.zero,
|
||||
child: const SimpleAttributionWidget(
|
||||
source: Text("OpenStreetMap contributors"),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMarker(BuildContext context, List<DataPoint> dataPoints) {
|
||||
if (widget.clusterBuilder == null) {
|
||||
return const SizedBox.shrink();
|
||||
} else {
|
||||
return GestureDetector(
|
||||
onTap: widget.onClusterTap?.let((l) => () => l(dataPoints)),
|
||||
child: widget.clusterBuilder!(context, dataPoints),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_ParentController? _parentController;
|
||||
late final _controller = MapController();
|
||||
}
|
||||
|
||||
class _OsmDataPoint extends Marker {
|
||||
_OsmDataPoint({
|
||||
required this.original,
|
||||
required super.child,
|
||||
}) : super(point: original.position.toLatLng());
|
||||
|
||||
final DataPoint original;
|
||||
}
|
||||
|
||||
class _ParentController implements InteractiveMapController {
|
||||
const _ParentController(this.controller);
|
||||
|
||||
@override
|
||||
void setPosition(MapCoord position) {
|
||||
controller.move(position.toLatLng(), 10);
|
||||
}
|
||||
|
||||
final MapController controller;
|
||||
}
|
||||
|
||||
extension on MapCoord {
|
||||
LatLng toLatLng() => LatLng(latitude, longitude);
|
||||
}
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
flutter:
|
||||
sdk: flutter
|
||||
flutter_map: ^6.1.0
|
||||
flutter_map_marker_cluster: ^1.3.6
|
||||
google_maps_flutter: 2.5.3
|
||||
google_maps_cluster_manager: 3.1.0
|
||||
latlong2: any
|
||||
|
|
Loading…
Reference in a new issue