Skip to content

Commit

Permalink
Use flutter maps with openstreetmap instead of google #23
Browse files Browse the repository at this point in the history
  • Loading branch information
svendroid committed Nov 1, 2020
1 parent b4d3682 commit 942f184
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 34 deletions.
134 changes: 134 additions & 0 deletions lib/flutter_map/clickable_polyline_layer_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:munich_ways/common/logger_setup.dart';

class ClickablePolylineLayerWidget extends StatelessWidget {
final ClickablePolylineLayerOptions options;

ClickablePolylineLayerWidget({@required this.options})
: super(key: options.key);

@override
Widget build(BuildContext context) {
final mapState = MapState.of(context);
return ClickablePolylineLayer(options, mapState, mapState.onMoved);
}
}

class ClickablePolylineLayerOptions extends PolylineLayerOptions {
ClickablePolylineLayerOptions({
Key key,
polylines = const [],
polylineCulling = false,
rebuild,
}) : super(
key: key,
polylines: polylines,
polylineCulling: polylineCulling,
rebuild: rebuild);
}

class ClickablePolyline extends Polyline {
VoidCallback onTap;

ClickablePolyline(
{points,
strokeWidth = 1.0,
color = const Color(0xFF00FF00),
borderStrokeWidth = 0.0,
borderColor = const Color(0xFFFFFF00),
gradientColors,
colorsStop,
isDotted = false,
this.onTap})
: super(
points: points,
strokeWidth: strokeWidth,
color: color,
borderStrokeWidth: borderStrokeWidth,
borderColor: borderColor,
gradientColors: gradientColors,
colorsStop: colorsStop,
isDotted: isDotted,
);
}

class ClickablePolylineLayer extends StatelessWidget {
final PolylineLayerOptions polylineOpts;
final MapState map;
final Stream<Null> stream;

ClickablePolylineLayer(this.polylineOpts, this.map, this.stream)
: super(key: polylineOpts.key);

@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: (TapUpDetails details) {
//Detect nearest polyline to the tapped point
polylineOpts.polylines.forEach((polyline) {
for (var i = 0; i < polyline.offsets.length - 1; i++) {
Offset x = polyline.offsets[i];
Offset y = polyline.offsets[i + 1];
Offset tap = details.localPosition;

double a = _dist(x, y);
double b = _dist(x, tap);
double c = _dist(y, tap);

// Use Herons formula to calculate area of triangle and from there the height
// https://www.khanacademy.org/math/in-in-grade-9-ncert/xfd53e0255cd302f8:surface-areas-and-volumes/xfd53e0255cd302f8:herons-formula/v/heron-s-formula
double s = (a + b + c) / 2.0;
double area = sqrt(s * (s - a) * (s - b) * (s - c));
double height = (2 * area) / a;

/*
Ensure tap is between x and y or inside the threshold of one of the points
Use Pythagoras: d = sqrt((c*c - h*h)) or d = sqrt((b*b - h*h))
In following case b is used (because its the hypotenuse) for our triangle:
x-------a--------y...d......z
--- - .
--- - .
b --- c - .height
--- - .
--- - .
------------tap
*/

double aAndD = sqrt((_sqr(max(b, c))) - _sqr(height));
double distanceToA = aAndD - a;
double threshold = 20;

if (height < threshold && distanceToA < threshold) {
log.d("Click found on $polyline");
if (polyline is ClickablePolyline) {
ClickablePolyline clickable = polyline;
if (clickable.onTap != null) {
clickable.onTap();
}
}
return;
}
}
});
},
child: PolylineLayer(polylineOpts, map, stream).build(context));
}

double _dist(Offset v, Offset w) {
return sqrt(_dist2(v, w));
}

double _dist2(Offset v, Offset w) {
return _sqr(v.dx - w.dx) + _sqr(v.dy - w.dy);
}

double _sqr(double x) {
return x * x;
}
}
43 changes: 43 additions & 0 deletions lib/flutter_map/osm_credits_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:munich_ways/common/logger_setup.dart';
import 'package:url_launcher/url_launcher.dart';

class OSMCreditsWidget extends StatelessWidget {
const OSMCreditsWidget({
Key key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomLeft,
child: GestureDetector(
onTap: () async {
const url = 'https://www.openstreetmap.org/copyright';
if (await canLaunch(url)) {
await launch(url);
} else {
log.e("No browser found");
}
},
child: Container(
padding: const EdgeInsets.all(2.0),
color: Colors.white70,
child: Text.rich(TextSpan(
text: "© ",
style: TextStyle(fontSize: 12),
children: <TextSpan>[
TextSpan(
text: "OpenStreetMaps",
style: TextStyle(
decoration: TextDecoration.underline,
)),
TextSpan(
text: " contributors",
)
],
))),
),
);
}
}
4 changes: 0 additions & 4 deletions lib/ui/map/geojson_converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ import 'package:latlong/latlong.dart';
import 'package:munich_ways/common/logger_setup.dart';
import 'package:munich_ways/model/street_details.dart';

