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) =>
|
googleClusterBuilder: (context, dataPoints) =>
|
||||||
_GoogleMarkerBuilder(context).build(dataPoints),
|
_GoogleMarkerBuilder(context).build(dataPoints),
|
||||||
|
osmClusterBuilder: (context, dataPoints) => _OsmMarker(
|
||||||
|
count: dataPoints.length,
|
||||||
|
),
|
||||||
contentPadding: EdgeInsets.only(
|
contentPadding: EdgeInsets.only(
|
||||||
top: MediaQuery.of(context).padding.top,
|
top: MediaQuery.of(context).padding.top,
|
||||||
bottom: MediaQuery.of(context).padding.bottom,
|
bottom: MediaQuery.of(context).padding.bottom,
|
||||||
|
@ -68,6 +71,30 @@ class _MapViewState extends State<_MapView> {
|
||||||
InteractiveMapController? _controller;
|
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 {
|
class _PanelContainer extends StatefulWidget {
|
||||||
const _PanelContainer({
|
const _PanelContainer({
|
||||||
required this.isShow,
|
required this.isShow,
|
||||||
|
|
|
@ -26,6 +26,14 @@ packages:
|
||||||
url: "https://gitlab.com/nc-photos/plus_plugins"
|
url: "https://gitlab.com/nc-photos/plus_plugins"
|
||||||
source: git
|
source: git
|
||||||
version: "3.1.1"
|
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:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -545,6 +553,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.0"
|
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:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:np_gps_map/src/gps_map.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/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/map_coord.dart';
|
||||||
import 'package:np_gps_map/src/util.dart';
|
import 'package:np_gps_map/src/util.dart';
|
||||||
import 'package:np_platform_util/np_platform_util.dart';
|
import 'package:np_platform_util/np_platform_util.dart';
|
||||||
|
@ -26,6 +27,7 @@ class InteractiveMap extends StatelessWidget {
|
||||||
this.initialZoom,
|
this.initialZoom,
|
||||||
this.dataPoints,
|
this.dataPoints,
|
||||||
this.onClusterTap,
|
this.onClusterTap,
|
||||||
|
this.osmClusterBuilder,
|
||||||
this.googleClusterBuilder,
|
this.googleClusterBuilder,
|
||||||
this.contentPadding,
|
this.contentPadding,
|
||||||
this.onMapCreated,
|
this.onMapCreated,
|
||||||
|
@ -35,7 +37,15 @@ class InteractiveMap extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (providerHint == GpsMapProvider.osm ||
|
if (providerHint == GpsMapProvider.osm ||
|
||||||
(getRawPlatform() == NpPlatform.android && !isNewGMapsRenderer())) {
|
(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 {
|
} else {
|
||||||
return GoogleInteractiveMap(
|
return GoogleInteractiveMap(
|
||||||
initialPosition: initialPosition,
|
initialPosition: initialPosition,
|
||||||
|
@ -57,6 +67,7 @@ class InteractiveMap extends StatelessWidget {
|
||||||
final List<DataPoint>? dataPoints;
|
final List<DataPoint>? dataPoints;
|
||||||
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
final void Function(List<DataPoint> dataPoints)? onClusterTap;
|
||||||
final GoogleClusterBuilder? googleClusterBuilder;
|
final GoogleClusterBuilder? googleClusterBuilder;
|
||||||
|
final OsmClusterBuilder? osmClusterBuilder;
|
||||||
final EdgeInsets? contentPadding;
|
final EdgeInsets? contentPadding;
|
||||||
final void Function(InteractiveMapController controller)? onMapCreated;
|
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:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_map: ^6.1.0
|
flutter_map: ^6.1.0
|
||||||
|
flutter_map_marker_cluster: ^1.3.6
|
||||||
google_maps_flutter: 2.5.3
|
google_maps_flutter: 2.5.3
|
||||||
google_maps_cluster_manager: 3.1.0
|
google_maps_cluster_manager: 3.1.0
|
||||||
latlong2: any
|
latlong2: any
|
||||||
|
|
Loading…
Reference in a new issue