ReactiveGoogleMap class
It creates a data-driven map UI component using Google Maps. It is the key component for building map based experiences. Example uses:
- showing a map of user checkins by city and topics for powering discovery based experiences.
- displaying restaurants filtered by a nearby distance query on a map.
Follow the installation steps mentioned at here.
Example
import 'package:flutter/material.dart';
import 'package:searchbase/searchbase.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'dart:async';
import 'dart:ui';
import 'package:flutter_searchbox/flutter_searchbox.dart';
import 'package:flutter_searchbox_ui/flutter_searchbox_ui.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:dart_geohash/dart_geohash.dart';
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
void main() {
runApp(FlutterSearchBoxUIApp());
}
class FlutterSearchBoxUIApp extends StatelessWidget {
// Avoid creating searchbase instance in build method
// to preserve state on hot reloading
final searchbaseInstance = SearchBase(
'earthquakes',
'https://appbase-demo-ansible-abxiydt-arc.searchbase.io',
'a03a1cb71321:75b6603d-9456-4a5a-af6b-a487b309eb61',
appbaseConfig: AppbaseSettings(
recordAnalytics: true,
// Use unique user id to personalize the recent searches
userId: 'jon@appbase.io'));
FlutterSearchBoxUIApp({Key? key}) : super(key: key);
// Function to build cluster icon
Future<BitmapDescriptor> _getMarkerBitmap(int size, {String? text}) async {
if (kIsWeb) size = (size / 2).floor();
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
final Paint paint1 = Paint()..color = Colors.orange;
final Paint paint2 = Paint()..color = Colors.white;
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.0, paint1);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.2, paint2);
canvas.drawCircle(Offset(size / 2, size / 2), size / 2.8, paint1);
if (text != null) {
TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
painter.text = TextSpan(
text: text,
style: TextStyle(
fontSize: size / 3,
color: Colors.white,
fontWeight: FontWeight.normal),
);
painter.layout();
painter.paint(
canvas,
Offset(size / 2 - painter.width / 2, size / 2 - painter.height / 2),
);
}
final img = await pictureRecorder.endRecording().toImage(size, size);
final data = await img.toByteData(format: ImageByteFormat.png) as ByteData;
return BitmapDescriptor.fromBytes(data.buffer.asUint8List());
}
@override
Widget build(BuildContext context) {
// The SearchBaseProvider should wrap your MaterialApp or WidgetsApp. This will
// ensure all routes have access to the store.
return SearchBaseProvider(
// Pass the searchbase instance to the SearchBaseProvider. Any ancestor `SearchWidgetConnector`
// widgets will find and use this value as the `SearchController`.
searchbase: searchbaseInstance,
child: MaterialApp(
title: "SearchBox Demo",
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(
body: Center(
// A custom UI widget to render a list of results
child: ReactiveGoogleMap(
id: 'result-widget',
// To update markers when magnitude gets changed
react: const {
"and": "range-selector",
},
// initial map center
initialCameraPosition: const CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 4,
),
// To enable markers' clustering
showMarkerClusters: true,
// Build cluster marker
// Here we are displaying the [Marker] icon and text based on the number of items present in a cluster.
buildClusterMarker: (Cluster<Place> cluster) async {
return Marker(
markerId: MarkerId(cluster.getId()),
position: cluster.location,
icon: await _getMarkerBitmap(cluster.isMultiple ? 125 : 75,
text: cluster.isMultiple
? cluster.count.toString()
: cluster.items.first.source?["magnitude"]),
);
},
// To build marker when `showMarkerClusters` is set to `false`
// buildMarker: (Place place) {
// return Marker(
// markerId: MarkerId(place.id), position: place.position);
// },
// Database field mapped to geo points.
dataField: 'location',
// Size of Elasticsearch hits
// We set the `size` as zero because we're using aggregations to build markers.
size: 0,
// Size of Elasticsearch aggregations
aggregationSize: 50,
// To fetch initial results
triggerQueryOnInit: true,
// To update markers when map bounds change
searchAsMove: true,
// Optional: Use a default query to use Elasticsearch `geohash_grid` query.
defaultQuery: (SearchController controller) {
return {
"aggregations": {
"location": {
"geohash_grid": {"field": "location", "precision": 3},
"aggs": {
"top_earthquakes": {
"top_hits": {
"_source": {
"includes": ["magnitude"]
},
"size": 1
}
}
}
},
}
};
},
// Optional: Calculate markers from aggregation data
calculateMarkers: (SearchController controller) {
List<Place> places = [];
for (var bucket
in controller.aggregationData?.raw?["buckets"] ?? []) {
try {
var locationDecode = GeoHash(bucket["key"]);
var source = bucket["top_earthquakes"]?["hits"]?["hits"]?[0]
?["_source"];
places.add(
Place(
id: bucket["key"],
position: LatLng(locationDecode.latitude(),
locationDecode.longitude()),
source: source),
);
} catch (e) {}
}
return places;
},
),
),
),
),
);
}
}
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- ReactiveGoogleMap
Constructors
-
ReactiveGoogleMap({Key? key, required String id, bool showMarkerClusters = true, bool autoCenter = false, bool searchAsMove = false, List<
Place> calculateMarkers(dynamic searchController)?, Marker buildMarker(Place place)?, Future<Marker> buildClusterMarker(Cluster<Place> cluster)?, List<KeysToSubscribe> ? subscribeTo, bool? triggerQueryOnInit, bool? shouldListenForChanges, bool? destroyOnDispose, List<double> levels = const [1, 4.25, 6.75, 8.25, 11.5, 14.5, 16.0, 16.5, 20.0], double extraPercent = 0.5, double? stopClusteringZoom, String? credentials, String? index, String? url, AppbaseSettings? appbaseConfig, TransformRequest? transformRequest, TransformResponse? transformResponse, Map<String, String> ? headers, Map<String, dynamic> ? react, String? queryFormat, dynamic dataField, String? categoryField, String? categoryValue, String? nestedField, int? from, int? size, SortType? sortBy, String? aggregationField, int? aggregationSize, Map? after, bool? includeNullValues, List<String> ? includeFields, List<String> ? excludeFields, dynamic fuzziness, bool? searchOperators, bool? highlight, dynamic highlightField, Map? customHighlight, int? interval, List<String> ? aggregations, String? missingLabel, bool? showMissing, bool? enableSynonyms, String? selectAllLabel, bool? pagination, bool? queryString, Map defaultQuery(dynamic searchController)?, Map customQuery(dynamic searchController)?, Future beforeValueChange(dynamic value)?, void onValueChange(dynamic next, {dynamic prev})?, void onResults(Results next, {Results prev})?, void onAggregationData(Aggregations next, {Aggregations prev})?, void onError(dynamic error)?, void onRequestStatusChange(String next, {String prev})?, void onQueryChange(List<Map> ? next, {List<Map> ? prev})?, bool? enablePopularSuggestions, int? maxPopularSuggestions, bool? showDistinctSuggestions, bool? preserveResults, bool clearOnQueryChange = false, dynamic value, List<Map> ? results, String? distinctField, Map? distinctFieldConfig, Duration httpRequestTimeout = const Duration(seconds: 30), CompoundClauseType? compoundClause, required CameraPosition initialCameraPosition, MapType mapType = MapType.normal, bool compassEnabled = true, MapCreatedCallback? onMapCreated, bool mapToolbarEnabled = true, CameraTargetBounds cameraTargetBounds = CameraTargetBounds.unbounded, MinMaxZoomPreference minMaxZoomPreference = MinMaxZoomPreference.unbounded, bool rotateGesturesEnabled = true, bool scrollGesturesEnabled = true, bool zoomControlsEnabled = true, bool zoomGesturesEnabled = true, bool liteModeEnabled = false, bool tiltGesturesEnabled = true, EdgeInsets padding = const EdgeInsets.all(0), bool myLocationEnabled = false, bool myLocationButtonEnabled = true, bool indoorViewEnabled = false, bool trafficEnabled = false, bool buildingsEnabled = true, Set<Polygon> polygons = const <Polygon>{}, Set<Polyline> polylines = const <Polyline>{}, Set<Circle> circles = const <Circle>{}, VoidCallback? onCameraMoveStarted, Set<TileOverlay> tileOverlays = const <TileOverlay>{}, CameraPositionCallback? onCameraMove, VoidCallback? onCameraIdle, ArgumentCallback<LatLng> ? onTap, ArgumentCallback<LatLng> ? onLongPress, Set<Factory< gestureRecognizers = const <Factory<OneSequenceGestureRecognizer>>{}})OneSequenceGestureRecognizer> >
Properties
- after → Map?
-
This property can be used to implement the pagination for
aggregations
.final - aggregationField → String?
-
It enables you to get
DISTINCT
results (useful when you are dealing with sessions, events, and logs type data).final -
aggregations
→ List<
String> ? -
It helps you to utilize the built-in aggregations for
QueryType.range
type of widgets directly, valid values are:final - aggregationSize → int?
-
To set the number of buckets to be returned by aggregations.
final
- appbaseConfig → AppbaseSettings?
-
It allows you to customize the analytics experience when appbase.io is used as a backend.
final
- autoCenter → bool
-
whether to auto center the map based on the geometric center of all the location markers. Defaults to false.
final
- beforeValueChange → (Future Function(dynamic value)?)
-
It is a callback function which accepts component's future value as a
parameter and returns a Future.
final
-
buildClusterMarker
→ (Future<
Marker> Function(Cluster<Place> cluster)?) -
To draw the marker on Map when
showMarkerClusters
is set totrue
.final - buildingsEnabled → bool
-
Enables or disables showing 3D buildings where available
final
- buildMarker → (Marker Function(Place place)?)
-
To draw the marker on Map when
showMarkerClusters
is not set totrue
.final -
calculateMarkers
→ (List<
Place> Function(dynamic searchController)?) -
The ReactiveGoogleMap component uses the ElasticSearch hits to render the markers, if you wish to override the default markers then ``calculateMarkers` prop is the way.
final
- cameraTargetBounds → CameraTargetBounds
-
Geographical bounding box for the camera target.
final
- categoryField → String?
-
Index field mapped to the category value.
final
- categoryValue → String?
-
This is the selected category value. It is used for informing the search result.
final
-
circles
→ Set<
Circle> -
Circles to be placed on the map.
final
- clearOnQueryChange → bool
-
When set to
true
, the controller's value would get cleared whenever the query of a watcher controller(which is set via react prop) changes.final - compassEnabled → bool
-
True if the map should show a compass when rotated.
final
- compoundClause ↔ CompoundClauseType?
-
Configure whether the DSL query is generated with the compound clause of
CompoundClauseType.must
orCompoundClauseType.filter
. If nothing is passed the default is to useCompoundClauseType.must
. Setting the compound clause to filter allows search engine to cache and allows for higher throughput in cases where scoring isn’t relevant (e.g. term, geo or range type of queries that act as filters on the data)getter/setter pair - credentials → String?
-
Basic Auth credentials if required for authentication purposes.
final
- customHighlight → Map?
-
It can be used to set the custom highlight settings.
final
- customQuery → (Map Function(dynamic searchController)?)
-
It takes SearchController instance as parameter and returns the query to be applied to the dependent widgets by
react
prop, as defined in Elasticsearch Query DSL.final - dataField → dynamic
-
The index field(s) to be connected to the component’s UI view.
final
- defaultQuery → (Map Function(dynamic searchController)?)
-
It is a callback function that takes the SearchController instance as parameter and returns the data query to be applied to the source component, as defined in Elasticsearch Query DSL, which doesn't get leaked to other components.
final
- destroyOnDispose → bool?
-
If set to
false
then after dispose the component will not get removed from seachbase context i.e can actively participate in query generation.final - distinctField → String?
-
This prop returns only the distinct value documents for the specified field.
It is equivalent to the DISTINCT clause in SQL. It internally uses the collapse feature of Elasticsearch.
You can read more about it over here - https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
final
- distinctFieldConfig → Map?
-
This prop allows specifying additional options to the distinctField prop.
Using the allowed DSL, one can specify how to return K distinct values (default value of K=1),
sort them by a specific order, or return a second level of distinct values.
distinctFieldConfig object corresponds to the inner_hits key's DSL.
You can read more about it over here - https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
final
- enablePopularSuggestions → bool?
-
It can be useful to curate search suggestions based on actual search queries that your users are making.
final
- enableSynonyms → bool?
-
This property can be used to control (enable/disable) the synonyms behavior for a particular query.
final
-
excludeFields
→ List<
String> ? -
final
- extraPercent → double
-
Extra percent of markers to be loaded (ex : 0.2 for 20%)
final
- from → int?
-
To define from which page to start the results, it is important to implement pagination.
final
- fuzziness → dynamic
-
Useful for showing the correct results for an incorrect search parameter by taking the fuzziness into account.
final
-
gestureRecognizers
→ Set<
Factory< OneSequenceGestureRecognizer> > -
Which gestures should be consumed by the map.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
-
headers
→ Map<
String, String> ? -
Set custom headers to be sent with each server request as key/value pairs.
final
- highlight → bool?
-
To define whether highlighting should be enabled in the returned results.
final
- highlightField → dynamic
-
If highlighting is enabled, this property allows specifying the fields which should be returned with the matching highlights.
final
- httpRequestTimeout → Duration
-
This prop is used to set the timeout value for HTTP requests.
Defaults to 30 seconds.
final
- id → String
-
A unique identifier of the component, can be referenced in other widgets'
react
prop to reactively update data.final -
includeFields
→ List<
String> ? -
final
- includeNullValues → bool?
-
If you have sparse data or documents or items not having the value in the specified field or mapping, then this prop enables you to show that data.
final
- index → String?
-
Refers to an index of the Elasticsearch cluster.
final
- indoorViewEnabled → bool
-
Enables or disables the indoor view from the map
final
- initialCameraPosition → CameraPosition
-
The initial position of the map's camera.
final
- interval → int?
-
To set the histogram bar interval for
QueryType.range
type of widgets, applicable when aggregations value is set to["histogram"]
.final - key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
-
levels
→ List<
double> -
Zoom levels configuration
final
- liteModeEnabled → bool
-
True if the map view should be in lite mode. Android only.
final
- mapToolbarEnabled → bool
-
True if the map should show a toolbar when you interact with the map. Android only.
final
- mapType → MapType
-
Type of map tiles to be rendered.
final
- maxPopularSuggestions → int?
-
It can be used to configure the size of popular suggestions.
final
- minMaxZoomPreference → MinMaxZoomPreference
-
Preferred bounds for the camera zoom level.
final
- missingLabel → String?
-
It allows you to specify a custom label to show when showMissing is set to
true
.final - myLocationButtonEnabled → bool
-
Enables or disables the my-location button.
final
- myLocationEnabled → bool
-
True if a "My Location" layer should be shown on the map.
final
- nestedField → String?
-
Sets the
nested
field path that allows an array of objects to be indexed in a way that can be queried independently of each other.final - onAggregationData → (void Function(Aggregations next, {Aggregations prev})?)
-
It can be used to listen for the
aggregationData
property changes.final - onCameraIdle → VoidCallback?
-
Called when camera movement has ended, there are no pending
animations and the user has stopped interacting with the map.
final
- onCameraMove → CameraPositionCallback?
-
Called repeatedly as the camera continues to move after an
onCameraMoveStarted call.
final
- onCameraMoveStarted → VoidCallback?
-
Called when the camera starts moving.
final
- onError → (void Function(dynamic error)?)
-
It gets triggered in case of an error occurs while fetching results.
final
-
onLongPress
→ ArgumentCallback<
LatLng> ? -
Called every time a
GoogleMap
is long pressed.final - onMapCreated → MapCreatedCallback?
-
Callback method for when the map is ready to be used.
final
-
onQueryChange
→ (void Function(List<
Map> ? next, {List<Map> ? prev})?) -
It is a callback function which accepts widget's nextQuery and prevQuery as parameters.
final
- onRequestStatusChange → (void Function(String next, {String prev})?)
-
It can be used to listen for the request status changes.
final
- onResults → (void Function(Results next, {Results prev})?)
-
It can be used to listen for the
results
changes.final -
onTap
→ ArgumentCallback<
LatLng> ? -
Called every time a
GoogleMap
is tapped.final - onValueChange → (void Function(dynamic next, {dynamic prev})?)
-
It is called every-time the widget's value changes.
final
- padding → EdgeInsets
-
Padding to be set on map. See https://developers.google.com/maps/documentation/android-sdk/map#map_padding for more details.
final
- pagination → bool?
-
This property allows you to implement the
pagination
forQueryType.term
type of queries.final -
polygons
→ Set<
Polygon> -
Polygons to be placed on the map.
final
-
polylines
→ Set<
Polyline> -
Polylines to be placed on the map.
final
- preserveResults → bool?
-
It set to
true
then it preserves the previously loaded results data that can be used to persist pagination or implement infinite loading.final - queryFormat → String?
-
Sets the query format, can be or or and.
final
- queryString → bool?
-
If set to
true
than it allows you to create a complex search that includes wildcard characters, searches across multiple fields, and more.final -
react
→ Map<
String, dynamic> ? -
It is useful for components whose data view should reactively update when on or more dependent components change their states.
final
-
results
→ List<
Map> ? -
A list of map to pre-populate results with static data.
final
- rotateGesturesEnabled → bool
-
True if the map view should respond to rotate gestures.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- scrollGesturesEnabled → bool
-
True if the map view should respond to scroll gestures.
final
- searchAsMove → bool
-
If set to
true
then it would update the results as the map bounds change. Defaults tofalse
.final - searchOperators → bool?
-
If set to
true
, then you can use special characters in the search query to enable the advanced search.final - selectAllLabel → String?
-
This property allows you to add a new property in the list with a particular value in such a way that
when selected i.e
value
is similar/contains to that label(selectAllLabel
) thenQueryType.term
query will make sure that thefield
exists in theresults
.final - shouldListenForChanges → bool?
-
It can be used to prevent state updates.
final
- showDistinctSuggestions → bool?
-
To display one suggestion per document.
final
- showMarkerClusters → bool
-
Whether to aggregate and form a cluster of nearby markers. Defaults to
false
.final - showMissing → bool?
-
When set to
true
then it also retrieves the aggregations for missing fields.final - size → int?
-
Number of suggestions and results to fetch per request.
final
- sortBy → SortType?
-
Sorts the results by either
SortType.asc
,SortType.desc
orSortType.count
order.final - stopClusteringZoom → double?
-
Zoom level to stop cluster rendering
final
-
subscribeTo
→ List<
KeysToSubscribe> ? -
This property allows to define a list of properties of SearchController class which can trigger the re-build when any changes happen.
final
-
tileOverlays
→ Set<
TileOverlay> -
Tile overlays to be placed on the map.
final
- tiltGesturesEnabled → bool
-
True if the map view should respond to tilt gestures.
final
- trafficEnabled → bool
-
Enables or disables the traffic layer of the map
final
- transformRequest → TransformRequest?
-
Enables transformation of network request before execution.
final
- transformResponse → TransformResponse?
-
Enables transformation of search network response before rendering them.
final
- triggerQueryOnInit → bool?
-
It can be used to prevent the default query execution at the time of initial build.
final
- url → String?
-
URL for the Elasticsearch cluster.
final
- value → dynamic
-
Represents the value for a particular
QueryType
.final - zoomControlsEnabled → bool
-
True if the map view should show zoom controls. This includes two buttons
to zoom in and zoom out. The default value is to show zoom controls.
final
- zoomGesturesEnabled → bool
-
True if the map view should respond to zoom gestures.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → _ReactiveGoogleMapState -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of
DiagnosticsNode
objects describing this node's children.inherited -
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited