-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[google_maps_flutter_web] Add "My Location" Widget #6868
Changes from 26 commits
5f861c5
d9a4fa6
1450b75
03ed666
72b6553
ea3dd73
64668d0
e2a5a24
1ae5172
9abc526
b986d65
c358fe8
278b043
a72e0a1
7ad54b5
e0c6c3d
ea4cdef
1cdce7a
58c74ec
7bd8aa4
1b62e8c
4d6ba54
9d40e2e
f3a8fc9
77414ec
6668606
1b4b0bb
241f69d
c0fff06
1747092
dd51548
c99c506
6c0aecd
cbc6bc2
766d690
d85e6b8
f99bce4
9755380
65630ef
42e307a
0090120
3db8113
9270247
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,10 @@ part of google_maps_flutter_web; | |
| typedef DebugCreateMapFunction = gmaps.GMap Function( | ||
| HtmlElement div, gmaps.MapOptions options); | ||
|
|
||
| /// Type used when passing an override to the _getCurrentLocation function. | ||
| @visibleForTesting | ||
| typedef DebugGetCurrentLocation = Future<LatLng> Function(); | ||
|
|
||
| /// Encapsulates a [gmaps.GMap], its events, and where in the DOM it's rendered. | ||
| class GoogleMapController { | ||
| /// Initializes the GMap, and the sub-controllers related to it. Wires events. | ||
|
|
@@ -64,6 +68,7 @@ class GoogleMapController { | |
| // The Flutter widget that contains the rendered Map. | ||
| HtmlElementView? _widget; | ||
| late HtmlElement _div; | ||
| HtmlElement? _myLocationButton; | ||
|
|
||
| /// The Flutter widget that will contain the rendered Map. Used for caching. | ||
| Widget? get widget { | ||
|
|
@@ -75,6 +80,10 @@ class GoogleMapController { | |
| return _widget; | ||
| } | ||
|
|
||
| /// A getter for the my location button | ||
| @visibleForTesting | ||
| HtmlElement? get myLocationButton => _myLocationButton; | ||
|
|
||
| // The currently-enabled traffic layer. | ||
| gmaps.TrafficLayer? _trafficLayer; | ||
|
|
||
|
|
@@ -114,14 +123,19 @@ class GoogleMapController { | |
| CirclesController? circles, | ||
| PolygonsController? polygons, | ||
| PolylinesController? polylines, | ||
| DebugGetCurrentLocation? getCurrentLocation, | ||
| }) { | ||
| _overrideCreateMap = createMap; | ||
| _markersController = markers ?? _markersController; | ||
| _circlesController = circles ?? _circlesController; | ||
| _polygonsController = polygons ?? _polygonsController; | ||
| _polylinesController = polylines ?? _polylinesController; | ||
| _overrideGetCurrentLocation = getCurrentLocation; | ||
| } | ||
|
|
||
| // Get current location | ||
| DebugGetCurrentLocation? _overrideGetCurrentLocation; | ||
|
|
||
| DebugCreateMapFunction? _overrideCreateMap; | ||
|
|
||
| gmaps.GMap _createMap(HtmlElement div, gmaps.MapOptions options) { | ||
|
|
@@ -163,6 +177,7 @@ class GoogleMapController { | |
|
|
||
| // Create the map... | ||
| final gmaps.GMap map = _createMap(_div, options); | ||
|
|
||
| _googleMap = map; | ||
|
|
||
| _attachMapEvents(map); | ||
|
|
@@ -177,6 +192,14 @@ class GoogleMapController { | |
| ); | ||
|
|
||
| _setTrafficLayer(map, _lastMapConfiguration.trafficEnabled ?? false); | ||
|
|
||
| if ((_lastMapConfiguration.myLocationEnabled ?? false) && | ||
| (_lastMapConfiguration.myLocationButtonEnabled ?? false)) { | ||
| _addMyLocationButton(map); | ||
| } | ||
| if (_lastMapConfiguration.myLocationEnabled ?? false) { | ||
| _moveToCurrentLocation(); | ||
| } | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // Funnels map gmap events into the plugin's stream controller. | ||
|
|
@@ -413,6 +436,113 @@ class GoogleMapController { | |
| return _markersController?.isInfoWindowShown(markerId) ?? false; | ||
| } | ||
|
|
||
| // Add My Location widget to right bottom | ||
| HtmlElement _createMyLocationButton() { | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| final HtmlElement controlDiv = DivElement(); | ||
| controlDiv.style.marginRight = '10px'; | ||
|
|
||
| final HtmlElement firstChild = ButtonElement(); | ||
| firstChild.className = 'gm-control-active'; | ||
| firstChild.style.backgroundColor = '#fff'; | ||
| firstChild.style.border = 'none'; | ||
| firstChild.style.outline = 'none'; | ||
| firstChild.style.width = '40px'; | ||
| firstChild.style.height = '40px'; | ||
| firstChild.style.borderRadius = '2px'; | ||
| firstChild.style.boxShadow = '0 1px 4px rgba(0,0,0,0.3)'; | ||
| firstChild.style.cursor = 'pointer'; | ||
| firstChild.style.padding = '8px'; | ||
| controlDiv.append(firstChild); | ||
|
|
||
| final HtmlElement secondChild = DivElement(); | ||
| secondChild.style.width = '24px'; | ||
| secondChild.style.height = '24px'; | ||
| secondChild.style.backgroundImage = | ||
| 'url(https://maps.gstatic.com/tactile/mylocation/mylocation-sprite-2x.png)'; | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| secondChild.style.backgroundSize = '240px 24px'; | ||
| secondChild.style.backgroundPosition = '0px 0px'; | ||
| secondChild.style.backgroundRepeat = 'no-repeat'; | ||
| secondChild.id = 'you_location_img'; | ||
| firstChild.append(secondChild); | ||
|
|
||
| firstChild.addEventListener('click', (_) { | ||
| String imgX = '0'; | ||
| // Add animation when find current location | ||
| final Timer timer = | ||
| Timer.periodic(const Duration(milliseconds: 500), (_) { | ||
| imgX = (imgX == '-24') ? '0' : '-24'; | ||
| document.getElementById('you_location_img')?.style.backgroundPosition = | ||
| '${imgX}px 0px'; | ||
|
nploi marked this conversation as resolved.
Outdated
nploi marked this conversation as resolved.
Outdated
|
||
| }); | ||
| // Find and move to current location | ||
| _moveToCurrentLocation().then((_) { | ||
| timer.cancel(); | ||
| document.getElementById('you_location_img')?.style.backgroundPosition = | ||
| '-192px 0px'; | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| }); | ||
| }); | ||
|
|
||
| return controlDiv; | ||
| } | ||
|
|
||
| // Get current location | ||
| Future<LatLng> _getCurrentLocation() async { | ||
| final Geoposition location = | ||
| await window.navigator.geolocation.getCurrentPosition(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method will not update the user's location if they move around, unless something else on the map changes. I think this should use the
Some documentation:
|
||
| return LatLng( | ||
| location.coords!.latitude!.toDouble(), | ||
| location.coords!.longitude!.toDouble(), | ||
| ); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two things here:
I think this should at least handle "1" gracefully. 2 can be left as a "todo" or a continuation to this PR.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm fixed "1", but i think i should do "2" in next pr :D |
||
| } | ||
|
|
||
| // Find and move to current location | ||
| Future<void> _moveToCurrentLocation() async { | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| LatLng location; | ||
| if (_overrideGetCurrentLocation != null) { | ||
| location = await _overrideGetCurrentLocation!.call(); | ||
| } else { | ||
| location = await _getCurrentLocation(); | ||
| } | ||
|
|
||
| await moveCamera( | ||
| CameraUpdate.newLatLng(location), | ||
| ); | ||
|
|
||
| _addBlueDotMarker(location); | ||
|
nploi marked this conversation as resolved.
Outdated
|
||
| } | ||
|
|
||
| // Add my location to map | ||
| void _addMyLocationButton(gmaps.GMap map) { | ||
| _myLocationButton = _createMyLocationButton(); | ||
|
|
||
| map.addListener('dragend', () { | ||
| document.getElementById('you_location_img')?.style.backgroundPosition = | ||
| '0px 0px'; | ||
| }); | ||
|
|
||
| map.controls![gmaps.ControlPosition.RIGHT_BOTTOM as int] | ||
| ?.push(_myLocationButton); | ||
| } | ||
|
|
||
| // Add blue dot for current location | ||
| Future<void> _addBlueDotMarker(LatLng location) async { | ||
| assert( | ||
| _markersController != null, 'Cannot update markers after dispose().'); | ||
| final BitmapDescriptor icon = await BitmapDescriptor.fromAssetImage( | ||
| const ImageConfiguration(size: Size(18, 18)), | ||
| 'icons/blue-dot.png', | ||
| package: 'google_maps_flutter_web', | ||
| ); | ||
| _markersController?.addMarkers(<Marker>{ | ||
| Marker( | ||
| markerId: const MarkerId('my_location_blue_dot'), | ||
| icon: icon, | ||
| position: location, | ||
| zIndex: 0.5, | ||
| ) | ||
| }); | ||
| } | ||
|
|
||
| // Cleanup | ||
|
|
||
| /// Disposes of this controller and its resources. | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.