mirror of
https://github.com/Iconica-Development/flutter_google_track_and_trace.git
synced 2025-05-19 05:03:45 +02:00
update track&trace with bitmaps
This commit is contained in:
parent
38ac7476a5
commit
0f5eb37d1f
11 changed files with 238 additions and 19 deletions
BIN
example/assets/ic_custom_marker.png
Normal file
BIN
example/assets/ic_custom_marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
example/assets/ic_location_on.png
Normal file
BIN
example/assets/ic_location_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
example/assets/profile_picture.png
Normal file
BIN
example/assets/profile_picture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 300 KiB |
|
@ -1,7 +1,9 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:google_track_trace/google_track_trace.dart';
|
||||
|
||||
class TrackTraceDemo extends StatefulWidget {
|
||||
|
@ -16,9 +18,12 @@ class _TrackTraceDemoState extends State<TrackTraceDemo> {
|
|||
int step = 1;
|
||||
int routeLength = 0;
|
||||
late final Timer timer;
|
||||
BitmapDescriptor? startMarkerIcon;
|
||||
BitmapDescriptor? destinationMarkerIcon;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
loadBitmapImages();
|
||||
timer = Timer.periodic(const Duration(seconds: 2), (_) {
|
||||
moveAlongRoute();
|
||||
});
|
||||
|
@ -39,43 +44,56 @@ class _TrackTraceDemoState extends State<TrackTraceDemo> {
|
|||
body: GoogleTrackTraceMap(
|
||||
mapStylingTheme: GoogleTrackTraceMapTheme(
|
||||
themes: [
|
||||
GoogleMapThemeFeature(
|
||||
featureType: 'all',
|
||||
stylers: [
|
||||
{'saturation': '-50'},
|
||||
//{'invert_lightness': 'true'},
|
||||
],
|
||||
),
|
||||
GoogleMapThemeFeature(
|
||||
featureType: 'landscape.natural.landcover',
|
||||
stylers: [
|
||||
{'color': '#00ff00'},
|
||||
],
|
||||
),
|
||||
GoogleMapThemeFeature(
|
||||
featureType: 'poi',
|
||||
stylers: [
|
||||
{'visibility': 'off'},
|
||||
],
|
||||
),
|
||||
GoogleMapThemeFeature(
|
||||
featureType: 'poi.park',
|
||||
stylers: [
|
||||
{'visibility': 'on'},
|
||||
],
|
||||
),
|
||||
GoogleMapThemeFeature(
|
||||
featureType: 'transit',
|
||||
stylers: [
|
||||
{'visibility': 'off'},
|
||||
],
|
||||
),
|
||||
// GoogleMapThemeFeature(
|
||||
// featureType: 'water',
|
||||
// stylers: [
|
||||
// {'color': '#00ff00'}
|
||||
// ],
|
||||
// ),
|
||||
// GoogleMapThemeFeature(
|
||||
// featureType: 'road',
|
||||
// stylers: [
|
||||
// {'color': '#000000'}
|
||||
// ],
|
||||
// )
|
||||
],
|
||||
),
|
||||
startPosition: const Marker(
|
||||
startPosition: Marker(
|
||||
markerId: MarkerId('Start locatie'),
|
||||
anchor: Offset(0.5, 0.5),
|
||||
position: LatLng(52.356057, 4.897540),
|
||||
icon: startMarkerIcon ?? BitmapDescriptor.defaultMarker,
|
||||
),
|
||||
destinationPosition: const Marker(
|
||||
destinationPosition: Marker(
|
||||
markerId: MarkerId('Bestemming Locatie'),
|
||||
anchor: Offset(0.5, 0.5),
|
||||
position: LatLng(52.364709, 4.877157),
|
||||
icon: destinationMarkerIcon ?? BitmapDescriptor.defaultMarker,
|
||||
),
|
||||
buildingsEnabled: false,
|
||||
googleAPIKey: 'AIzaSyDaxZX8TeQeVf5tW-D6A66WLl20arbWV6c',
|
||||
travelMode: TravelMode.walking,
|
||||
mapType: MapType.normal,
|
||||
indoorViewEnabled: false,
|
||||
routeUpdateInterval: Duration(seconds: 30),
|
||||
timerPrecision: TimePrecision.everySecond,
|
||||
zoomGesturesEnabled: true,
|
||||
|
@ -113,6 +131,35 @@ class _TrackTraceDemoState extends State<TrackTraceDemo> {
|
|||
);
|
||||
}
|
||||
|
||||
void loadBitmapImages() {
|
||||
rootBundle.load('assets/profile_picture.png').then((value) {
|
||||
convertBytesToCustomBitmapDescriptor(
|
||||
value.buffer.asUint8List(),
|
||||
size: 80,
|
||||
addBorder: true,
|
||||
borderColor: Colors.grey,
|
||||
title: 'Alex',
|
||||
titleBackgroundColor: Color(0xffff7884),
|
||||
).then((bitmap) {
|
||||
startMarkerIcon = bitmap;
|
||||
BitmapDescriptor.fromAssetImage(
|
||||
ImageConfiguration(size: Size(100, 100)),
|
||||
'assets/ic_location_on.png',
|
||||
).then((value) {
|
||||
setState(() {
|
||||
destinationMarkerIcon = value;
|
||||
controller?.end = Marker(
|
||||
anchor: Offset(0.5, 0.5),
|
||||
markerId: MarkerId('Bestemming Locatie'),
|
||||
position: LatLng(52.364709, 4.877157),
|
||||
icon: value,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void getRandomPointOnMap() {
|
||||
// 51.989909, 6.234950 NW
|
||||
// 51.939909, 6.314950 SE
|
||||
|
@ -133,10 +180,12 @@ class _TrackTraceDemoState extends State<TrackTraceDemo> {
|
|||
controller!.route!.line.length > 1) {
|
||||
controller!.start = Marker(
|
||||
markerId: const MarkerId('Start Locatie'),
|
||||
anchor: Offset(0.5, 0.5),
|
||||
position: LatLng(
|
||||
controller!.route!.line[step].latitude,
|
||||
controller!.route!.line[step].longitude,
|
||||
),
|
||||
icon: startMarkerIcon ?? BitmapDescriptor.defaultMarker,
|
||||
);
|
||||
step++;
|
||||
routeLength = controller!.route!.distance;
|
||||
|
|
|
@ -134,7 +134,7 @@ packages:
|
|||
path: ".."
|
||||
relative: true
|
||||
source: path
|
||||
version: "1.0.0"
|
||||
version: "1.0.1"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -60,7 +60,8 @@ flutter:
|
|||
uses-material-design: true
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
# assets:
|
||||
assets:
|
||||
- assets/
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
|
|
|
@ -4,9 +4,12 @@ import 'dart:async';
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
@ -22,8 +25,8 @@ export 'package:google_maps_flutter/google_maps_flutter.dart'
|
|||
PolylineId,
|
||||
JointType,
|
||||
LatLng;
|
||||
|
||||
part 'src/controller.dart';
|
||||
part 'src/directions_repository.dart';
|
||||
part 'src/google_map.dart';
|
||||
part 'src/google_map_theme.dart';
|
||||
part 'src/marker_generator.dart';
|
||||
|
|
|
@ -163,7 +163,10 @@ class _GoogleTrackTraceMapState extends State<GoogleTrackTraceMap> {
|
|||
if (mounted) {
|
||||
controller.mapController = ctr;
|
||||
if (widget.mapStylingTheme != null) {
|
||||
ctr.setMapStyle(widget.mapStylingTheme!.getJson());
|
||||
ctr.setMapStyle(widget.mapStylingTheme!.getJson()).onError(
|
||||
(error, stackTrace) =>
|
||||
throw GoogleMapsException(error.toString()),
|
||||
);
|
||||
} else {
|
||||
// No theme provided so switching to default
|
||||
ctr.setMapStyle(
|
||||
|
|
|
@ -52,3 +52,7 @@ class GoogleMapThemeFeature {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum GoogleMapThemeFeatureType {
|
||||
featureAll,
|
||||
}
|
||||
|
|
159
lib/src/marker_generator.dart
Normal file
159
lib/src/marker_generator.dart
Normal file
|
@ -0,0 +1,159 @@
|
|||
part of google_track_trace;
|
||||
|
||||
Future<BitmapDescriptor> convertBytesToCustomBitmapDescriptor(
|
||||
Uint8List image, {
|
||||
int size = 150,
|
||||
bool addBorder = false,
|
||||
Color borderColor = Colors.white,
|
||||
double borderSize = 10,
|
||||
String? title,
|
||||
Color titleColor = Colors.white,
|
||||
Color titleBackgroundColor = Colors.black,
|
||||
}) async {
|
||||
var pictureRecorder = ui.PictureRecorder();
|
||||
var canvas = Canvas(pictureRecorder);
|
||||
var paint = Paint()..color;
|
||||
var textPainter = TextPainter(
|
||||
textDirection: TextDirection.ltr,
|
||||
);
|
||||
var radius = size / 2;
|
||||
|
||||
//make canvas clip path to prevent image drawing over the circle
|
||||
var clipPath = Path()
|
||||
..addRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
|
||||
Radius.circular(100),
|
||||
),
|
||||
)
|
||||
..addRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, size * 8 / 10, size.toDouble(), size * 3 / 10),
|
||||
Radius.circular(100),
|
||||
),
|
||||
);
|
||||
canvas.clipPath(clipPath);
|
||||
|
||||
//paintImage
|
||||
var imageUint8List = image;
|
||||
var codec = await ui.instantiateImageCodec(imageUint8List);
|
||||
var imageFI = await codec.getNextFrame();
|
||||
paintImage(
|
||||
canvas: canvas,
|
||||
rect: Rect.fromLTWH(0, 0, size.toDouble(), size.toDouble()),
|
||||
image: imageFI.image,
|
||||
);
|
||||
|
||||
if (addBorder) {
|
||||
//draw Border
|
||||
paint
|
||||
..color = borderColor
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = borderSize;
|
||||
canvas.drawCircle(Offset(radius, radius), radius, paint);
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
var displayedTitle = '';
|
||||
if (title.length > 9) {
|
||||
displayedTitle = title.substring(0, 9);
|
||||
} else {
|
||||
displayedTitle = title;
|
||||
}
|
||||
//draw Title background
|
||||
paint
|
||||
..color = titleBackgroundColor
|
||||
..style = PaintingStyle.fill;
|
||||
canvas.drawRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, size * 8 / 10, size.toDouble(), size * 3 / 10),
|
||||
Radius.circular(100),
|
||||
),
|
||||
paint,
|
||||
);
|
||||
|
||||
//draw Title
|
||||
textPainter
|
||||
..text = TextSpan(
|
||||
text: displayedTitle,
|
||||
style: TextStyle(
|
||||
fontSize: radius / 2.5,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: titleColor,
|
||||
),
|
||||
)
|
||||
..layout()
|
||||
..paint(
|
||||
canvas,
|
||||
Offset(
|
||||
radius - textPainter.width / 2,
|
||||
size * 9.5 / 10 - textPainter.height / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//convert canvas as PNG bytes
|
||||
var _image =
|
||||
await pictureRecorder.endRecording().toImage(size, (size * 1.1).toInt());
|
||||
var data = await _image.toByteData(format: ui.ImageByteFormat.png);
|
||||
|
||||
//convert PNG bytes as BitmapDescriptor
|
||||
return BitmapDescriptor.fromBytes(data!.buffer.asUint8List());
|
||||
}
|
||||
|
||||
/// https://medium.com/@JBXBergDev/how-to-use-googlemap-markers-with-flutter-material-icons-38c4c975e928
|
||||
Future<BitmapDescriptor> createBitmapDescriptorFromIconData(
|
||||
IconData iconData,
|
||||
double markerSize,
|
||||
Color iconColor,
|
||||
Color circleColor,
|
||||
Color backgroundColor,
|
||||
) async {
|
||||
var pictureRecorder = ui.PictureRecorder();
|
||||
//var canvas = Canvas(pictureRecorder);
|
||||
|
||||
//_paintCircleFill(canvas, backgroundColor);
|
||||
//_paintCircleStroke(canvas, circleColor);
|
||||
//_paintIcon(canvas, iconColor, iconData);
|
||||
|
||||
var picture = pictureRecorder.endRecording();
|
||||
var image = await picture.toImage(markerSize.round(), markerSize.round());
|
||||
var bytes = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
|
||||
return BitmapDescriptor.fromBytes(bytes!.buffer.asUint8List());
|
||||
}
|
||||
|
||||
/// Paints the icon background
|
||||
// void _paintCircleFill(Canvas canvas, Color color) {
|
||||
// final paint = Paint()
|
||||
// ..style = PaintingStyle.fill
|
||||
// ..color = color;
|
||||
// canvas.drawCircle(Offset(_circleOffset, _circleOffset),
|
||||
//_fillCircleWidth, paint);
|
||||
// }
|
||||
|
||||
// /// Paints a circle around the icon
|
||||
// void _paintCircleStroke(Canvas canvas, Color color) {
|
||||
// final paint = Paint()
|
||||
// ..style = PaintingStyle.stroke
|
||||
// ..color = color
|
||||
// ..strokeWidth = _circleStrokeWidth;
|
||||
// canvas.drawCircle(Offset(_circleOffset, _circleOffset),
|
||||
//_outlineCircleWidth, paint);
|
||||
// }
|
||||
|
||||
// /// Paints the icon
|
||||
// void _paintIcon(Canvas canvas, Color color, IconData iconData) {
|
||||
// final textPainter = TextPainter(textDirection: TextDirection.ltr);
|
||||
// textPainter.text = TextSpan(
|
||||
// text: String.fromCharCode(iconData.codePoint),
|
||||
// style: TextStyle(
|
||||
// letterSpacing: 0.0,
|
||||
// fontSize: _iconSize,
|
||||
// fontFamily: iconData.fontFamily,
|
||||
// color: color,
|
||||
// )
|
||||
// );
|
||||
// textPainter.layout();
|
||||
// textPainter.paint(canvas, Offset(_iconOffset, _iconOffset));
|
||||
// }
|
|
@ -1,6 +1,6 @@
|
|||
name: google_track_trace
|
||||
description: An Iconica Flutter pluginin for Track & Trace Package
|
||||
version: 1.0.0
|
||||
version: 1.0.1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.14.0 <3.0.0"
|
||||
|
|
Loading…
Reference in a new issue