UNPKG

geofirex

Version:

Realtime Firestore GeoQueries with RxJS

1,461 lines (1,435 loc) 55.8 kB
import { Subject, Observable, combineLatest } from 'rxjs'; import { map, takeUntil, shareReplay, finalize, first } from 'rxjs/operators'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var helpers = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * @module helpers */ /** * Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth. * * @memberof helpers * @type {number} */ exports.earthRadius = 6371008.8; /** * Unit of measurement factors using a spherical (non-ellipsoid) earth radius. * * @memberof helpers * @type {Object} */ exports.factors = { centimeters: exports.earthRadius * 100, centimetres: exports.earthRadius * 100, degrees: exports.earthRadius / 111325, feet: exports.earthRadius * 3.28084, inches: exports.earthRadius * 39.370, kilometers: exports.earthRadius / 1000, kilometres: exports.earthRadius / 1000, meters: exports.earthRadius, metres: exports.earthRadius, miles: exports.earthRadius / 1609.344, millimeters: exports.earthRadius * 1000, millimetres: exports.earthRadius * 1000, nauticalmiles: exports.earthRadius / 1852, radians: 1, yards: exports.earthRadius / 1.0936, }; /** * Units of measurement factors based on 1 meter. * * @memberof helpers * @type {Object} */ exports.unitsFactors = { centimeters: 100, centimetres: 100, degrees: 1 / 111325, feet: 3.28084, inches: 39.370, kilometers: 1 / 1000, kilometres: 1 / 1000, meters: 1, metres: 1, miles: 1 / 1609.344, millimeters: 1000, millimetres: 1000, nauticalmiles: 1 / 1852, radians: 1 / exports.earthRadius, yards: 1 / 1.0936, }; /** * Area of measurement factors based on 1 square meter. * * @memberof helpers * @type {Object} */ exports.areaFactors = { acres: 0.000247105, centimeters: 10000, centimetres: 10000, feet: 10.763910417, inches: 1550.003100006, kilometers: 0.000001, kilometres: 0.000001, meters: 1, metres: 1, miles: 3.86e-7, millimeters: 1000000, millimetres: 1000000, yards: 1.195990046, }; /** * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. * * @name feature * @param {Geometry} geometry input geometry * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature} a GeoJSON Feature * @example * var geometry = { * "type": "Point", * "coordinates": [110, 50] * }; * * var feature = turf.feature(geometry); * * //=feature */ function feature(geom, properties, options) { if (options === void 0) { options = {}; } var feat = { type: "Feature" }; if (options.id === 0 || options.id) { feat.id = options.id; } if (options.bbox) { feat.bbox = options.bbox; } feat.properties = properties || {}; feat.geometry = geom; return feat; } exports.feature = feature; /** * Creates a GeoJSON {@link Geometry} from a Geometry string type & coordinates. * For GeometryCollection type use `helpers.geometryCollection` * * @name geometry * @param {string} type Geometry Type * @param {Array<any>} coordinates Coordinates * @param {Object} [options={}] Optional Parameters * @returns {Geometry} a GeoJSON Geometry * @example * var type = "Point"; * var coordinates = [110, 50]; * var geometry = turf.geometry(type, coordinates); * // => geometry */ function geometry(type, coordinates, options) { switch (type) { case "Point": return point(coordinates).geometry; case "LineString": return lineString(coordinates).geometry; case "Polygon": return polygon(coordinates).geometry; case "MultiPoint": return multiPoint(coordinates).geometry; case "MultiLineString": return multiLineString(coordinates).geometry; case "MultiPolygon": return multiPolygon(coordinates).geometry; default: throw new Error(type + " is invalid"); } } exports.geometry = geometry; /** * Creates a {@link Point} {@link Feature} from a Position. * * @name point * @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees) * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<Point>} a Point feature * @example * var point = turf.point([-75.343, 39.984]); * * //=point */ function point(coordinates, properties, options) { if (options === void 0) { options = {}; } var geom = { type: "Point", coordinates: coordinates, }; return feature(geom, properties, options); } exports.point = point; /** * Creates a {@link Point} {@link FeatureCollection} from an Array of Point coordinates. * * @name points * @param {Array<Array<number>>} coordinates an array of Points * @param {Object} [properties={}] Translate these properties to each Feature * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] * associated with the FeatureCollection * @param {string|number} [options.id] Identifier associated with the FeatureCollection * @returns {FeatureCollection<Point>} Point Feature * @example * var points = turf.points([ * [-75, 39], * [-80, 45], * [-78, 50] * ]); * * //=points */ function points(coordinates, properties, options) { if (options === void 0) { options = {}; } return featureCollection(coordinates.map(function (coords) { return point(coords, properties); }), options); } exports.points = points; /** * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings. * * @name polygon * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<Polygon>} Polygon Feature * @example * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' }); * * //=polygon */ function polygon(coordinates, properties, options) { if (options === void 0) { options = {}; } for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) { var ring = coordinates_1[_i]; if (ring.length < 4) { throw new Error("Each LinearRing of a Polygon must have 4 or more Positions."); } for (var j = 0; j < ring[ring.length - 1].length; j++) { // Check if first point of Polygon contains two numbers if (ring[ring.length - 1][j] !== ring[0][j]) { throw new Error("First and last Position are not equivalent."); } } } var geom = { type: "Polygon", coordinates: coordinates, }; return feature(geom, properties, options); } exports.polygon = polygon; /** * Creates a {@link Polygon} {@link FeatureCollection} from an Array of Polygon coordinates. * * @name polygons * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygon coordinates * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the FeatureCollection * @returns {FeatureCollection<Polygon>} Polygon FeatureCollection * @example * var polygons = turf.polygons([ * [[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], * [[[-15, 42], [-14, 46], [-12, 41], [-17, 44], [-15, 42]]], * ]); * * //=polygons */ function polygons(coordinates, properties, options) { if (options === void 0) { options = {}; } return featureCollection(coordinates.map(function (coords) { return polygon(coords, properties); }), options); } exports.polygons = polygons; /** * Creates a {@link LineString} {@link Feature} from an Array of Positions. * * @name lineString * @param {Array<Array<number>>} coordinates an array of Positions * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<LineString>} LineString Feature * @example * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'}); * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'}); * * //=linestring1 * //=linestring2 */ function lineString(coordinates, properties, options) { if (options === void 0) { options = {}; } if (coordinates.length < 2) { throw new Error("coordinates must be an array of two or more positions"); } var geom = { type: "LineString", coordinates: coordinates, }; return feature(geom, properties, options); } exports.lineString = lineString; /** * Creates a {@link LineString} {@link FeatureCollection} from an Array of LineString coordinates. * * @name lineStrings * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] * associated with the FeatureCollection * @param {string|number} [options.id] Identifier associated with the FeatureCollection * @returns {FeatureCollection<LineString>} LineString FeatureCollection * @example * var linestrings = turf.lineStrings([ * [[-24, 63], [-23, 60], [-25, 65], [-20, 69]], * [[-14, 43], [-13, 40], [-15, 45], [-10, 49]] * ]); * * //=linestrings */ function lineStrings(coordinates, properties, options) { if (options === void 0) { options = {}; } return featureCollection(coordinates.map(function (coords) { return lineString(coords, properties); }), options); } exports.lineStrings = lineStrings; /** * Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}. * * @name featureCollection * @param {Feature[]} features input features * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {FeatureCollection} FeatureCollection of Features * @example * var locationA = turf.point([-75.343, 39.984], {name: 'Location A'}); * var locationB = turf.point([-75.833, 39.284], {name: 'Location B'}); * var locationC = turf.point([-75.534, 39.123], {name: 'Location C'}); * * var collection = turf.featureCollection([ * locationA, * locationB, * locationC * ]); * * //=collection */ function featureCollection(features, options) { if (options === void 0) { options = {}; } var fc = { type: "FeatureCollection" }; if (options.id) { fc.id = options.id; } if (options.bbox) { fc.bbox = options.bbox; } fc.features = features; return fc; } exports.featureCollection = featureCollection; /** * Creates a {@link Feature<MultiLineString>} based on a * coordinate array. Properties can be added optionally. * * @name multiLineString * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<MultiLineString>} a MultiLineString feature * @throws {Error} if no coordinates are passed * @example * var multiLine = turf.multiLineString([[[0,0],[10,10]]]); * * //=multiLine */ function multiLineString(coordinates, properties, options) { if (options === void 0) { options = {}; } var geom = { type: "MultiLineString", coordinates: coordinates, }; return feature(geom, properties, options); } exports.multiLineString = multiLineString; /** * Creates a {@link Feature<MultiPoint>} based on a * coordinate array. Properties can be added optionally. * * @name multiPoint * @param {Array<Array<number>>} coordinates an array of Positions * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<MultiPoint>} a MultiPoint feature * @throws {Error} if no coordinates are passed * @example * var multiPt = turf.multiPoint([[0,0],[10,10]]); * * //=multiPt */ function multiPoint(coordinates, properties, options) { if (options === void 0) { options = {}; } var geom = { type: "MultiPoint", coordinates: coordinates, }; return feature(geom, properties, options); } exports.multiPoint = multiPoint; /** * Creates a {@link Feature<MultiPolygon>} based on a * coordinate array. Properties can be added optionally. * * @name multiPolygon * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<MultiPolygon>} a multipolygon feature * @throws {Error} if no coordinates are passed * @example * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]); * * //=multiPoly * */ function multiPolygon(coordinates, properties, options) { if (options === void 0) { options = {}; } var geom = { type: "MultiPolygon", coordinates: coordinates, }; return feature(geom, properties, options); } exports.multiPolygon = multiPolygon; /** * Creates a {@link Feature<GeometryCollection>} based on a * coordinate array. Properties can be added optionally. * * @name geometryCollection * @param {Array<Geometry>} geometries an array of GeoJSON Geometries * @param {Object} [properties={}] an Object of key-value pairs to add as properties * @param {Object} [options={}] Optional Parameters * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature * @param {string|number} [options.id] Identifier associated with the Feature * @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature * @example * var pt = turf.geometry("Point", [100, 0]); * var line = turf.geometry("LineString", [[101, 0], [102, 1]]); * var collection = turf.geometryCollection([pt, line]); * * // => collection */ function geometryCollection(geometries, properties, options) { if (options === void 0) { options = {}; } var geom = { type: "GeometryCollection", geometries: geometries, }; return feature(geom, properties, options); } exports.geometryCollection = geometryCollection; /** * Round number to precision * * @param {number} num Number * @param {number} [precision=0] Precision * @returns {number} rounded number * @example * turf.round(120.4321) * //=120 * * turf.round(120.4321, 2) * //=120.43 */ function round(num, precision) { if (precision === void 0) { precision = 0; } if (precision && !(precision >= 0)) { throw new Error("precision must be a positive number"); } var multiplier = Math.pow(10, precision || 0); return Math.round(num * multiplier) / multiplier; } exports.round = round; /** * Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit. * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet * * @name radiansToLength * @param {number} radians in radians across the sphere * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres, * meters, kilometres, kilometers. * @returns {number} distance */ function radiansToLength(radians, units) { if (units === void 0) { units = "kilometers"; } var factor = exports.factors[units]; if (!factor) { throw new Error(units + " units is invalid"); } return radians * factor; } exports.radiansToLength = radiansToLength; /** * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet * * @name lengthToRadians * @param {number} distance in real units * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres, * meters, kilometres, kilometers. * @returns {number} radians */ function lengthToRadians(distance, units) { if (units === void 0) { units = "kilometers"; } var factor = exports.factors[units]; if (!factor) { throw new Error(units + " units is invalid"); } return distance / factor; } exports.lengthToRadians = lengthToRadians; /** * Convert a distance measurement (assuming a spherical Earth) from a real-world unit into degrees * Valid units: miles, nauticalmiles, inches, yards, meters, metres, centimeters, kilometres, feet * * @name lengthToDegrees * @param {number} distance in real units * @param {string} [units="kilometers"] can be degrees, radians, miles, or kilometers inches, yards, metres, * meters, kilometres, kilometers. * @returns {number} degrees */ function lengthToDegrees(distance, units) { return radiansToDegrees(lengthToRadians(distance, units)); } exports.lengthToDegrees = lengthToDegrees; /** * Converts any bearing angle from the north line direction (positive clockwise) * and returns an angle between 0-360 degrees (positive clockwise), 0 being the north line * * @name bearingToAzimuth * @param {number} bearing angle, between -180 and +180 degrees * @returns {number} angle between 0 and 360 degrees */ function bearingToAzimuth(bearing) { var angle = bearing % 360; if (angle < 0) { angle += 360; } return angle; } exports.bearingToAzimuth = bearingToAzimuth; /** * Converts an angle in radians to degrees * * @name radiansToDegrees * @param {number} radians angle in radians * @returns {number} degrees between 0 and 360 degrees */ function radiansToDegrees(radians) { var degrees = radians % (2 * Math.PI); return degrees * 180 / Math.PI; } exports.radiansToDegrees = radiansToDegrees; /** * Converts an angle in degrees to radians * * @name degreesToRadians * @param {number} degrees angle between 0 and 360 degrees * @returns {number} angle in radians */ function degreesToRadians(degrees) { var radians = degrees % 360; return radians * Math.PI / 180; } exports.degreesToRadians = degreesToRadians; /** * Converts a length to the requested unit. * Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet * * @param {number} length to be converted * @param {Units} [originalUnit="kilometers"] of the length * @param {Units} [finalUnit="kilometers"] returned unit * @returns {number} the converted length */ function convertLength(length, originalUnit, finalUnit) { if (originalUnit === void 0) { originalUnit = "kilometers"; } if (finalUnit === void 0) { finalUnit = "kilometers"; } if (!(length >= 0)) { throw new Error("length must be a positive number"); } return radiansToLength(lengthToRadians(length, originalUnit), finalUnit); } exports.convertLength = convertLength; /** * Converts a area to the requested unit. * Valid units: kilometers, kilometres, meters, metres, centimetres, millimeters, acres, miles, yards, feet, inches * @param {number} area to be converted * @param {Units} [originalUnit="meters"] of the distance * @param {Units} [finalUnit="kilometers"] returned unit * @returns {number} the converted distance */ function convertArea(area, originalUnit, finalUnit) { if (originalUnit === void 0) { originalUnit = "meters"; } if (finalUnit === void 0) { finalUnit = "kilometers"; } if (!(area >= 0)) { throw new Error("area must be a positive number"); } var startFactor = exports.areaFactors[originalUnit]; if (!startFactor) { throw new Error("invalid original units"); } var finalFactor = exports.areaFactors[finalUnit]; if (!finalFactor) { throw new Error("invalid final units"); } return (area / startFactor) * finalFactor; } exports.convertArea = convertArea; /** * isNumber * * @param {*} num Number to validate * @returns {boolean} true/false * @example * turf.isNumber(123) * //=true * turf.isNumber('foo') * //=false */ function isNumber(num) { return !isNaN(num) && num !== null && !Array.isArray(num) && !/^\s*$/.test(num); } exports.isNumber = isNumber; /** * isObject * * @param {*} input variable to validate * @returns {boolean} true/false * @example * turf.isObject({elevation: 10}) * //=true * turf.isObject('foo') * //=false */ function isObject(input) { return (!!input) && (input.constructor === Object); } exports.isObject = isObject; /** * Validate BBox * * @private * @param {Array<number>} bbox BBox to validate * @returns {void} * @throws Error if BBox is not valid * @example * validateBBox([-180, -40, 110, 50]) * //=OK * validateBBox([-180, -40]) * //=Error * validateBBox('Foo') * //=Error * validateBBox(5) * //=Error * validateBBox(null) * //=Error * validateBBox(undefined) * //=Error */ function validateBBox(bbox) { if (!bbox) { throw new Error("bbox is required"); } if (!Array.isArray(bbox)) { throw new Error("bbox must be an Array"); } if (bbox.length !== 4 && bbox.length !== 6) { throw new Error("bbox must be an Array of 4 or 6 numbers"); } bbox.forEach(function (num) { if (!isNumber(num)) { throw new Error("bbox must only contain numbers"); } }); } exports.validateBBox = validateBBox; /** * Validate Id * * @private * @param {string|number} id Id to validate * @returns {void} * @throws Error if Id is not valid * @example * validateId([-180, -40, 110, 50]) * //=Error * validateId([-180, -40]) * //=Error * validateId('Foo') * //=OK * validateId(5) * //=OK * validateId(null) * //=Error * validateId(undefined) * //=Error */ function validateId(id) { if (!id) { throw new Error("id is required"); } if (["string", "number"].indexOf(typeof id) === -1) { throw new Error("id must be a number or a string"); } } exports.validateId = validateId; // Deprecated methods function radians2degrees() { throw new Error("method has been renamed to `radiansToDegrees`"); } exports.radians2degrees = radians2degrees; function degrees2radians() { throw new Error("method has been renamed to `degreesToRadians`"); } exports.degrees2radians = degrees2radians; function distanceToDegrees() { throw new Error("method has been renamed to `lengthToDegrees`"); } exports.distanceToDegrees = distanceToDegrees; function distanceToRadians() { throw new Error("method has been renamed to `lengthToRadians`"); } exports.distanceToRadians = distanceToRadians; function radiansToDistance() { throw new Error("method has been renamed to `radiansToLength`"); } exports.radiansToDistance = radiansToDistance; function bearingToAngle() { throw new Error("method has been renamed to `bearingToAzimuth`"); } exports.bearingToAngle = bearingToAngle; function convertDistance() { throw new Error("method has been renamed to `convertLength`"); } exports.convertDistance = convertDistance; }); var index = unwrapExports(helpers); var helpers_1 = helpers.earthRadius; var helpers_2 = helpers.factors; var helpers_3 = helpers.unitsFactors; var helpers_4 = helpers.areaFactors; var helpers_5 = helpers.feature; var helpers_6 = helpers.geometry; var helpers_7 = helpers.point; var helpers_8 = helpers.points; var helpers_9 = helpers.polygon; var helpers_10 = helpers.polygons; var helpers_11 = helpers.lineString; var helpers_12 = helpers.lineStrings; var helpers_13 = helpers.featureCollection; var helpers_14 = helpers.multiLineString; var helpers_15 = helpers.multiPoint; var helpers_16 = helpers.multiPolygon; var helpers_17 = helpers.geometryCollection; var helpers_18 = helpers.round; var helpers_19 = helpers.radiansToLength; var helpers_20 = helpers.lengthToRadians; var helpers_21 = helpers.lengthToDegrees; var helpers_22 = helpers.bearingToAzimuth; var helpers_23 = helpers.radiansToDegrees; var helpers_24 = helpers.degreesToRadians; var helpers_25 = helpers.convertLength; var helpers_26 = helpers.convertArea; var helpers_27 = helpers.isNumber; var helpers_28 = helpers.isObject; var helpers_29 = helpers.validateBBox; var helpers_30 = helpers.validateId; var helpers_31 = helpers.radians2degrees; var helpers_32 = helpers.degrees2radians; var helpers_33 = helpers.distanceToDegrees; var helpers_34 = helpers.distanceToRadians; var helpers_35 = helpers.radiansToDistance; var helpers_36 = helpers.bearingToAngle; var helpers_37 = helpers.convertDistance; var helpers$1 = /*#__PURE__*/Object.freeze({ __proto__: null, 'default': index, __moduleExports: helpers, earthRadius: helpers_1, factors: helpers_2, unitsFactors: helpers_3, areaFactors: helpers_4, feature: helpers_5, geometry: helpers_6, point: helpers_7, points: helpers_8, polygon: helpers_9, polygons: helpers_10, lineString: helpers_11, lineStrings: helpers_12, featureCollection: helpers_13, multiLineString: helpers_14, multiPoint: helpers_15, multiPolygon: helpers_16, geometryCollection: helpers_17, round: helpers_18, radiansToLength: helpers_19, lengthToRadians: helpers_20, lengthToDegrees: helpers_21, bearingToAzimuth: helpers_22, radiansToDegrees: helpers_23, degreesToRadians: helpers_24, convertLength: helpers_25, convertArea: helpers_26, isNumber: helpers_27, isObject: helpers_28, validateBBox: helpers_29, validateId: helpers_30, radians2degrees: helpers_31, degrees2radians: helpers_32, distanceToDegrees: helpers_33, distanceToRadians: helpers_34, radiansToDistance: helpers_35, bearingToAngle: helpers_36, convertDistance: helpers_37 }); var helpers_1$1 = ( helpers$1 && index ) || helpers$1; var invariant = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); /** * Unwrap a coordinate from a Point Feature, Geometry or a single coordinate. * * @name getCoord * @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers * @returns {Array<number>} coordinates * @example * var pt = turf.point([10, 10]); * * var coord = turf.getCoord(pt); * //= [10, 10] */ function getCoord(coord) { if (!coord) { throw new Error("coord is required"); } if (!Array.isArray(coord)) { if (coord.type === "Feature" && coord.geometry !== null && coord.geometry.type === "Point") { return coord.geometry.coordinates; } if (coord.type === "Point") { return coord.coordinates; } } if (Array.isArray(coord) && coord.length >= 2 && !Array.isArray(coord[0]) && !Array.isArray(coord[1])) { return coord; } throw new Error("coord must be GeoJSON Point or an Array of numbers"); } exports.getCoord = getCoord; /** * Unwrap coordinates from a Feature, Geometry Object or an Array * * @name getCoords * @param {Array<any>|Geometry|Feature} coords Feature, Geometry Object or an Array * @returns {Array<any>} coordinates * @example * var poly = turf.polygon([[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]]); * * var coords = turf.getCoords(poly); * //= [[[119.32, -8.7], [119.55, -8.69], [119.51, -8.54], [119.32, -8.7]]] */ function getCoords(coords) { if (Array.isArray(coords)) { return coords; } // Feature if (coords.type === "Feature") { if (coords.geometry !== null) { return coords.geometry.coordinates; } } else { // Geometry if (coords.coordinates) { return coords.coordinates; } } throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array"); } exports.getCoords = getCoords; /** * Checks if coordinates contains a number * * @name containsNumber * @param {Array<any>} coordinates GeoJSON Coordinates * @returns {boolean} true if Array contains a number */ function containsNumber(coordinates) { if (coordinates.length > 1 && helpers_1$1.isNumber(coordinates[0]) && helpers_1$1.isNumber(coordinates[1])) { return true; } if (Array.isArray(coordinates[0]) && coordinates[0].length) { return containsNumber(coordinates[0]); } throw new Error("coordinates must only contain numbers"); } exports.containsNumber = containsNumber; /** * Enforce expectations about types of GeoJSON objects for Turf. * * @name geojsonType * @param {GeoJSON} value any GeoJSON object * @param {string} type expected GeoJSON type * @param {string} name name of calling function * @throws {Error} if value is not the expected type. */ function geojsonType(value, type, name) { if (!type || !name) { throw new Error("type and name required"); } if (!value || value.type !== type) { throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + value.type); } } exports.geojsonType = geojsonType; /** * Enforce expectations about types of {@link Feature} inputs for Turf. * Internally this uses {@link geojsonType} to judge geometry types. * * @name featureOf * @param {Feature} feature a feature with an expected geometry type * @param {string} type expected GeoJSON type * @param {string} name name of calling function * @throws {Error} error if value is not the expected type. */ function featureOf(feature, type, name) { if (!feature) { throw new Error("No feature passed"); } if (!name) { throw new Error(".featureOf() requires a name"); } if (!feature || feature.type !== "Feature" || !feature.geometry) { throw new Error("Invalid input to " + name + ", Feature with geometry required"); } if (!feature.geometry || feature.geometry.type !== type) { throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type); } } exports.featureOf = featureOf; /** * Enforce expectations about types of {@link FeatureCollection} inputs for Turf. * Internally this uses {@link geojsonType} to judge geometry types. * * @name collectionOf * @param {FeatureCollection} featureCollection a FeatureCollection for which features will be judged * @param {string} type expected GeoJSON type * @param {string} name name of calling function * @throws {Error} if value is not the expected type. */ function collectionOf(featureCollection, type, name) { if (!featureCollection) { throw new Error("No featureCollection passed"); } if (!name) { throw new Error(".collectionOf() requires a name"); } if (!featureCollection || featureCollection.type !== "FeatureCollection") { throw new Error("Invalid input to " + name + ", FeatureCollection required"); } for (var _i = 0, _a = featureCollection.features; _i < _a.length; _i++) { var feature = _a[_i]; if (!feature || feature.type !== "Feature" || !feature.geometry) { throw new Error("Invalid input to " + name + ", Feature with geometry required"); } if (!feature.geometry || feature.geometry.type !== type) { throw new Error("Invalid input to " + name + ": must be a " + type + ", given " + feature.geometry.type); } } } exports.collectionOf = collectionOf; /** * Get Geometry from Feature or Geometry Object * * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object * @returns {Geometry|null} GeoJSON Geometry Object * @throws {Error} if geojson is not a Feature or Geometry Object * @example * var point = { * "type": "Feature", * "properties": {}, * "geometry": { * "type": "Point", * "coordinates": [110, 40] * } * } * var geom = turf.getGeom(point) * //={"type": "Point", "coordinates": [110, 40]} */ function getGeom(geojson) { if (geojson.type === "Feature") { return geojson.geometry; } return geojson; } exports.getGeom = getGeom; /** * Get GeoJSON object's type, Geometry type is prioritize. * * @param {GeoJSON} geojson GeoJSON object * @param {string} [name="geojson"] name of the variable to display in error message * @returns {string} GeoJSON type * @example * var point = { * "type": "Feature", * "properties": {}, * "geometry": { * "type": "Point", * "coordinates": [110, 40] * } * } * var geom = turf.getType(point) * //="Point" */ function getType(geojson, name) { if (geojson.type === "FeatureCollection") { return "FeatureCollection"; } if (geojson.type === "GeometryCollection") { return "GeometryCollection"; } if (geojson.type === "Feature" && geojson.geometry !== null) { return geojson.geometry.type; } return geojson.type; } exports.getType = getType; }); var index$1 = unwrapExports(invariant); var invariant_1 = invariant.getCoord; var invariant_2 = invariant.getCoords; var invariant_3 = invariant.containsNumber; var invariant_4 = invariant.geojsonType; var invariant_5 = invariant.featureOf; var invariant_6 = invariant.collectionOf; var invariant_7 = invariant.getGeom; var invariant_8 = invariant.getType; var invariant$1 = /*#__PURE__*/Object.freeze({ __proto__: null, 'default': index$1, __moduleExports: invariant, getCoord: invariant_1, getCoords: invariant_2, containsNumber: invariant_3, geojsonType: invariant_4, featureOf: invariant_5, collectionOf: invariant_6, getGeom: invariant_7, getType: invariant_8 }); var invariant_1$1 = ( invariant$1 && index$1 ) || invariant$1; var C__Users_jeffd23_apps_geofirex_node_modules__turf_distance = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); //http://en.wikipedia.org/wiki/Haversine_formula //http://www.movable-type.co.uk/scripts/latlong.html /** * Calculates the distance between two {@link Point|points} in degrees, radians, miles, or kilometers. * This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. * * @name distance * @param {Coord} from origin point * @param {Coord} to destination point * @param {Object} [options={}] Optional parameters * @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers * @returns {number} distance between the two points * @example * var from = turf.point([-75.343, 39.984]); * var to = turf.point([-75.534, 39.123]); * var options = {units: 'miles'}; * * var distance = turf.distance(from, to, options); * * //addToMap * var addToMap = [from, to]; * from.properties.distance = distance; * to.properties.distance = distance; */ function distance(from, to, options) { if (options === void 0) { options = {}; } var coordinates1 = invariant_1$1.getCoord(from); var coordinates2 = invariant_1$1.getCoord(to); var dLat = helpers_1$1.degreesToRadians((coordinates2[1] - coordinates1[1])); var dLon = helpers_1$1.degreesToRadians((coordinates2[0] - coordinates1[0])); var lat1 = helpers_1$1.degreesToRadians(coordinates1[1]); var lat2 = helpers_1$1.degreesToRadians(coordinates2[1]); var a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); return helpers_1$1.radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), options.units); } exports.default = distance; }); var turfDistance = unwrapExports(C__Users_jeffd23_apps_geofirex_node_modules__turf_distance); var bearing_1 = createCommonjsModule(function (module, exports) { Object.defineProperty(exports, "__esModule", { value: true }); // http://en.wikipedia.org/wiki/Haversine_formula // http://www.movable-type.co.uk/scripts/latlong.html /** * Takes two {@link Point|points} and finds the geographic bearing between them, * i.e. the angle measured in degrees from the north line (0 degrees) * * @name bearing * @param {Coord} start starting Point * @param {Coord} end ending Point * @param {Object} [options={}] Optional parameters * @param {boolean} [options.final=false] calculates the final bearing if true * @returns {number} bearing in decimal degrees, between -180 and 180 degrees (positive clockwise) * @example * var point1 = turf.point([-75.343, 39.984]); * var point2 = turf.point([-75.534, 39.123]); * * var bearing = turf.bearing(point1, point2); * * //addToMap * var addToMap = [point1, point2] * point1.properties['marker-color'] = '#f00' * point2.properties['marker-color'] = '#0f0' * point1.properties.bearing = bearing */ function bearing(start, end, options) { if (options === void 0) { options = {}; } // Reverse calculation if (options.final === true) { return calculateFinalBearing(start, end); } var coordinates1 = invariant_1$1.getCoord(start); var coordinates2 = invariant_1$1.getCoord(end); var lon1 = helpers_1$1.degreesToRadians(coordinates1[0]); var lon2 = helpers_1$1.degreesToRadians(coordinates2[0]); var lat1 = helpers_1$1.degreesToRadians(coordinates1[1]); var lat2 = helpers_1$1.degreesToRadians(coordinates2[1]); var a = Math.sin(lon2 - lon1) * Math.cos(lat2); var b = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); return helpers_1$1.radiansToDegrees(Math.atan2(a, b)); } /** * Calculates Final Bearing * * @private * @param {Coord} start starting Point * @param {Coord} end ending Point * @returns {number} bearing */ function calculateFinalBearing(start, end) { // Swap start & end var bear = bearing(end, start); bear = (bear + 180) % 360; return bear; } exports.default = bearing; }); var turfBearing = unwrapExports(bearing_1); function distance(from, to) { return turfDistance(toGeoJSONFeature(from), toGeoJSONFeature(to)); } function bearing(from, to) { return turfBearing(toGeoJSONFeature(from), toGeoJSONFeature(to)); } function toGeoJSONFeature(coordinates, props) { coordinates = flip(coordinates); return { type: 'Feature', geometry: { type: 'Point', coordinates: coordinates }, properties: props }; } function flip(arr) { return [arr[1], arr[0]]; } function setPrecsion(km) { switch (true) { case km <= 0.00477: return 9; case km <= 0.0382: return 8; case km <= 0.153: return 7; case km <= 1.22: return 6; case km <= 4.89: return 5; case km <= 39.1: return 4; case km <= 156: return 3; case km <= 1250: return 2; default: return 1; } // 1 ≤ 5,000km × 5,000km // 2 ≤ 1,250km × 625km // 3 ≤ 156km × 156km // 4 ≤ 39.1km × 19.5km // 5 ≤ 4.89km × 4.89km // 6 ≤ 1.22km × 0.61km // 7 ≤ 153m × 153m // 8 ≤ 38.2m × 19.1m // 9 ≤ 4.77m × 4.77m } /////// NGEOHASH //////// var BASE32_CODES = '0123456789bcdefghjkmnpqrstuvwxyz'; var BASE32_CODES_DICT = {}; for (var i = 0; i < BASE32_CODES.length; i++) { BASE32_CODES_DICT[BASE32_CODES.charAt(i)] = i; } var ENCODE_AUTO = 'auto'; /** * Significant Figure Hash Length * * This is a quick and dirty lookup to figure out how long our hash * should be in order to guarantee a certain amount of trailing * significant figures. This was calculated by determining the error: * 45/2^(n-1) where n is the number of bits for a latitude or * longitude. Key is # of desired sig figs, value is minimum length of * the geohash. * @type Array */ // Desired sig figs: 0 1 2 3 4 5 6 7 8 9 10 var SIGFIG_HASH_LENGTH = [0, 5, 7, 8, 11, 12, 13, 15, 16, 17, 18]; /** * Encode * * Create a Geohash out of a latitude and longitude that is * `numberOfChars` long. * * @param {Number|String} latitude * @param {Number|String} longitude * @param {Number} numberOfChars * @returns {String} */ var encode = function (latitude, longitude, numberOfChars) { if (numberOfChars === ENCODE_AUTO) { if (typeof latitude === 'number' || typeof longitude === 'number') { throw new Error('string notation required for auto precision.'); } var decSigFigsLat = latitude.split('.')[1].length; var decSigFigsLong = longitude.split('.')[1].length; var numberOfSigFigs = Math.max(decSigFigsLat, decSigFigsLong); numberOfChars = SIGFIG_HASH_LENGTH[numberOfSigFigs]; } else if (numberOfChars === undefined) { numberOfChars = 9; } var chars = [], bits = 0, bitsTotal = 0, hash_value = 0, maxLat = 90, minLat = -90, maxLon = 180, minLon = -180, mid; while (chars.length < numberOfChars) { if (bitsTotal % 2 === 0) { mid = (maxLon + minLon) / 2; if (longitude > mid) { hash_value = (hash_value << 1) + 1; minLon = mid; } else { hash_value = (hash_value << 1) + 0; maxLon = mid; } } else { mid = (maxLat + minLat) / 2; if (latitude > mid) { hash_value = (hash_value << 1) + 1; minLat = mid; } else { hash_value = (hash_value << 1) + 0; maxLat = mid; } } bits++; bitsTotal++; if (bits === 5) { var code = BASE32_CODES[hash_value]; chars.push(code); bits = 0; hash_value = 0; } } return chars.join(''); }; /** * Decode Bounding Box * * Decode hashString into a bound box matches it. Data returned in a four-element array: [minlat, minlon, maxlat, maxlon] * @param {String} hash_string * @returns {Array} */ var decode_bbox = function (hash_string) { var isLon = true, maxLat = 90, minLat = -90, maxLon = 180, minLon = -180, mid; var hashValue = 0; for (var i = 0, l = hash_string.length; i < l; i++) { var code = hash_string[i].toLowerCase(); hashValue = BASE32_CODES_DICT[code]; for (var bits = 4; bits >= 0; bits--) { var bit = (hashValue >> bits) & 1; if (isLon) { mid = (maxLon + minLon) / 2; if (bit === 1) { minLon = mid; } else { maxLon = mid; } } else { mid = (maxLat + minLat) / 2; if (bit === 1) { minLat = mid; } else { maxLat = mid; } } isLon = !isLon; } } return [minLat, minLon, maxLat, maxLon]; }; /** * Decode * * Decode a hash string into pair of latitude and longitude. A javascript object is returned with keys `latitude`, * `longitude` and `error`. * @param {String} hashString * @returns {Object} */ var decode = function (hashString) { var bbox = decode_bbox(hashString); var lat = (bbox[0] + bbox[2]) / 2; var lon = (bbox[1] + bbox[3]) / 2; var latErr = bbox[2] - lat; var lonErr = bbox[3] - lon; return { latitude: lat, longitude: lon, error: { latitude: latErr, longitude: lonErr } }; }; /** * Neighbors * * Returns all neighbors' hashstrings clockwise from north around to northwest * 7 0 1 * 6 x 2 * 5 4 3 * @param {String} hash_string * @returns {encoded neighborHashList|Array} */ var neighbors = function (hash_string) { var hashstringLength = hash_string.length; var lonlat = decode(hash_string); var lat = lonlat.latitude; var lon = lonlat.longitude; var latErr = lonlat.error.latitude * 2; var lonErr = lonlat.error.longitude * 2; var neighbor_lat, neighbor_lon; var neighborHashList = [ encodeNeighbor(1, 0), encodeNeighbor(1, 1), encodeNeighbor(0, 1), encodeNeighbor(-1, 1), encodeNeighbor(-1, 0), encodeNeighbor(-1, -1), encodeNeighbor(0, -1), encodeNeighbor(1, -1) ]; function encodeNeighbor(neighborLatDir, neighborLonDir) { neighbor_lat = lat + neighborLatDir * latErr; neighbor_lon = lon + neighborLonDir * lonErr; return encode(neighbor_lat, neighbor_lon, hashstringLength); } return neighborHashList; }; // import { firestore } from './interfaces'; var defaultOpts = { units: 'km', log: false }; var GeoFireQuery = /** @class */ (function () { function GeoFireQuery(app, ref) { this.app = app; this.ref = ref; if (typeof ref === 'string') { this.ref = this.app.firestore().collection(ref); } } // GEO QUERIES /** * Queries the Firestore collection based on geograpic radius * @param {FirePoint} center the starting point for the query, i.e gfx.point(lat, lng) * @param {number} radius the radius to search from the centerpoint * @param {string} field the document field that contains the FirePoint data * @param {GeoQueryOptions} opts=defaultOpts * @returns {Observable<GeoQueryDocument>} sorted by nearest to farthest */ GeoFireQuery.prototype.within = function (center, radius, field, opts) { var _this = this; opts = __assign(__assign({}, defaultOpts), opts); var tick = Date.now(); var precision = setPrecsion(radius); var radiusBuffer = radius * 1.02; // buffer for edge distances var centerHash = center.geohash.substr(0, precision); var area = neighbors(centerHash).concat(centerHash); var _a = center.geopoint, centerLat = _a.latitude, centerLng = _a.longitude; // Used to cancel the individual geohash subscriptions var complete = new Subject(); // Map geohash neighbors to individual queries var queries = area.map(function (hash) { var query = _this.queryPoint(hash, field);