Skip to content

Instantly share code, notes, and snippets.

@AmitMY
Last active July 5, 2021 17:13
Show Gist options
  • Save AmitMY/4dbfaf82b159092810252d44dcedec88 to your computer and use it in GitHub Desktop.
Save AmitMY/4dbfaf82b159092810252d44dcedec88 to your computer and use it in GitHub Desktop.
GeoFire angular observable
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import GeoFire from 'geofire';
import { Coordinates } from '../../models/coordinates';
import { Observable } from 'rxjs/Observable';
import Rx from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
export interface GeoFireLocation {
key: string;
coordinates: Coordinates;
distance: number;
}
@Injectable()
export class GeoFireProvider {
private geoFire;
constructor(afDatabase: AngularFireDatabase) {
// geofire is the name of the list of locations
this.geoFire = new GeoFire(afDatabase.list('geofire').$ref);
}
private locationComparer(e1: GeoFireLocation, e2: GeoFireLocation) {
if (e1.distance < e2.distance) {
return -1;
}
if (e1.distance > e2.distance) {
return 1;
}
return 0;
}
private locationOf(element: GeoFireLocation, array: Array<GeoFireLocation>, start?: number, end?: number) {
if (array.length === 0) {
return -1;
}
start = start || 0;
end = end || array.length;
const pivot = (start + end) >> 1; // should be faster than dividing by 2
const c = this.locationComparer(element, array[pivot]);
if (end - start <= 1) {
return c == -1 ? pivot - 1 : pivot;
}
switch (c) {
case -1:
return this.locationOf(element, array, start, pivot);
case 0:
return pivot;
case 1:
return this.locationOf(element, array, pivot, end);
}
}
private insertIntoSortedArray(geoLocation: GeoFireLocation, array: Array<GeoFireLocation>) {
array.splice(this.locationOf(geoLocation, array) + 1, 0, geoLocation);
return array;
}
getAround(center: BehaviorSubject<Coordinates>, radius: number): Observable<Array<GeoFireLocation>> {
console.debug('GeoFireProvider:getAround', center, radius);
const geoQuery = this.geoFire.query({
center: [center.value.latitude, center.value.longitude],
radius
});
center.subscribe(c => {
console.debug('GeoFireProvider:getAround:updateCenter', c);
geoQuery.updateCriteria({
center: [c.latitude, c.longitude],
radius
});
});
let locations: BehaviorSubject<Array<GeoFireLocation>> = new BehaviorSubject<Array<GeoFireLocation>>([]);
geoQuery.on('key_entered', (key, location, distance) => {
locations.next(this.insertIntoSortedArray({
key, distance,
coordinates: {
latitude: location[0],
longitude: location[1]
}
}, locations.getValue()));
});
geoQuery.on('key_exited', (key) => {
locations.next(locations.getValue().filter(location => location.key === key));
});
return Rx.Observable.create((observer: Rx.Observer<Array<GeoFireLocation>>) => {
locations.subscribe(locationsArray => observer.next(locationsArray));
}).finally(() => {
//TODO perform cleanup
//geoQuery.cancel()
});
}
}
@AmitMY
Copy link
Author

AmitMY commented Jul 19, 2017

Works like a charm, just needs to perform cleanup, not on finally, but on a custom method. somehow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment