Flutter: Get the best ROI with Geolocation and Firebase (Firestore)

Photo by henry perks on Unsplash

The modules used

The database

position: {
geohash : "gbsuv7ztq"
geopoint : [48.668983, -4.329021]
}

The view

GoogleMap(
onCameraIdle: () async {
var region = await mapController.getVisibleRegion()
var zoom = await mapController.getZoomLevel()
var p1 = geo.LatLng(
region.southwest.latitude,
region.southwest.longitude
);
var p2 = geo.LatLng(
region.northeast.latitude,
region.northeast.longitude
);
var center = geo.Geodesy().midPointBetweenTwoGeoPoints(p1, p2);
MyService.getMarkers(
LatLng(center.latitude, center.longitude),
zoom,
(markers) {
// Update the markers
// ..
}
);
},
// ...
)

The service

static int _zoomToPrecision(double zoom) {
if (zoom < 5) return 1;
if (zoom < 7) return 2;
if (zoom < 10) return 3;
if (zoom < 12) return 4;
if (zoom < 15) return 5;
if (zoom < 17) return 6;
else return 7;
}
/// Return the endcode (last char) of the given word.
/// Used to get all documents related to a geohash.
static String _getEndcode(String word) {
int strLength = word.length;
var strFrontCode = word.substring(0, strLength-1);
String strEndCode = word.substring(strLength-1, word.length);

return strFrontCode + String.fromCharCode(
charCodeAt(strEndCode, 0) + 1);
}
static var zonesCache = {
1: Set(), 2: Set(), 3: Set(), 4: Set(), 5: Set(), 6: Set()
};
Figure 1: In red, the neighbours of the region displayed. They are stored in the array “directions”
static const MARKERS_COLLECTION = 'markers';
static const COL_POSITION = 'position';
static const COL_POSITION_HASH = COL_POSITION + '.geohash';
static Future<void> getMarkers(LatLng center, double zoom, Function(List<Marker>) function) async {
int precision = _zoomToPrecision(zoom);
String centerHash = hasher.encode(
center.longitude,
center.latitude,
precision: precision
);
List<String> directions = hasher.neighbors(centerHash)
.values.toList();
// Update cache and directions
_updateCache(precision, directions);
// Retrieve the markers from collection
for (var direction in directions) {
var snapshots = Firestore.instance
.collection(MARKERS_COLLECTION)
.where(
COL_POSITION_HASH,
isGreaterThanOrEqualTo: direction,
isLessThan: _getEndcode(direction)
)
.snapshots();
snapshots.listen((snapshot) {
var markers = _getMarkersFromSnapshot(snapshot);
function(markers)
});
}
}

/// Update the cache and update directions hashes given
/// in parameters
static void _updateCache(int precision, List<String> directions) {
int index = directions.length - 1;
bool stop = false;
for (; index >= 0; index--) {
var hash = directions[index];
for(int i = 1; i <= precision; i++) {
String zoneHash = hash.substring(0, i);
bool containsZoneHash =
zonesCache[i].contains(zoneHash);
if (zoneHash == hash) {
if (!containsZoneHash)
zonesCache[precision].add(hash);
else
directions.removeAt(index);
} else {
if (containsZoneHash) {
directions.clear();
stop = true;
break;
}
}
}
if (stop) break;
}
}
/// Format the snapshot elements to obtain a list of Marker
static List<Marker> _getMarkersFromSnapshot(snapshot) { ... }

Conclusion

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store