abstract class OnTapListener {
void onTap(dynamic feature);
}

/// Converts geojson to google maps polylines
class GeojsonConverter {
Set<MPolyline> getPolylines({@required geojson}) {
Expand Down
51 changes: 33 additions & 18 deletions lib/ui/map/map_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
import 'package:munich_ways/common/logger_setup.dart';
import 'package:munich_ways/flutter_map/clickable_polyline_layer_widget.dart';
import 'package:munich_ways/flutter_map/osm_credits_widget.dart';
import 'package:munich_ways/ui/map/map_info_dialog.dart';
import 'package:munich_ways/ui/map/map_screen_model.dart';
import 'package:munich_ways/ui/map/missing_radnetze_overlay.dart';
Expand Down Expand Up @@ -125,26 +127,39 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
children: [
FlutterMap(
options: MapOptions(
center: LatLng(_stachus.latitude, _stachus.longitude),
zoom: 14),
layers: [
TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c'],
center: LatLng(_stachus.latitude, _stachus.longitude),
zoom: 14,
),
children: [
TileLayerWidget(
options: TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c'],
),
),
PolylineLayerOptions(
polylines: model.polylines
.map((e) => Polyline(
points: e.points
.map((latlng) =>
LatLng(latlng.latitude, latlng.longitude))
.toList(),
strokeWidth: 3.0,
color:
AppColors.getPolylineColor(e.details.farbe)))
.toList(),
ClickablePolylineLayerWidget(
options: ClickablePolylineLayerOptions(
polylineCulling: true,
polylines: model.polylines
.map(
(polyline) => ClickablePolyline(
points: polyline.points
.map((latlng) => LatLng(
latlng.latitude, latlng.longitude))
.toList(),
strokeWidth: 3.0,
isDotted: false,
color: AppColors.getPolylineColor(
polyline.details.farbe),
onTap: () {
model.onTap(polyline.details);
}),
)
.toList(),
),
),
OSMCreditsWidget(),
],
),
SafeArea(
Expand Down
13 changes: 6 additions & 7 deletions lib/ui/map/map_screen_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:munich_ways/model/street_details.dart';
import 'package:munich_ways/ui/map/geojson_converter.dart';
import 'package:munich_ways/ui/map/munichways_api.dart';

class MapScreenViewModel extends ChangeNotifier implements OnTapListener {
class MapScreenViewModel extends ChangeNotifier {
bool loading = false;

bool firstLoad = true;
Expand Down Expand Up @@ -136,8 +136,8 @@ class MapScreenViewModel extends ChangeNotifier implements OnTapListener {
notifyListeners();

try {
_polylinesVorrangnetz = await _netzRepo.getRadlvorrangnetz(this);
_polylinesGesamtnetz = await _netzRepo.getGesamtnetz(this);
_polylinesVorrangnetz = await _netzRepo.getRadlvorrangnetz();
_polylinesGesamtnetz = await _netzRepo.getGesamtnetz();
} catch (e) {
_displayErrorMsg(e.toString());
log.e("Error loading Netze", e);
Expand All @@ -149,9 +149,8 @@ class MapScreenViewModel extends ChangeNotifier implements OnTapListener {
notifyListeners();
}

@override
void onTap(feature) {
log.d(feature['properties']);
showStreetDetailsController.add(StreetDetails.fromJson(feature));
void onTap(StreetDetails details) {
log.d(details);
showStreetDetailsController.add(details);
}
}
8 changes: 3 additions & 5 deletions lib/ui/map/munichways_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ class MunichwaysApi {

GeojsonConverter _converter = GeojsonConverter();

Future<Set<MPolyline>> getRadlvorrangnetz(OnTapListener onTapListener) async {
return _getNetz(
_radlvorrangnetzName,
);
Future<Set<MPolyline>> getRadlvorrangnetz() async {
return _getNetz(_radlvorrangnetzName);
}

Future<Set<MPolyline>> getGesamtnetz(OnTapListener onTapListener) async {
Future<Set<MPolyline>> getGesamtnetz() async {
return _getNetz(_gesamtnetzName);
}

Expand Down

0 comments on commit 942f184

Please sign in to comment.