From ed119987396da21c55744a4ef4a623523ea69e49 Mon Sep 17 00:00:00 2001 From: Freek van de Ven Date: Wed, 29 Sep 2021 12:18:53 +0200 Subject: [PATCH] update demo to amsterdam travel --- example/lib/main.dart | 67 ++++++----------- lib/src/controller.dart | 56 ++++++++------ lib/src/directions_controller.dart | 5 +- lib/src/google_map.dart | 117 +++++++++++++++++------------ 4 files changed, 124 insertions(+), 121 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index ffca333..f8bf62e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -17,15 +17,8 @@ class _TrackTraceDemoState extends State { @override void initState() { - // TODO: implement initState Timer.periodic(const Duration(seconds: 10), (_) { - print('updating marker'); - getRandomPointOnMap(); - }); - - Timer.periodic(const Duration(seconds: 60), (_) { - print('updating route'); - getRandomRoute(); + moveAlongRoute(); }); super.initState(); } @@ -34,24 +27,30 @@ class _TrackTraceDemoState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: (controller == null) + title: (controller == null || controller!.route == null) ? const Text('TrackTrace example') - : Text(controller!.duration.toString() + ' seconds')), + : Text(controller!.route!.duration.toString() + + ' seconds, afstand: ' + + (controller!.route!.distance / 1000).toString() + + ' km')), body: GoogleTrackTraceMap( startPosition: const Marker( markerId: MarkerId('Start locatie'), - position: LatLng(51.965578, 6.293439), + position: LatLng(52.356057, 4.897540), ), destinationPosition: const Marker( - markerId: MarkerId('Eind locatie'), - position: LatLng(51.958996, 6.296520), - ), + markerId: MarkerId('Bestemming Locatie'), + position: LatLng(52.364709, 4.877157)), googleAPIKey: 'AIzaSyDaxZX8TeQeVf5tW-D6A66WLl20arbWV6c', - travelMode: TravelMode.walking, + travelMode: TravelMode.bicycling, routeUpdateInterval: 60, - routeLabel: 'Test route', timerPrecision: TimePrecision.everySecond, zoomGesturesEnabled: true, + line: const Polyline( + polylineId: PolylineId('test route'), + color: Colors.purple, + width: 7, + ), onMapCreated: (ctr) => { controller = ctr, ctr.addListener(() { @@ -62,42 +61,20 @@ class _TrackTraceDemoState extends State { ); } - void updateMap() { - controller!.current = const Marker( - markerId: MarkerId('Huidige locatie'), - position: LatLng(51.962578, 6.294439), - ); - } - void getRandomPointOnMap() { - // 51.989909, 6.234950 - - // 51.939909, 6.314950 + // 51.989909, 6.234950 NW + // 51.939909, 6.314950 SE if (controller != null) { - controller!.current = Marker( - markerId: MarkerId('Huidige Locatie'), + controller!.start = Marker( + markerId: const MarkerId('Start Locatie'), position: LatLng(51.93 + Random().nextDouble() * 0.06, 6.23 + Random().nextDouble() * 0.08)); } } - void getRandomRoute() { - // if (route != null) { - // print('removing point'); - // PointLatLng point = route!.polylinePoints[1]; - // trackTraceController.startMarker = Marker( - // markerId: MarkerId('Start locatie'), - // position: LatLng(point.latitude, point.longitude)); - // } - if (controller != null) { - controller!.start = Marker( - markerId: MarkerId('Start Locatie'), - position: LatLng(51.93 + Random().nextDouble() * 0.06, - 6.23 + Random().nextDouble() * 0.08)); - controller!.end = Marker( - markerId: MarkerId('Bestemming Locatie'), - position: LatLng(51.93 + Random().nextDouble() * 0.06, - 6.23 + Random().nextDouble() * 0.08)); + void moveAlongRoute() { + if (controller != null && controller!.route != null && controller!.route!.line.length > 1) { + controller!.start = Marker(markerId: const MarkerId('Start Locatie'), position: LatLng(controller!.route!.line[1].latitude, controller!.route!.line[1].longitude)); } } } diff --git a/lib/src/controller.dart b/lib/src/controller.dart index e3299b3..d98729d 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -1,48 +1,56 @@ part of google_track_trace; class TrackTraceController extends ChangeNotifier { - late final GoogleMapController _mapController; - Marker startPosition; - Marker destinationPosition; - Marker? currentPosition; - - int durationInSeconds = 0; + GoogleMapController? _mapController; + Marker _startPosition; + Marker _destinationPosition; + TrackTraceRoute? _route; TrackTraceController(Marker start, Marker destination) - : startPosition = start, - destinationPosition = destination; + : _startPosition = start, + _destinationPosition = destination; set start(Marker start) { - startPosition = start; - notifyListeners(); - } - - set current(Marker? current) { - currentPosition = current; + _startPosition = start; notifyListeners(); } set end(Marker end) { - destinationPosition = end; + _destinationPosition = end; notifyListeners(); } - Marker get start => startPosition; + Marker get start => _startPosition; - Marker? get current => currentPosition; + Marker get end => _destinationPosition; - Marker get end => destinationPosition; + TrackTraceRoute? get route => _route; - set duration(int duration) { - durationInSeconds = duration; + set route(TrackTraceRoute? newRoute) { + _route = newRoute; notifyListeners(); } - int get duration => durationInSeconds; - - set mapController(GoogleMapController controller) { + set mapController(GoogleMapController? controller) { _mapController = controller; } - GoogleMapController get mapController => _mapController; + GoogleMapController? get mapController => _mapController; +} + +class TrackTraceRoute { + /// route duration in seconds + int duration = 0; + + /// route distance in meters + int distance = 0; + + /// route edge points + List line; + + TrackTraceRoute( + int durationValue, int distanceValue, List lineValue) + : duration = durationValue, + distance = distanceValue, + line = lineValue; } diff --git a/lib/src/directions_controller.dart b/lib/src/directions_controller.dart index 33cfe48..7ab03d6 100644 --- a/lib/src/directions_controller.dart +++ b/lib/src/directions_controller.dart @@ -35,7 +35,7 @@ class DirectionsRepository { } on HttpException catch (e) { print(e.message); } - throw GoogleMapsException('Unable to retrieve directions'); + throw GoogleMapsException('Unable to retrieve directions from Google Maps API'); } } @@ -52,6 +52,7 @@ class Directions { required this.totalDuration, }); + /// map the json response to a [Directions] object factory Directions.fromMap(Map map) { if ((map['routes'] as List).isEmpty) { throw GoogleMapsException('No Routes available'); @@ -92,7 +93,7 @@ class GoogleMapsException implements Exception { @override String toString() { - return 'Error occurred in Google Maps package:\n' + return 'Error occurred in Track&Trace package:\n' '$message'; } } diff --git a/lib/src/google_map.dart b/lib/src/google_map.dart index 6ba3679..a145a97 100644 --- a/lib/src/google_map.dart +++ b/lib/src/google_map.dart @@ -13,13 +13,15 @@ class GoogleTrackTraceMap extends StatefulWidget { required this.routeUpdateInterval, this.timerPrecision = TimePrecision.everyMinute, this.travelMode = TravelMode.driving, - this.routeLabel = '', this.compassEnabled = false, this.zoomControlsEnabled = false, this.zoomGesturesEnabled = false, this.mapToolbarEnabled = false, this.mapType = MapType.normal, this.buildingsEnabled = false, + this.mapMarkations = + '[{"featureType": "poi","stylers": [{"visibility": "off"}]}]', + this.line, }) : assert(true), super(key: key); @@ -31,8 +33,6 @@ class GoogleTrackTraceMap extends StatefulWidget { final TravelMode travelMode; - final String routeLabel; - final int routeUpdateInterval; final TimePrecision timerPrecision; @@ -40,6 +40,8 @@ class GoogleTrackTraceMap extends StatefulWidget { final Marker startPosition; final Marker destinationPosition; + Polyline? line; + final bool compassEnabled; final bool zoomControlsEnabled; final bool zoomGesturesEnabled; @@ -47,6 +49,8 @@ class GoogleTrackTraceMap extends StatefulWidget { final bool buildingsEnabled; final MapType mapType; + final String mapMarkations; + CameraPosition initialCameraPosition = const CameraPosition( // doetinchem default initialCamera target: LatLng(51.965578, 6.293439), @@ -59,25 +63,24 @@ class GoogleTrackTraceMap extends StatefulWidget { } class _GoogleTrackTraceMapState extends State { - late final TrackTraceController trackTraceController; + late final TrackTraceController controller; - Directions? route; DateTime lastRouteUpdate = DateTime.now(); @override void initState() { super.initState(); - trackTraceController = + controller = TrackTraceController(widget.startPosition, widget.destinationPosition); - trackTraceController.addListener(_onChange); - widget.onMapCreated(trackTraceController); + controller.addListener(_onChange); + widget.onMapCreated(controller); startRouteUpdateTimer(); startMarkerUpdateTimer(); } @override void dispose() { - trackTraceController.dispose(); + controller.dispose(); super.dispose(); } @@ -85,8 +88,7 @@ class _GoogleTrackTraceMapState extends State { Widget build(BuildContext context) { return GoogleMap( initialCameraPosition: calculateCameraPosition( - trackTraceController.start.position, - trackTraceController.end.position), + controller.start.position, controller.end.position), onMapCreated: _onMapCreated, compassEnabled: widget.compassEnabled, zoomControlsEnabled: widget.zoomControlsEnabled, @@ -95,22 +97,25 @@ class _GoogleTrackTraceMapState extends State { mapType: widget.mapType, buildingsEnabled: widget.buildingsEnabled, markers: { - // style the markers - trackTraceController.start, - trackTraceController.end, - if (trackTraceController.current != null) - trackTraceController.current!, + controller.start, + controller.end, }, polylines: { - if (route != null) - Polyline( - polylineId: PolylineId(widget.routeLabel), - color: Theme.of(context).primaryColor, - width: 4, - points: route!.polylinePoints - .map((e) => LatLng(e.latitude, e.longitude)) - .toList(), - ), + if (controller.route != null) + (widget.line != null) + ? widget.line!.copyWith( + pointsParam: controller.route!.line + .map((e) => LatLng(e.latitude, e.longitude)) + .toList()) + : Polyline( + // default PolyLine if none is provided + polylineId: const PolylineId('track&trace route'), + color: Theme.of(context).primaryColor, + width: 4, + points: controller.route!.line + .map((e) => LatLng(e.latitude, e.longitude)) + .toList(), + ), }); } @@ -118,11 +123,10 @@ class _GoogleTrackTraceMapState extends State { setState(() {}); } - void _onMapCreated(GoogleMapController controller) { + void _onMapCreated(GoogleMapController ctr) { if (mounted) { - trackTraceController.mapController = controller; - controller.setMapStyle( - '[{"featureType": "poi","stylers": [{"visibility": "off"}]}]'); // move to dart json file + controller.mapController = ctr; + ctr.setMapStyle(widget.mapMarkations); // move to dart json file } } @@ -130,11 +134,26 @@ class _GoogleTrackTraceMapState extends State { LatLng target = LatLng((pointA.latitude + pointB.latitude) / 2, (pointA.longitude + pointB.longitude) / 2); double calculatedZoom = 13.0; // TODO calculate this zoom - + return CameraPosition( target: target, zoom: calculatedZoom, tilt: 0.0, bearing: 0.0); } + CameraUpdate moveCameraToCenter(LatLng pointA, LatLng pointB) { + return CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: LatLng( + min(pointA.latitude, pointB.latitude), + min(pointA.longitude, pointB.longitude), + ), + northeast: LatLng( + max(pointA.latitude, pointB.latitude), + max(pointA.longitude, pointB.longitude), + ), + ), + 50); + } + void startRouteUpdateTimer() { calculateRoute(); // run at the start Timer.periodic(Duration(seconds: widget.routeUpdateInterval), (timer) { @@ -144,37 +163,35 @@ class _GoogleTrackTraceMapState extends State { void startMarkerUpdateTimer() { if (widget.timerPrecision != TimePrecision.updateOnly) { - Timer.periodic( - Duration( - seconds: (widget.timerPrecision == TimePrecision.everyMinute) - ? 60 - : 1), (timer) { - updateDurationTimer(); + int updateInterval = + (widget.timerPrecision == TimePrecision.everyMinute) ? 60 : 1; + Timer.periodic(Duration(seconds: updateInterval), (timer) { + if (controller.route != null) { + controller.route!.duration = + controller.route!.duration - updateInterval; + } }); } } - void updateDurationTimer() { - if (route != null) { - trackTraceController.duration = route!.totalDuration - - DateTime.now().difference(lastRouteUpdate).inSeconds; - } - } - - void calculateRoute() async { - DirectionsRepository() + void calculateRoute() async { + DirectionsRepository() //TODO refactor this away .getDirections( - origin: trackTraceController.start.position, - destination: trackTraceController.end.position, + origin: controller.start.position, + destination: controller.end.position, mode: widget.travelMode, key: widget.googleAPIKey, ) .then((value) => { - trackTraceController.duration = value.totalDuration, - trackTraceController.mapController.moveCamera(CameraUpdate.newCameraPosition(calculateCameraPosition(trackTraceController.start.position, trackTraceController.end.position))), + controller.route = TrackTraceRoute(value.totalDuration, + value.totalDistance, value.polylinePoints), + if (controller.mapController != null) + { + controller.mapController!.moveCamera(moveCameraToCenter( + controller.start.position, controller.end.position)), + }, setState(() { lastRouteUpdate = DateTime.now(); - route = value; }) }); }