|
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
|
'use strict'; |
|
|
|
var turf_circle = require('@turf/circle'); |
|
var turf_linedistance = require('@turf/line-distance'); |
|
var turf_bbox = require('@turf/bbox'); |
|
var turf_bbox_poly = require('@turf/bbox-polygon'); |
|
var turf_truncate = require('@turf/truncate'); |
|
var turf_destination = require('@turf/destination'); |
|
var turf_helpers = require('@turf/helpers'); |
|
|
|
function Circle(center, radius, options) { |
|
|
|
this.center = center; //Point geojson feature or array of [long,lat] |
|
this.radius = radius; //Radius of circle |
|
|
|
// miles, kilometers, degrees, or radians |
|
this.units = options.units ? options.units : 'kilometers'; |
|
//Current zoom level detail of circle |
|
this.zoom = options.zoom ? options.zoom : 8; |
|
// JSON Object - property metadata for circle |
|
this.properties = options.properties ? options.properties : {}; |
|
|
|
this.steps = 100; // Default steps |
|
|
|
this.circle_gj = turf_circle(this.center, this.radius, this.steps, this.units, this.properties); |
|
|
|
this.controlPoints = [turf_destination(this.center, this.radius, 0, this.units), turf_destination(this.center, this.radius, 90, this.units), turf_destination(this.center, this.radius, 180, this.units), turf_destination(this.center, this.radius, -90, this.units)]; |
|
|
|
this._updateCircle = function () { |
|
|
|
this.steps = this._calcSteps(this.zoom); |
|
|
|
this.circle_gj = turf_circle(this.center, this.radius, this.steps, this.units, this.properties); |
|
|
|
this.controlPoints = [turf_destination(this.center, this.radius, 0, this.units), turf_destination(this.center, this.radius, 90, this.units), turf_destination(this.center, this.radius, 180, this.units), turf_destination(this.center, this.radius, -90, this.units)]; |
|
}; |
|
|
|
this._calcSteps = function (zoom) { |
|
if (zoom <= 0.1) { |
|
zoom = 0.1; |
|
} |
|
var radius_km = turf_helpers.convertDistance(this.radius, this.units, 'kilometers'); |
|
this.steps = Math.sqrt(radius_km * 250) * zoom ^ 2; |
|
}; |
|
|
|
this._calcSteps(this.zoom); |
|
|
|
this.asGeojson = function () { |
|
var feats = this.controlPoints; |
|
feats.push(this.circle_gj); |
|
feats.push(turf_helpers.point(this.center, { "type": "center" })); |
|
return turf_helpers.featureCollection(feats); |
|
}; |
|
|
|
this.updateCenter = function (newCenter) { |
|
this.center = newCenter; |
|
this._updateCircle(); |
|
}; |
|
|
|
this.updateRadius = function (newRadius) { |
|
this.radius = newRadius; |
|
this._updateCircle(); |
|
}; |
|
|
|
this.updateZoom = function (newZoom) { |
|
this.zoom = this._calcSteps(newZoom); |
|
this._updateCircle(); |
|
}; |
|
|
|
this.updateSteps = function (newSteps) { |
|
this.steps = newSteps; |
|
this._updateCircle(); |
|
}; |
|
|
|
this.updateUnits = function (newUnits) { |
|
this.units = newUnits; |
|
this._updateCircle(); |
|
}; |
|
|
|
this.getBounds = function () { |
|
var bbox_poly = turf_truncate(turf_bbox_poly(turf_bbox(this.circle_gj)), 6); |
|
var bounds = [bbox_poly.geometry.coordinates[0][0][0], bbox_poly.geometry.coordinates[0][0][1], bbox_poly.geometry.coordinates[0][2][0], bbox_poly.geometry.coordinates[0][2][1]]; |
|
return bounds; |
|
}; |
|
|
|
this.getBboxPoly = function () { |
|
return bbox_poly = turf_truncate(turf_bbox_poly(turf_bbox(this.circle_gj)), 6); |
|
}; |
|
|
|
this.getCenter = function () { |
|
return this.center; |
|
}; |
|
|
|
this.getRadius = function () { |
|
return this.radius; |
|
}; |
|
|
|
this.getControlPoints = function () { |
|
return turf_helpers.featureCollection(this.controlPoints); |
|
}; |
|
} |
|
|
|
module.exports = exports = Circle; |
|
|
|
},{"@turf/bbox":4,"@turf/bbox-polygon":3,"@turf/circle":5,"@turf/destination":6,"@turf/helpers":9,"@turf/line-distance":12,"@turf/truncate":14}],2:[function(require,module,exports){ |
|
'use strict'; |
|
|
|
var Circle = require('./Circle.js'); |
|
var turf_inside = require('@turf/inside'); |
|
var turf_helpers = require('@turf/helpers'); |
|
var turf_truncate = require('@turf/truncate'); |
|
var turf_distance = require('@turf/distance'); |
|
|
|
mapboxgl.accessToken = 'pk.eyJ1IjoicnNiYXVtYW5uIiwiYSI6IjdiOWEzZGIyMGNkOGY3NWQ4ZTBhN2Y5ZGU2Mzg2NDY2In0.jycgv7qwF8MMIWt4cT0RaQ'; |
|
|
|
var mapzoom = 12; |
|
|
|
var map = new mapboxgl.Map({ |
|
container: 'map', |
|
style: 'mapbox://styles/mapbox/streets-v9', |
|
center: [-75.343, 39.984], |
|
zoom: mapzoom |
|
}); |
|
|
|
// Circle Setup |
|
|
|
var center = [-75.343, 39.984]; |
|
var radius = 3; |
|
var units = 'kilometers'; |
|
var properties = { foo: 'bar' }; |
|
|
|
var myCircle = new Circle(center, radius, { |
|
units: units, |
|
zoom: mapzoom, |
|
properties: properties |
|
}); |
|
|
|
// DOM elements |
|
var bounds_el = document.getElementById('circleBounds'); |
|
var radius_el = document.getElementById('selectRadius'); |
|
var drag_el = document.getElementById('selectRadius'); |
|
var center_el = document.getElementById('circleCenter'); |
|
var radiusLabel_el = document.getElementById('circleRadiusLabel'); |
|
bounds_el.innerHTML = 'Bounds: ' + myCircle.getBounds(); |
|
center_el.innerHTML = 'Center: ' + myCircle.getCenter(); |
|
radiusLabel_el.innerHTML = 'Radius: ' + myCircle.getRadius() + ' ' + units; |
|
|
|
// Helper functions |
|
|
|
var animateCircle = function animateCircle() { |
|
//map.on('sourcedata', onSourceData) |
|
map.getSource('circle-1').setData(myCircle.asGeojson()); |
|
bounds_el.innerHTML = 'Bounds: ' + myCircle.getBounds(); |
|
center_el.innerHTML = 'Center: ' + myCircle.getCenter(); |
|
}; |
|
|
|
var adjustCirclePrecision = function adjustCirclePrecision() { |
|
var cur_zoom = map.getZoom(); |
|
myCircle.updateZoom(cur_zoom); |
|
animateCircle(); |
|
}; |
|
|
|
var onMoveCircle = function onMoveCircle(e) { |
|
var mousePoint = turf_truncate(turf_helpers.point(map.unproject(e.point).toArray()), 6); |
|
myCircle.updateCenter(mousePoint.geometry.coordinates); |
|
animateCircle(); |
|
}; |
|
|
|
var mouseUpCircle = function mouseUpCircle() { |
|
map.setPaintProperty('circle-center-point', 'circle-color', '#fb6a4a'); |
|
map.dragPan.enable(); |
|
map.off('mousemove', onMoveCircle); |
|
}; |
|
|
|
var mouseDownCircle = function mouseDownCircle(e) { |
|
map.dragPan.disable(); |
|
map.setPaintProperty('circle-center-point', 'circle-color', '#a50f15'); |
|
map.on('mousemove', onMoveCircle); |
|
map.once('mouseup', mouseUpCircle); |
|
}; |
|
|
|
var onMovePoint = function onMovePoint(e) { |
|
var clickPoint = map.unproject(e.point).toArray(); |
|
myCircle.updateRadius(turf_distance(myCircle.getCenter(), clickPoint, units)); |
|
radiusLabel_el.innerHTML = 'Radius: ' + Math.trunc(myCircle.getRadius()) + ' ' + units; |
|
animateCircle(); |
|
}; |
|
|
|
var mouseUpPoint = function mouseUpPoint() { |
|
map.setPaintProperty('circle-control-points', 'circle-color', 'white'); |
|
map.dragPan.enable(); |
|
map.off('mousemove', onMovePoint); |
|
}; |
|
|
|
var mouseDownPoint = function mouseDownPoint(e) { |
|
map.dragPan.disable(); |
|
map.setPaintProperty('circle-control-points', 'circle-color', '#a50f15'); |
|
map.on('mousemove', onMovePoint); |
|
map.once('mouseup', mouseUpPoint); |
|
}; |
|
|
|
var onMousemove = function onMousemove(e) { |
|
|
|
map.off('mousedown', mouseDownCircle); |
|
map.off('mousedown', mouseDownPoint); |
|
|
|
var pointFeatures = map.queryRenderedFeatures(e.point, { |
|
layers: ['circle-control-points'] |
|
}); |
|
|
|
var circleFeatures = map.queryRenderedFeatures(e.point, { |
|
layers: ['circle-center-point'] |
|
}); |
|
|
|
if (!pointFeatures.length && !circleFeatures.length) { |
|
map.getCanvas().style.cursor = ''; |
|
return; |
|
} |
|
|
|
if (pointFeatures.length) { |
|
map.getCanvas().style.cursor = 'pointer'; |
|
map.once('mousedown', mouseDownPoint); |
|
} else if (circleFeatures.length) { |
|
map.getCanvas().style.cursor = 'pointer'; |
|
map.once('mousedown', mouseDownCircle); |
|
} |
|
}; |
|
|
|
map.on('load', function () { |
|
|
|
map.addSource('circle-1', { |
|
type: "geojson", |
|
data: myCircle.asGeojson(), |
|
buffer: 1 |
|
}); |
|
|
|
map.addLayer({ |
|
id: "circle-line", |
|
type: "line", |
|
source: "circle-1", |
|
paint: { |
|
"line-color": "#fb6a4a", |
|
"line-width": { |
|
stops: [[0, 0.1], [16, 5]] |
|
} |
|
}, |
|
filter: ["==", "$type", "Polygon"] |
|
}, 'waterway-label'); |
|
|
|
map.addLayer({ |
|
id: "circle-fill", |
|
type: "fill", |
|
source: "circle-1", |
|
paint: { |
|
"fill-color": "#fb6a4a", |
|
"fill-opacity": 0.5 |
|
}, |
|
filter: ["==", "$type", "Polygon"] |
|
}, 'waterway-label'); |
|
|
|
map.addLayer({ |
|
id: "circle-control-points", |
|
type: "circle", |
|
source: "circle-1", |
|
paint: { |
|
"circle-color": "white", |
|
"circle-radius": { |
|
stops: [[0, 6], [4, 10], [18, 12]] |
|
}, |
|
"circle-stroke-color": "black", |
|
"circle-stroke-width": { |
|
stops: [[0, 0.1], [8, 1], [16, 4]] |
|
} |
|
}, |
|
filter: ["all", ["==", "$type", "Point"], ["!=", "type", "center"]] |
|
}); |
|
|
|
map.addLayer({ |
|
id: "circle-center-point", |
|
type: "circle", |
|
source: "circle-1", |
|
paint: { |
|
"circle-color": "#fb6a4a", |
|
"circle-radius": { |
|
stops: [[0, 6], [4, 10], [18, 12]] |
|
}, |
|
"circle-stroke-color": "black", |
|
"circle-stroke-width": { |
|
stops: [[0, 0.1], [8, 1], [16, 4]] |
|
} |
|
}, |
|
filter: ["all", ["==", "$type", "Point"], ["==", "type", "center"]] |
|
}); |
|
|
|
// Add map event listeners |
|
|
|
map.on('zoomend', adjustCirclePrecision); |
|
map.on('mousemove', _.debounce(onMousemove, 16)); |
|
}); |
|
|
|
},{"./Circle.js":1,"@turf/distance":7,"@turf/helpers":9,"@turf/inside":10,"@turf/truncate":14}],3:[function(require,module,exports){ |
|
var polygon = require('@turf/helpers').polygon; |
|
|
|
/** |
|
* Takes a bbox and returns an equivalent {@link Polygon|polygon}. |
|
* |
|
* @name bboxPolygon |
|
* @param {Array<number>} bbox extent in [minX, minY, maxX, maxY] order |
|
* @return {Feature<Polygon>} a Polygon representation of the bounding box |
|
* @addToMap poly |
|
* @example |
|
* var bbox = [0, 0, 10, 10]; |
|
* |
|
* var poly = turf.bboxPolygon(bbox); |
|
* |
|
* //addToMap |
|
* var addToMap = [poly] |
|
*/ |
|
|
|
module.exports = function (bbox) { |
|
var lowLeft = [bbox[0], bbox[1]]; |
|
var topLeft = [bbox[0], bbox[3]]; |
|
var topRight = [bbox[2], bbox[3]]; |
|
var lowRight = [bbox[2], bbox[1]]; |
|
|
|
return polygon([[ |
|
lowLeft, |
|
lowRight, |
|
topRight, |
|
topLeft, |
|
lowLeft |
|
]]); |
|
}; |
|
|
|
},{"@turf/helpers":9}],4:[function(require,module,exports){ |
|
var coordEach = require('@turf/meta').coordEach; |
|
|
|
/** |
|
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box. |
|
* |
|
* @name bbox |
|
* @param {FeatureCollection|Feature<any>} geojson input features |
|
* @returns {Array<number>} bbox extent in [minX, minY, maxX, maxY] order |
|
* @example |
|
* var line = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "LineString", |
|
* "coordinates": [[-74, 40], [-78, 42], [-82, 35]] |
|
* } |
|
* } |
|
* var bbox = turf.bbox(line); |
|
* |
|
* //addToMap |
|
* var bboxPolygon = turf.bboxPolygon(bbox); |
|
* var addToMap = [line, bboxPolygon] |
|
*/ |
|
module.exports = function (geojson) { |
|
var bbox = [Infinity, Infinity, -Infinity, -Infinity]; |
|
coordEach(geojson, function (coord) { |
|
if (bbox[0] > coord[0]) bbox[0] = coord[0]; |
|
if (bbox[1] > coord[1]) bbox[1] = coord[1]; |
|
if (bbox[2] < coord[0]) bbox[2] = coord[0]; |
|
if (bbox[3] < coord[1]) bbox[3] = coord[1]; |
|
}); |
|
return bbox; |
|
}; |
|
|
|
},{"@turf/meta":13}],5:[function(require,module,exports){ |
|
var destination = require('@turf/destination'); |
|
var polygon = require('@turf/helpers').polygon; |
|
|
|
/** |
|
* Takes a {@link Point} and calculates the circle polygon given a radius in degrees, radians, miles, or kilometers; and steps for precision. |
|
* |
|
* @name circle |
|
* @param {Feature<Point>|number[]} center center point |
|
* @param {number} radius radius of the circle |
|
* @param {number} [steps=64] number of steps |
|
* @param {string} [units=kilometers] miles, kilometers, degrees, or radians |
|
* @param {Object} [properties={}] properties |
|
* @returns {Feature<Polygon>} circle polygon |
|
* @example |
|
* var center = [-75.343, 39.984]; |
|
* var radius = 5; |
|
* var steps = 10; |
|
* var units = 'kilometers'; |
|
* var properties = {foo: 'bar'}; |
|
* |
|
* var circle = turf.circle(center, radius, steps, units, properties); |
|
* |
|
* //addToMap |
|
* var addToMap = [turf.point(center), circle] |
|
*/ |
|
module.exports = function (center, radius, steps, units, properties) { |
|
// validation |
|
if (!center) throw new Error('center is required'); |
|
if (!radius) throw new Error('radius is required'); |
|
|
|
// default params |
|
steps = steps || 64; |
|
properties = properties || center.properties || {}; |
|
|
|
var coordinates = []; |
|
for (var i = 0; i < steps; i++) { |
|
coordinates.push(destination(center, radius, i * 360 / steps, units).geometry.coordinates); |
|
} |
|
coordinates.push(coordinates[0]); |
|
|
|
return polygon([coordinates], properties); |
|
}; |
|
|
|
},{"@turf/destination":6,"@turf/helpers":9}],6:[function(require,module,exports){ |
|
//http://en.wikipedia.org/wiki/Haversine_formula |
|
//http://www.movable-type.co.uk/scripts/latlong.html |
|
var getCoord = require('@turf/invariant').getCoord; |
|
var helpers = require('@turf/helpers'); |
|
var point = helpers.point; |
|
var distanceToRadians = helpers.distanceToRadians; |
|
|
|
/** |
|
* Takes a {@link Point} and calculates the location of a destination point given a distance in degrees, radians, miles, or kilometers; and bearing in degrees. This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. |
|
* |
|
* @name destination |
|
* @param {Geometry|Feature<Point>|Array<number>} origin starting point |
|
* @param {number} distance distance from the origin point |
|
* @param {number} bearing ranging from -180 to 180 |
|
* @param {string} [units=kilometers] miles, kilometers, degrees, or radians |
|
* @returns {Feature<Point>} destination point |
|
* @example |
|
* var point = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [-75.343, 39.984] |
|
* } |
|
* }; |
|
* var distance = 50; |
|
* var bearing = 90; |
|
* var units = 'miles'; |
|
* |
|
* var destination = turf.destination(point, distance, bearing, units); |
|
* |
|
* //addToMap |
|
* destination.properties['marker-color'] = '#f00'; |
|
* point.properties['marker-color'] = '#0f0'; |
|
* var addToMap = [point, destination] |
|
*/ |
|
module.exports = function (origin, distance, bearing, units) { |
|
var degrees2radians = Math.PI / 180; |
|
var radians2degrees = 180 / Math.PI; |
|
var coordinates1 = getCoord(origin); |
|
var longitude1 = degrees2radians * coordinates1[0]; |
|
var latitude1 = degrees2radians * coordinates1[1]; |
|
var bearing_rad = degrees2radians * bearing; |
|
|
|
var radians = distanceToRadians(distance, units); |
|
|
|
var latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) + |
|
Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearing_rad)); |
|
var longitude2 = longitude1 + Math.atan2(Math.sin(bearing_rad) * |
|
Math.sin(radians) * Math.cos(latitude1), |
|
Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2)); |
|
|
|
return point([radians2degrees * longitude2, radians2degrees * latitude2]); |
|
}; |
|
|
|
},{"@turf/helpers":9,"@turf/invariant":11}],7:[function(require,module,exports){ |
|
var getCoord = require('@turf/invariant').getCoord; |
|
var radiansToDistance = require('@turf/helpers').radiansToDistance; |
|
//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 {Geometry|Feature<Point>|Array<number>} from origin point |
|
* @param {Geometry|Feature<Point>|Array<number>} to destination point |
|
* @param {string} [units=kilometers] can be degrees, radians, miles, or kilometers |
|
* @returns {number} distance between the two points |
|
* @example |
|
* var from = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [-75.343, 39.984] |
|
* } |
|
* }; |
|
* var to = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [-75.534, 39.123] |
|
* } |
|
* }; |
|
* |
|
* var distance = turf.distance(from, to, "miles"); |
|
* |
|
* //addToMap |
|
* from.properties.distance = distance; |
|
* to.properties.distance = distance; |
|
* var addToMap = [from, to]; |
|
*/ |
|
module.exports = function (from, to, units) { |
|
var degrees2radians = Math.PI / 180; |
|
var coordinates1 = getCoord(from); |
|
var coordinates2 = getCoord(to); |
|
var dLat = degrees2radians * (coordinates2[1] - coordinates1[1]); |
|
var dLon = degrees2radians * (coordinates2[0] - coordinates1[0]); |
|
var lat1 = degrees2radians * coordinates1[1]; |
|
var lat2 = degrees2radians * 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 radiansToDistance(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), units); |
|
}; |
|
|
|
},{"@turf/helpers":9,"@turf/invariant":11}],8:[function(require,module,exports){ |
|
var flattenEach = require('@turf/meta').flattenEach; |
|
var featureCollection = require('@turf/helpers').featureCollection; |
|
|
|
/** |
|
* Flattens any {@link GeoJSON} to a {@link FeatureCollection} inspired by [geojson-flatten](https://github.com/tmcw/geojson-flatten). |
|
* |
|
* @name flatten |
|
* @param {FeatureCollection|Geometry|Feature<any>} geojson any valid GeoJSON Object |
|
* @returns {FeatureCollection<any>} all Multi-Geometries are flattened into single Features |
|
* @example |
|
* var multiGeometry = { |
|
* "type": "MultiPolygon", |
|
* "coordinates": [ |
|
* [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]], |
|
* [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]], |
|
* [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]] |
|
* ] |
|
* }; |
|
* |
|
* var flatten = turf.flatten(multiGeometry); |
|
* |
|
* //addToMap |
|
* var addToMap = [flatten] |
|
*/ |
|
function flatten(geojson) { |
|
if (!geojson) throw new Error('geojson is required'); |
|
|
|
var results = []; |
|
flattenEach(geojson, function (feature) { |
|
results.push(feature); |
|
}); |
|
return featureCollection(results); |
|
} |
|
module.exports = flatten; |
|
|
|
},{"@turf/helpers":9,"@turf/meta":13}],9:[function(require,module,exports){ |
|
/** |
|
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. |
|
* |
|
* @name feature |
|
* @param {Geometry} geometry input geometry |
|
* @param {Object} properties properties |
|
* @returns {Feature} a GeoJSON Feature |
|
* @example |
|
* var geometry = { |
|
* "type": "Point", |
|
* "coordinates": [110, 50] |
|
* }; |
|
* |
|
* var feature = turf.feature(geometry); |
|
* |
|
* //=feature |
|
*/ |
|
function feature(geometry, properties) { |
|
if (!geometry) throw new Error('No geometry passed'); |
|
|
|
return { |
|
type: 'Feature', |
|
properties: properties || {}, |
|
geometry: geometry |
|
}; |
|
} |
|
|
|
/** |
|
* Takes coordinates and properties (optional) and returns a new {@link Point} feature. |
|
* |
|
* @name point |
|
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees) |
|
* @param {Object=} properties an Object that is used as the {@link Feature}'s |
|
* properties |
|
* @returns {Feature<Point>} a Point feature |
|
* @example |
|
* var point = turf.point([-75.343, 39.984]); |
|
* |
|
* //=point |
|
*/ |
|
function point(coordinates, properties) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
if (coordinates.length === undefined) throw new Error('Coordinates must be an array'); |
|
if (coordinates.length < 2) throw new Error('Coordinates must be at least 2 numbers long'); |
|
if (typeof coordinates[0] !== 'number' || typeof coordinates[1] !== 'number') throw new Error('Coordinates must contain numbers'); |
|
|
|
return feature({ |
|
type: 'Point', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* Takes an array of LinearRings and optionally an {@link Object} with properties and returns a {@link Polygon} feature. |
|
* |
|
* @name polygon |
|
* @param {Array<Array<Array<number>>>} coordinates an array of LinearRings |
|
* @param {Object=} properties a properties object |
|
* @returns {Feature<Polygon>} a Polygon feature |
|
* @throws {Error} throw an error if a LinearRing of the polygon has too few positions |
|
* or if a LinearRing of the Polygon does not have matching Positions at the beginning & end. |
|
* @example |
|
* var polygon = turf.polygon([[ |
|
* [-2.275543, 53.464547], |
|
* [-2.275543, 53.489271], |
|
* [-2.215118, 53.489271], |
|
* [-2.215118, 53.464547], |
|
* [-2.275543, 53.464547] |
|
* ]], { name: 'poly1', population: 400}); |
|
* |
|
* //=polygon |
|
*/ |
|
function polygon(coordinates, properties) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
|
|
for (var i = 0; i < coordinates.length; i++) { |
|
var ring = coordinates[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++) { |
|
if (ring[ring.length - 1][j] !== ring[0][j]) { |
|
throw new Error('First and last Position are not equivalent.'); |
|
} |
|
} |
|
} |
|
|
|
return feature({ |
|
type: 'Polygon', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* Creates a {@link LineString} based on a |
|
* coordinate array. Properties can be added optionally. |
|
* |
|
* @name lineString |
|
* @param {Array<Array<number>>} coordinates an array of Positions |
|
* @param {Object=} properties an Object of key-value pairs to add as properties |
|
* @returns {Feature<LineString>} a LineString feature |
|
* @throws {Error} if no coordinates are passed |
|
* @example |
|
* var linestring1 = turf.lineString([ |
|
* [-21.964416, 64.148203], |
|
* [-21.956176, 64.141316], |
|
* [-21.93901, 64.135924], |
|
* [-21.927337, 64.136673] |
|
* ]); |
|
* var linestring2 = turf.lineString([ |
|
* [-21.929054, 64.127985], |
|
* [-21.912918, 64.134726], |
|
* [-21.916007, 64.141016], |
|
* [-21.930084, 64.14446] |
|
* ], {name: 'line 1', distance: 145}); |
|
* |
|
* //=linestring1 |
|
* |
|
* //=linestring2 |
|
*/ |
|
function lineString(coordinates, properties) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
if (coordinates.length < 2) throw new Error('Coordinates must be an array of two or more positions'); |
|
|
|
return feature({ |
|
type: 'LineString', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* Takes one or more {@link Feature|Features} and creates a {@link FeatureCollection}. |
|
* |
|
* @name featureCollection |
|
* @param {Feature[]} features input features |
|
* @returns {FeatureCollection} a FeatureCollection of input features |
|
* @example |
|
* var features = [ |
|
* turf.point([-75.343, 39.984], {name: 'Location A'}), |
|
* turf.point([-75.833, 39.284], {name: 'Location B'}), |
|
* turf.point([-75.534, 39.123], {name: 'Location C'}) |
|
* ]; |
|
* |
|
* var collection = turf.featureCollection(features); |
|
* |
|
* //=collection |
|
*/ |
|
function featureCollection(features) { |
|
if (!features) throw new Error('No features passed'); |
|
if (!Array.isArray(features)) throw new Error('features must be an Array'); |
|
|
|
return { |
|
type: 'FeatureCollection', |
|
features: features |
|
}; |
|
} |
|
|
|
/** |
|
* 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 |
|
* @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) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
|
|
return feature({ |
|
type: 'MultiLineString', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* 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 |
|
* @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) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
|
|
return feature({ |
|
type: 'MultiPoint', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* 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 |
|
* @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) { |
|
if (!coordinates) throw new Error('No coordinates passed'); |
|
|
|
return feature({ |
|
type: 'MultiPolygon', |
|
coordinates: coordinates |
|
}, properties); |
|
} |
|
|
|
/** |
|
* 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 |
|
* @returns {Feature<GeometryCollection>} a GeoJSON GeometryCollection Feature |
|
* @example |
|
* var pt = { |
|
* "type": "Point", |
|
* "coordinates": [100, 0] |
|
* }; |
|
* var line = { |
|
* "type": "LineString", |
|
* "coordinates": [ [101, 0], [102, 1] ] |
|
* }; |
|
* var collection = turf.geometryCollection([pt, line]); |
|
* |
|
* //=collection |
|
*/ |
|
function geometryCollection(geometries, properties) { |
|
if (!geometries) throw new Error('geometries is required'); |
|
|
|
return feature({ |
|
type: 'GeometryCollection', |
|
geometries: geometries |
|
}, properties); |
|
} |
|
|
|
// https://en.wikipedia.org/wiki/Great-circle_distance#Radius_for_spherical_Earth |
|
var factors = { |
|
miles: 3960, |
|
nauticalmiles: 3441.145, |
|
degrees: 57.2957795, |
|
radians: 1, |
|
inches: 250905600, |
|
yards: 6969600, |
|
meters: 6373000, |
|
metres: 6373000, |
|
centimeters: 6.373e+8, |
|
centimetres: 6.373e+8, |
|
kilometers: 6373, |
|
kilometres: 6373, |
|
feet: 20908792.65 |
|
}; |
|
|
|
var areaFactors = { |
|
kilometers: 0.000001, |
|
kilometres: 0.000001, |
|
meters: 1, |
|
metres: 1, |
|
centimetres: 10000, |
|
millimeter: 1000000, |
|
acres: 0.000247105, |
|
miles: 3.86e-7, |
|
yards: 1.195990046, |
|
feet: 10.763910417, |
|
inches: 1550.003100006 |
|
}; |
|
/** |
|
* Round number to precision |
|
* |
|
* @param {number} num Number |
|
* @param {number} [precision=0] Precision |
|
* @returns {number} rounded number |
|
* @example |
|
* round(120.4321) |
|
* //=120 |
|
* |
|
* round(120.4321, 2) |
|
* //=120.43 |
|
*/ |
|
function round(num, precision) { |
|
if (num === undefined || num === null || isNaN(num)) throw new Error('num is required'); |
|
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; |
|
} |
|
|
|
/** |
|
* 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 radiansToDistance |
|
* @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 radiansToDistance(radians, units) { |
|
if (radians === undefined || radians === null) throw new Error('radians is required'); |
|
|
|
var factor = factors[units || 'kilometers']; |
|
if (!factor) throw new Error('units is invalid'); |
|
return radians * factor; |
|
} |
|
|
|
/** |
|
* 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 distanceToRadians |
|
* @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 distanceToRadians(distance, units) { |
|
if (distance === undefined || distance === null) throw new Error('distance is required'); |
|
|
|
var factor = factors[units || 'kilometers']; |
|
if (!factor) throw new Error('units is invalid'); |
|
return distance / factor; |
|
} |
|
|
|
/** |
|
* 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 distanceToDegrees |
|
* @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 distanceToDegrees(distance, units) { |
|
return radians2degrees(distanceToRadians(distance, units)); |
|
} |
|
|
|
/** |
|
* 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 bearingToAngle |
|
* @param {number} bearing angle, between -180 and +180 degrees |
|
* @returns {number} angle between 0 and 360 degrees |
|
*/ |
|
function bearingToAngle(bearing) { |
|
if (bearing === null || bearing === undefined) throw new Error('bearing is required'); |
|
|
|
var angle = bearing % 360; |
|
if (angle < 0) angle += 360; |
|
return angle; |
|
} |
|
|
|
/** |
|
* Converts an angle in radians to degrees |
|
* |
|
* @name radians2degrees |
|
* @param {number} radians angle in radians |
|
* @returns {number} degrees between 0 and 360 degrees |
|
*/ |
|
function radians2degrees(radians) { |
|
if (radians === null || radians === undefined) throw new Error('radians is required'); |
|
|
|
var degrees = radians % (2 * Math.PI); |
|
return degrees * 180 / Math.PI; |
|
} |
|
|
|
/** |
|
* Converts an angle in degrees to radians |
|
* |
|
* @name degrees2radians |
|
* @param {number} degrees angle between 0 and 360 degrees |
|
* @returns {number} angle in radians |
|
*/ |
|
function degrees2radians(degrees) { |
|
if (degrees === null || degrees === undefined) throw new Error('degrees is required'); |
|
|
|
var radians = degrees % 360; |
|
return radians * Math.PI / 180; |
|
} |
|
|
|
|
|
/** |
|
* Converts a distance to the requested unit. |
|
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet |
|
* |
|
* @param {number} distance to be converted |
|
* @param {string} originalUnit of the distance |
|
* @param {string} [finalUnit=kilometers] returned unit |
|
* @returns {number} the converted distance |
|
*/ |
|
function convertDistance(distance, originalUnit, finalUnit) { |
|
if (distance === null || distance === undefined) throw new Error('distance is required'); |
|
if (!(distance >= 0)) throw new Error('distance must be a positive number'); |
|
|
|
var convertedDistance = radiansToDistance(distanceToRadians(distance, originalUnit), finalUnit || 'kilometers'); |
|
return convertedDistance; |
|
} |
|
|
|
/** |
|
* Converts a area to the requested unit. |
|
* Valid units: kilometers, kilometres, meters, metres, centimetres, millimeter, acre, mile, yard, foot, inch |
|
* @param {number} area to be converted |
|
* @param {string} [originalUnit=meters] of the distance |
|
* @param {string} [finalUnit=kilometers] returned unit |
|
* @returns {number} the converted distance |
|
*/ |
|
function convertArea(area, originalUnit, finalUnit) { |
|
if (area === null || area === undefined) throw new Error('area is required'); |
|
if (!(area >= 0)) throw new Error('area must be a positive number'); |
|
|
|
var startFactor = areaFactors[originalUnit || 'meters']; |
|
if (!startFactor) throw new Error('invalid original units'); |
|
|
|
var finalFactor = areaFactors[finalUnit || 'kilometers']; |
|
if (!finalFactor) throw new Error('invalid final units'); |
|
|
|
return (area / startFactor) * finalFactor; |
|
} |
|
|
|
module.exports = { |
|
feature: feature, |
|
featureCollection: featureCollection, |
|
geometryCollection: geometryCollection, |
|
point: point, |
|
multiPoint: multiPoint, |
|
lineString: lineString, |
|
multiLineString: multiLineString, |
|
polygon: polygon, |
|
multiPolygon: multiPolygon, |
|
radiansToDistance: radiansToDistance, |
|
distanceToRadians: distanceToRadians, |
|
distanceToDegrees: distanceToDegrees, |
|
radians2degrees: radians2degrees, |
|
degrees2radians: degrees2radians, |
|
bearingToAngle: bearingToAngle, |
|
convertDistance: convertDistance, |
|
convertArea: convertArea, |
|
round: round |
|
}; |
|
|
|
},{}],10:[function(require,module,exports){ |
|
var invariant = require('@turf/invariant'); |
|
var getCoord = invariant.getCoord; |
|
var getCoords = invariant.getCoords; |
|
|
|
// http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule |
|
// modified from: https://github.com/substack/point-in-polygon/blob/master/index.js |
|
// which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html |
|
|
|
/** |
|
* Takes a {@link Point} and a {@link Polygon} or {@link MultiPolygon} and determines if the point resides inside the polygon. The polygon can |
|
* be convex or concave. The function accounts for holes. |
|
* |
|
* @name inside |
|
* @param {Feature<Point>} point input point |
|
* @param {Feature<Polygon|MultiPolygon>} polygon input polygon or multipolygon |
|
* @param {boolean} [ignoreBoundary=false] True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise false. |
|
* @returns {boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon |
|
* @example |
|
* var pt = turf.point([-77, 44]); |
|
* var poly = turf.polygon([[ |
|
* [-81, 41], |
|
* [-81, 47], |
|
* [-72, 47], |
|
* [-72, 41], |
|
* [-81, 41] |
|
* ]]); |
|
* |
|
* var isInside = turf.inside(pt, poly); |
|
* |
|
* //addToMap |
|
* pt.properties.isInside = isInside |
|
* var addToMap = [pt, poly] |
|
*/ |
|
module.exports = function (point, polygon, ignoreBoundary) { |
|
// validation |
|
if (!point) throw new Error('point is required'); |
|
if (!polygon) throw new Error('polygon is required'); |
|
|
|
var pt = getCoord(point); |
|
var polys = getCoords(polygon); |
|
var type = (polygon.geometry) ? polygon.geometry.type : polygon.type; |
|
var bbox = polygon.bbox; |
|
|
|
// Quick elimination if point is not inside bbox |
|
if (bbox && inBBox(pt, bbox) === false) return false; |
|
|
|
// normalize to multipolygon |
|
if (type === 'Polygon') polys = [polys]; |
|
|
|
for (var i = 0, insidePoly = false; i < polys.length && !insidePoly; i++) { |
|
// check if it is in the outer ring first |
|
if (inRing(pt, polys[i][0], ignoreBoundary)) { |
|
var inHole = false; |
|
var k = 1; |
|
// check for the point in any of the holes |
|
while (k < polys[i].length && !inHole) { |
|
if (inRing(pt, polys[i][k], !ignoreBoundary)) { |
|
inHole = true; |
|
} |
|
k++; |
|
} |
|
if (!inHole) insidePoly = true; |
|
} |
|
} |
|
return insidePoly; |
|
}; |
|
|
|
/** |
|
* inRing |
|
* |
|
* @private |
|
* @param {[number, number]} pt [x,y] |
|
* @param {Array<[number, number]>} ring [[x,y], [x,y],..] |
|
* @param {boolean} ignoreBoundary ignoreBoundary |
|
* @returns {boolean} inRing |
|
*/ |
|
function inRing(pt, ring, ignoreBoundary) { |
|
var isInside = false; |
|
if (ring[0][0] === ring[ring.length - 1][0] && ring[0][1] === ring[ring.length - 1][1]) ring = ring.slice(0, ring.length - 1); |
|
|
|
for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) { |
|
var xi = ring[i][0], yi = ring[i][1]; |
|
var xj = ring[j][0], yj = ring[j][1]; |
|
var onBoundary = (pt[1] * (xi - xj) + yi * (xj - pt[0]) + yj * (pt[0] - xi) === 0) && |
|
((xi - pt[0]) * (xj - pt[0]) <= 0) && ((yi - pt[1]) * (yj - pt[1]) <= 0); |
|
if (onBoundary) return !ignoreBoundary; |
|
var intersect = ((yi > pt[1]) !== (yj > pt[1])) && |
|
(pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi); |
|
if (intersect) isInside = !isInside; |
|
} |
|
return isInside; |
|
} |
|
|
|
/** |
|
* inBBox |
|
* |
|
* @private |
|
* @param {[number, number]} pt point [x,y] |
|
* @param {[number, number, number, number]} bbox BBox [west, south, east, north] |
|
* @returns {boolean} true/false if point is inside BBox |
|
*/ |
|
function inBBox(pt, bbox) { |
|
return bbox[0] <= pt[0] && |
|
bbox[1] <= pt[1] && |
|
bbox[2] >= pt[0] && |
|
bbox[3] >= pt[1]; |
|
} |
|
|
|
},{"@turf/invariant":11}],11:[function(require,module,exports){ |
|
/** |
|
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate. |
|
* |
|
* @name getCoord |
|
* @param {Array<any>|Geometry|Feature<Point>} obj any value |
|
* @returns {Array<number>} coordinates |
|
*/ |
|
function getCoord(obj) { |
|
if (!obj) throw new Error('No obj passed'); |
|
|
|
var coordinates = getCoords(obj); |
|
|
|
// getCoord() must contain at least two numbers (Point) |
|
if (coordinates.length > 1 && |
|
typeof coordinates[0] === 'number' && |
|
typeof coordinates[1] === 'number') { |
|
return coordinates; |
|
} else { |
|
throw new Error('Coordinate is not a valid Point'); |
|
} |
|
} |
|
|
|
/** |
|
* Unwrap coordinates from a Feature, Geometry Object or an Array of numbers |
|
* |
|
* @name getCoords |
|
* @param {Array<any>|Geometry|Feature<any>} obj any value |
|
* @returns {Array<any>} coordinates |
|
*/ |
|
function getCoords(obj) { |
|
if (!obj) throw new Error('No obj passed'); |
|
var coordinates; |
|
|
|
// Array of numbers |
|
if (obj.length) { |
|
coordinates = obj; |
|
|
|
// Geometry Object |
|
} else if (obj.coordinates) { |
|
coordinates = obj.coordinates; |
|
|
|
// Feature |
|
} else if (obj.geometry && obj.geometry.coordinates) { |
|
coordinates = obj.geometry.coordinates; |
|
} |
|
// Checks if coordinates contains a number |
|
if (coordinates) { |
|
containsNumber(coordinates); |
|
return coordinates; |
|
} |
|
throw new Error('No valid coordinates'); |
|
} |
|
|
|
/** |
|
* 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 && |
|
typeof coordinates[0] === 'number' && |
|
typeof coordinates[1] === 'number') { |
|
return true; |
|
} |
|
|
|
if (Array.isArray(coordinates[0]) && coordinates[0].length) { |
|
return containsNumber(coordinates[0]); |
|
} |
|
throw new Error('coordinates must only contain numbers'); |
|
} |
|
|
|
/** |
|
* 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); |
|
} |
|
} |
|
|
|
/** |
|
* 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); |
|
} |
|
} |
|
|
|
/** |
|
* 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; i < featureCollection.features.length; i++) { |
|
var feature = featureCollection.features[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); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Get Geometry from Feature or Geometry Object |
|
* |
|
* @param {Feature<any>|Geometry<any>} geojson GeoJSON Feature or Geometry Object |
|
* @returns {Geometry<any>} 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 = invariant.getGeom(point) |
|
* //={"type": "Point", "coordinates": [110, 40]} |
|
*/ |
|
function getGeom(geojson) { |
|
if (!geojson) throw new Error('<geojson> is required'); |
|
if (geojson.geometry) return geojson.geometry; |
|
if (geojson.coordinates || geojson.geometries) return geojson; |
|
throw new Error('<geojson> must be a Feature or Geometry Object'); |
|
} |
|
|
|
/** |
|
* Get Geometry Type from Feature or Geometry Object |
|
* |
|
* @param {Feature<any>|Geometry<any>} geojson GeoJSON Feature or Geometry Object |
|
* @returns {string} GeoJSON Geometry Type |
|
* @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 = invariant.getGeom(point) |
|
* //="Point" |
|
*/ |
|
function getGeomType(geojson) { |
|
return getGeom(geojson).type; |
|
} |
|
|
|
module.exports = { |
|
geojsonType: geojsonType, |
|
collectionOf: collectionOf, |
|
featureOf: featureOf, |
|
getCoord: getCoord, |
|
getCoords: getCoords, |
|
containsNumber: containsNumber, |
|
getGeom: getGeom, |
|
getGeomType: getGeomType |
|
}; |
|
|
|
},{}],12:[function(require,module,exports){ |
|
var flatten = require('@turf/flatten'); |
|
var distance = require('@turf/distance'); |
|
var meta = require('@turf/meta'); |
|
var geomEach = meta.geomEach; |
|
var featureEach = meta.featureEach; |
|
var coordReduce = meta.coordReduce; |
|
var helpers = require('@turf/helpers'); |
|
var point = helpers.point; |
|
var lineString = helpers.lineString; |
|
|
|
/** |
|
* Takes a {@link LineString} or {@link Polygon} and measures its length in the specified units. |
|
* |
|
* @name lineDistance |
|
* @param {Feature<(LineString|Polygon)>|FeatureCollection<(LineString|Polygon)>} geojson feature to measure |
|
* @param {string} [units=kilometers] can be degrees, radians, miles, or kilometers |
|
* @returns {number} length feature |
|
* @example |
|
* var line = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "LineString", |
|
* "coordinates": [ |
|
* [-77.031669, 38.878605], |
|
* [-77.029609, 38.881946], |
|
* [-77.020339, 38.884084], |
|
* [-77.025661, 38.885821], |
|
* [-77.021884, 38.889563], |
|
* [-77.019824, 38.892368] |
|
* ] |
|
* } |
|
* }; |
|
* |
|
* var length = turf.lineDistance(line, 'miles'); |
|
* |
|
* //addToMap |
|
* line.properties.distance = length; |
|
* var addToMap = [line]; |
|
*/ |
|
module.exports = function lineDistance(geojson, units) { |
|
// Input Validation |
|
if (!geojson) throw new Error('geojson is required'); |
|
geomEach(geojson, function (geometry) { |
|
if (geometry.type === 'Point') throw new Error('geojson cannot be a Point'); |
|
if (geometry.type === 'MultiPoint') throw new Error('geojson cannot be a MultiPoint'); |
|
}); |
|
|
|
// Calculate distance from 2-vertex line segements |
|
return segmentReduce(geojson, function (previousValue, segment) { |
|
var coords = segment.geometry.coordinates; |
|
var start = point(coords[0]); |
|
var end = point(coords[1]); |
|
return previousValue + distance(start, end, units); |
|
}, 0); |
|
}; |
|
|
|
/** |
|
* Iterate over 2-vertex line segment in any GeoJSON object, similar to Array.forEach() |
|
* |
|
* @private |
|
* @param {FeatureCollection|Feature<any>} geojson any GeoJSON |
|
* @param {Function} callback a method that takes (currentSegment, currentIndex) |
|
* @returns {void} |
|
* @example |
|
* var polygon = { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Polygon", |
|
* "coordinates": [[[-50, 5], [-40, -10], [-50, -10], [-40, 5], [-50, 5]]] |
|
* } |
|
* } |
|
* turf.segmentEach(polygon, function (segment) { |
|
* //= segment |
|
* }); |
|
*/ |
|
function segmentEach(geojson, callback) { |
|
var count = 0; |
|
featureEach(geojson, function (multiFeature) { |
|
featureEach(flatten(multiFeature), function (feature) { |
|
coordReduce(feature, function (previousCoords, currentCoords) { |
|
var line = lineString([previousCoords, currentCoords], feature.properties); |
|
callback(line, count); |
|
count++; |
|
return currentCoords; |
|
}); |
|
}); |
|
}); |
|
} |
|
|
|
/** |
|
* Reduce 2-vertex line segment in any GeoJSON object, similar to Array.reduce() |
|
* |
|
* @private |
|
* @param {FeatureCollection|Feature<any>} geojson any GeoJSON |
|
* @param {Function} callback a method that takes (previousValue, currentSegment, currentIndex) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @returns {void} |
|
*/ |
|
function segmentReduce(geojson, callback, initialValue) { |
|
var previousValue = initialValue; |
|
segmentEach(geojson, function (currentSegment, currentIndex) { |
|
if (currentIndex === 0 && initialValue === undefined) { |
|
previousValue = currentSegment; |
|
} else { |
|
previousValue = callback(previousValue, currentSegment, currentIndex); |
|
} |
|
}); |
|
return previousValue; |
|
} |
|
|
|
},{"@turf/distance":7,"@turf/flatten":8,"@turf/helpers":9,"@turf/meta":13}],13:[function(require,module,exports){ |
|
/** |
|
* Callback for coordEach |
|
* |
|
* @private |
|
* @callback coordEachCallback |
|
* @param {Array<number>} currentCoords The current coordinates being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Iterate over coordinates in any GeoJSON object, similar to Array.forEach() |
|
* |
|
* @name coordEach |
|
* @param {FeatureCollection|Geometry|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (currentCoords, currentIndex) |
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.coordEach(features, function (currentCoords, currentIndex) { |
|
* //=currentCoords |
|
* //=currentIndex |
|
* }); |
|
*/ |
|
function coordEach(geojson, callback, excludeWrapCoord) { |
|
var i, j, k, g, l, geometry, stopG, coords, |
|
geometryMaybeCollection, |
|
wrapShrink = 0, |
|
currentIndex = 0, |
|
isGeometryCollection, |
|
isFeatureCollection = geojson.type === 'FeatureCollection', |
|
isFeature = geojson.type === 'Feature', |
|
stop = isFeatureCollection ? geojson.features.length : 1; |
|
|
|
// This logic may look a little weird. The reason why it is that way |
|
// is because it's trying to be fast. GeoJSON supports multiple kinds |
|
// of objects at its root: FeatureCollection, Features, Geometries. |
|
// This function has the responsibility of handling all of them, and that |
|
// means that some of the `for` loops you see below actually just don't apply |
|
// to certain inputs. For instance, if you give this just a |
|
// Point geometry, then both loops are short-circuited and all we do |
|
// is gradually rename the input until it's called 'geometry'. |
|
// |
|
// This also aims to allocate as few resources as possible: just a |
|
// few numbers and booleans, rather than any temporary arrays as would |
|
// be required with the normalization approach. |
|
for (i = 0; i < stop; i++) { |
|
|
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry : |
|
(isFeature ? geojson.geometry : geojson)); |
|
isGeometryCollection = geometryMaybeCollection.type === 'GeometryCollection'; |
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1; |
|
|
|
for (g = 0; g < stopG; g++) { |
|
geometry = isGeometryCollection ? |
|
geometryMaybeCollection.geometries[g] : geometryMaybeCollection; |
|
coords = geometry.coordinates; |
|
|
|
wrapShrink = (excludeWrapCoord && |
|
(geometry.type === 'Polygon' || geometry.type === 'MultiPolygon')) ? |
|
1 : 0; |
|
|
|
if (geometry.type === 'Point') { |
|
callback(coords, currentIndex); |
|
currentIndex++; |
|
} else if (geometry.type === 'LineString' || geometry.type === 'MultiPoint') { |
|
for (j = 0; j < coords.length; j++) { |
|
callback(coords[j], currentIndex); |
|
currentIndex++; |
|
} |
|
} else if (geometry.type === 'Polygon' || geometry.type === 'MultiLineString') { |
|
for (j = 0; j < coords.length; j++) |
|
for (k = 0; k < coords[j].length - wrapShrink; k++) { |
|
callback(coords[j][k], currentIndex); |
|
currentIndex++; |
|
} |
|
} else if (geometry.type === 'MultiPolygon') { |
|
for (j = 0; j < coords.length; j++) |
|
for (k = 0; k < coords[j].length; k++) |
|
for (l = 0; l < coords[j][k].length - wrapShrink; l++) { |
|
callback(coords[j][k][l], currentIndex); |
|
currentIndex++; |
|
} |
|
} else if (geometry.type === 'GeometryCollection') { |
|
for (j = 0; j < geometry.geometries.length; j++) |
|
coordEach(geometry.geometries[j], callback, excludeWrapCoord); |
|
} else { |
|
throw new Error('Unknown Geometry Type'); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Callback for coordReduce |
|
* |
|
* The first time the callback function is called, the values provided as arguments depend |
|
* on whether the reduce method has an initialValue argument. |
|
* |
|
* If an initialValue is provided to the reduce method: |
|
* - The previousValue argument is initialValue. |
|
* - The currentValue argument is the value of the first element present in the array. |
|
* |
|
* If an initialValue is not provided: |
|
* - The previousValue argument is the value of the first element present in the array. |
|
* - The currentValue argument is the value of the second element present in the array. |
|
* |
|
* @private |
|
* @callback coordReduceCallback |
|
* @param {*} previousValue The accumulated value previously returned in the last invocation |
|
* of the callback, or initialValue, if supplied. |
|
* @param {[number, number]} currentCoords The current coordinate being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Reduce coordinates in any GeoJSON object, similar to Array.reduce() |
|
* |
|
* @name coordReduce |
|
* @param {FeatureCollection|Geometry|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (previousValue, currentCoords, currentIndex) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @param {boolean} [excludeWrapCoord=false] whether or not to include |
|
* the final coordinate of LinearRings that wraps the ring in its iteration. |
|
* @returns {*} The value that results from the reduction. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.coordReduce(features, function (previousValue, currentCoords, currentIndex) { |
|
* //=previousValue |
|
* //=currentCoords |
|
* //=currentIndex |
|
* return currentCoords; |
|
* }); |
|
*/ |
|
function coordReduce(geojson, callback, initialValue, excludeWrapCoord) { |
|
var previousValue = initialValue; |
|
coordEach(geojson, function (currentCoords, currentIndex) { |
|
if (currentIndex === 0 && initialValue === undefined) { |
|
previousValue = currentCoords; |
|
} else { |
|
previousValue = callback(previousValue, currentCoords, currentIndex); |
|
} |
|
}, excludeWrapCoord); |
|
return previousValue; |
|
} |
|
|
|
/** |
|
* Callback for propEach |
|
* |
|
* @private |
|
* @callback propEachCallback |
|
* @param {*} currentProperties The current properties being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Iterate over properties in any GeoJSON object, similar to Array.forEach() |
|
* |
|
* @name propEach |
|
* @param {FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (currentProperties, currentIndex) |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"foo": "bar"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"hello": "world"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.propEach(features, function (currentProperties, currentIndex) { |
|
* //=currentProperties |
|
* //=currentIndex |
|
* }); |
|
*/ |
|
function propEach(geojson, callback) { |
|
var i; |
|
switch (geojson.type) { |
|
case 'FeatureCollection': |
|
for (i = 0; i < geojson.features.length; i++) { |
|
callback(geojson.features[i].properties, i); |
|
} |
|
break; |
|
case 'Feature': |
|
callback(geojson.properties, 0); |
|
break; |
|
} |
|
} |
|
|
|
|
|
/** |
|
* Callback for propReduce |
|
* |
|
* The first time the callback function is called, the values provided as arguments depend |
|
* on whether the reduce method has an initialValue argument. |
|
* |
|
* If an initialValue is provided to the reduce method: |
|
* - The previousValue argument is initialValue. |
|
* - The currentValue argument is the value of the first element present in the array. |
|
* |
|
* If an initialValue is not provided: |
|
* - The previousValue argument is the value of the first element present in the array. |
|
* - The currentValue argument is the value of the second element present in the array. |
|
* |
|
* @private |
|
* @callback propReduceCallback |
|
* @param {*} previousValue The accumulated value previously returned in the last invocation |
|
* of the callback, or initialValue, if supplied. |
|
* @param {*} currentProperties The current properties being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Reduce properties in any GeoJSON object into a single value, |
|
* similar to how Array.reduce works. However, in this case we lazily run |
|
* the reduction, so an array of all properties is unnecessary. |
|
* |
|
* @name propReduce |
|
* @param {FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (previousValue, currentProperties, currentIndex) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @returns {*} The value that results from the reduction. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"foo": "bar"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"hello": "world"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.propReduce(features, function (previousValue, currentProperties, currentIndex) { |
|
* //=previousValue |
|
* //=currentProperties |
|
* //=currentIndex |
|
* return currentProperties |
|
* }); |
|
*/ |
|
function propReduce(geojson, callback, initialValue) { |
|
var previousValue = initialValue; |
|
propEach(geojson, function (currentProperties, currentIndex) { |
|
if (currentIndex === 0 && initialValue === undefined) { |
|
previousValue = currentProperties; |
|
} else { |
|
previousValue = callback(previousValue, currentProperties, currentIndex); |
|
} |
|
}); |
|
return previousValue; |
|
} |
|
|
|
/** |
|
* Callback for featureEach |
|
* |
|
* @private |
|
* @callback featureEachCallback |
|
* @param {Feature<any>} currentFeature The current feature being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Iterate over features in any GeoJSON object, similar to |
|
* Array.forEach. |
|
* |
|
* @name featureEach |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (currentFeature, currentIndex) |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.featureEach(features, function (currentFeature, currentIndex) { |
|
* //=currentFeature |
|
* //=currentIndex |
|
* }); |
|
*/ |
|
function featureEach(geojson, callback) { |
|
if (geojson.type === 'Feature') { |
|
callback(geojson, 0); |
|
} else if (geojson.type === 'FeatureCollection') { |
|
for (var i = 0; i < geojson.features.length; i++) { |
|
callback(geojson.features[i], i); |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Callback for featureReduce |
|
* |
|
* The first time the callback function is called, the values provided as arguments depend |
|
* on whether the reduce method has an initialValue argument. |
|
* |
|
* If an initialValue is provided to the reduce method: |
|
* - The previousValue argument is initialValue. |
|
* - The currentValue argument is the value of the first element present in the array. |
|
* |
|
* If an initialValue is not provided: |
|
* - The previousValue argument is the value of the first element present in the array. |
|
* - The currentValue argument is the value of the second element present in the array. |
|
* |
|
* @private |
|
* @callback featureReduceCallback |
|
* @param {*} previousValue The accumulated value previously returned in the last invocation |
|
* of the callback, or initialValue, if supplied. |
|
* @param {Feature<any>} currentFeature The current Feature being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
*/ |
|
|
|
/** |
|
* Reduce features in any GeoJSON object, similar to Array.reduce(). |
|
* |
|
* @name featureReduce |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (previousValue, currentFeature, currentIndex) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @returns {*} The value that results from the reduction. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"foo": "bar"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"hello": "world"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.featureReduce(features, function (previousValue, currentFeature, currentIndex) { |
|
* //=previousValue |
|
* //=currentFeature |
|
* //=currentIndex |
|
* return currentFeature |
|
* }); |
|
*/ |
|
function featureReduce(geojson, callback, initialValue) { |
|
var previousValue = initialValue; |
|
featureEach(geojson, function (currentFeature, currentIndex) { |
|
if (currentIndex === 0 && initialValue === undefined) { |
|
previousValue = currentFeature; |
|
} else { |
|
previousValue = callback(previousValue, currentFeature, currentIndex); |
|
} |
|
}); |
|
return previousValue; |
|
} |
|
|
|
/** |
|
* Get all coordinates from any GeoJSON object. |
|
* |
|
* @name coordAll |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @returns {Array<Array<number>>} coordinate position array |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* var coords = turf.coordAll(features); |
|
* //=coords |
|
*/ |
|
function coordAll(geojson) { |
|
var coords = []; |
|
coordEach(geojson, function (coord) { |
|
coords.push(coord); |
|
}); |
|
return coords; |
|
} |
|
|
|
/** |
|
* Iterate over each geometry in any GeoJSON object, similar to Array.forEach() |
|
* |
|
* @name geomEach |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (currentGeometry, currentIndex, currentProperties) |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.geomEach(features, function (currentGeometry, currentIndex, currentProperties) { |
|
* //=currentGeometry |
|
* //=currentIndex |
|
* //=currentProperties |
|
* }); |
|
*/ |
|
function geomEach(geojson, callback) { |
|
var i, j, g, geometry, stopG, |
|
geometryMaybeCollection, |
|
isGeometryCollection, |
|
geometryProperties, |
|
currentIndex = 0, |
|
isFeatureCollection = geojson.type === 'FeatureCollection', |
|
isFeature = geojson.type === 'Feature', |
|
stop = isFeatureCollection ? geojson.features.length : 1; |
|
|
|
// This logic may look a little weird. The reason why it is that way |
|
// is because it's trying to be fast. GeoJSON supports multiple kinds |
|
// of objects at its root: FeatureCollection, Features, Geometries. |
|
// This function has the responsibility of handling all of them, and that |
|
// means that some of the `for` loops you see below actually just don't apply |
|
// to certain inputs. For instance, if you give this just a |
|
// Point geometry, then both loops are short-circuited and all we do |
|
// is gradually rename the input until it's called 'geometry'. |
|
// |
|
// This also aims to allocate as few resources as possible: just a |
|
// few numbers and booleans, rather than any temporary arrays as would |
|
// be required with the normalization approach. |
|
for (i = 0; i < stop; i++) { |
|
|
|
geometryMaybeCollection = (isFeatureCollection ? geojson.features[i].geometry : |
|
(isFeature ? geojson.geometry : geojson)); |
|
geometryProperties = (isFeatureCollection ? geojson.features[i].properties : |
|
(isFeature ? geojson.properties : {})); |
|
isGeometryCollection = geometryMaybeCollection.type === 'GeometryCollection'; |
|
stopG = isGeometryCollection ? geometryMaybeCollection.geometries.length : 1; |
|
|
|
for (g = 0; g < stopG; g++) { |
|
geometry = isGeometryCollection ? |
|
geometryMaybeCollection.geometries[g] : geometryMaybeCollection; |
|
|
|
if (geometry.type === 'Point' || |
|
geometry.type === 'LineString' || |
|
geometry.type === 'MultiPoint' || |
|
geometry.type === 'Polygon' || |
|
geometry.type === 'MultiLineString' || |
|
geometry.type === 'MultiPolygon') { |
|
callback(geometry, currentIndex, geometryProperties); |
|
currentIndex++; |
|
} else if (geometry.type === 'GeometryCollection') { |
|
for (j = 0; j < geometry.geometries.length; j++) { |
|
callback(geometry.geometries[j], currentIndex, geometryProperties); |
|
currentIndex++; |
|
} |
|
} else { |
|
throw new Error('Unknown Geometry Type'); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* Callback for geomReduce |
|
* |
|
* The first time the callback function is called, the values provided as arguments depend |
|
* on whether the reduce method has an initialValue argument. |
|
* |
|
* If an initialValue is provided to the reduce method: |
|
* - The previousValue argument is initialValue. |
|
* - The currentValue argument is the value of the first element present in the array. |
|
* |
|
* If an initialValue is not provided: |
|
* - The previousValue argument is the value of the first element present in the array. |
|
* - The currentValue argument is the value of the second element present in the array. |
|
* |
|
* @private |
|
* @callback geomReduceCallback |
|
* @param {*} previousValue The accumulated value previously returned in the last invocation |
|
* of the callback, or initialValue, if supplied. |
|
* @param {*} currentGeometry The current Feature being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
* @param {object} currentProperties The current feature properties being processed. |
|
*/ |
|
|
|
/** |
|
* Reduce geometry in any GeoJSON object, similar to Array.reduce(). |
|
* |
|
* @name geomReduce |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (previousValue, currentGeometry, currentIndex, currentProperties) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @returns {*} The value that results from the reduction. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"foo": "bar"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"hello": "world"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [36, 53] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.geomReduce(features, function (previousValue, currentGeometry, currentIndex) { |
|
* //=previousValue |
|
* //=currentGeometry |
|
* //=currentIndex |
|
* return currentGeometry |
|
* }); |
|
*/ |
|
function geomReduce(geojson, callback, initialValue) { |
|
var previousValue = initialValue; |
|
geomEach(geojson, function (currentGeometry, currentIndex, currentProperties) { |
|
if (currentIndex === 0 && initialValue === undefined) { |
|
previousValue = currentGeometry; |
|
} else { |
|
previousValue = callback(previousValue, currentGeometry, currentIndex, currentProperties); |
|
} |
|
}); |
|
return previousValue; |
|
} |
|
|
|
/** |
|
* Callback for flattenEach |
|
* |
|
* @private |
|
* @callback flattenEachCallback |
|
* @param {Feature<any>} currentFeature The current flattened feature being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array. Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
* @param {number} currentSubIndex The subindex of the current element being processed in the |
|
* array. Starts at index 0 and increases if the flattened feature was a multi-geometry. |
|
*/ |
|
|
|
/** |
|
* Iterate over flattened features in any GeoJSON object, similar to |
|
* Array.forEach. |
|
* |
|
* @name flattenEach |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (currentFeature, currentIndex, currentSubIndex) |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {}, |
|
* "geometry": { |
|
* "type": "MultiPoint", |
|
* "coordinates": [ [36, 53], [46, 69] ] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.flattenEach(features, function (currentFeature, currentIndex, currentSubIndex) { |
|
* //=currentFeature |
|
* //=currentIndex |
|
* //=currentSubIndex |
|
* }); |
|
*/ |
|
function flattenEach(geojson, callback) { |
|
geomEach(geojson, function (geometry, index, properties) { |
|
|
|
// Callback for single geometry |
|
switch (geometry.type) { |
|
case 'Point': |
|
case 'LineString': |
|
case 'Polygon': |
|
callback(feature(geometry, properties), index, 0); |
|
return; |
|
} |
|
|
|
var geomType; |
|
|
|
// Callback for multi-geometry |
|
switch (geometry.type) { |
|
case 'MultiPoint': |
|
geomType = 'Point'; |
|
break; |
|
case 'MultiLineString': |
|
geomType = 'LineString'; |
|
break; |
|
case 'MultiPolygon': |
|
geomType = 'Polygon'; |
|
break; |
|
} |
|
|
|
geometry.coordinates.forEach(function (coordinate, subindex) { |
|
var geom = { |
|
type: geomType, |
|
coordinates: coordinate |
|
}; |
|
callback(feature(geom, properties), index, subindex); |
|
}); |
|
|
|
}); |
|
} |
|
|
|
/** |
|
* Callback for flattenReduce |
|
* |
|
* The first time the callback function is called, the values provided as arguments depend |
|
* on whether the reduce method has an initialValue argument. |
|
* |
|
* If an initialValue is provided to the reduce method: |
|
* - The previousValue argument is initialValue. |
|
* - The currentValue argument is the value of the first element present in the array. |
|
* |
|
* If an initialValue is not provided: |
|
* - The previousValue argument is the value of the first element present in the array. |
|
* - The currentValue argument is the value of the second element present in the array. |
|
* |
|
* @private |
|
* @callback flattenReduceCallback |
|
* @param {*} previousValue The accumulated value previously returned in the last invocation |
|
* of the callback, or initialValue, if supplied. |
|
* @param {Feature<any>} currentFeature The current Feature being processed. |
|
* @param {number} currentIndex The index of the current element being processed in the |
|
* array.Starts at index 0, if an initialValue is provided, and at index 1 otherwise. |
|
* @param {number} currentSubIndex The subindex of the current element being processed in the |
|
* array. Starts at index 0 and increases if the flattened feature was a multi-geometry. |
|
*/ |
|
|
|
/** |
|
* Reduce flattened features in any GeoJSON object, similar to Array.reduce(). |
|
* |
|
* @name flattenReduce |
|
* @param {Geometry|FeatureCollection|Feature<any>} geojson any GeoJSON object |
|
* @param {Function} callback a method that takes (previousValue, currentFeature, currentIndex, currentSubIndex) |
|
* @param {*} [initialValue] Value to use as the first argument to the first call of the callback. |
|
* @returns {*} The value that results from the reduction. |
|
* @example |
|
* var features = { |
|
* "type": "FeatureCollection", |
|
* "features": [ |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"foo": "bar"}, |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [26, 37] |
|
* } |
|
* }, |
|
* { |
|
* "type": "Feature", |
|
* "properties": {"hello": "world"}, |
|
* "geometry": { |
|
* "type": "MultiPoint", |
|
* "coordinates": [ [36, 53], [46, 69] ] |
|
* } |
|
* } |
|
* ] |
|
* }; |
|
* turf.flattenReduce(features, function (previousValue, currentFeature, currentIndex, currentSubIndex) { |
|
* //=previousValue |
|
* //=currentFeature |
|
* //=currentIndex |
|
* //=currentSubIndex |
|
* return currentFeature |
|
* }); |
|
*/ |
|
function flattenReduce(geojson, callback, initialValue) { |
|
var previousValue = initialValue; |
|
flattenEach(geojson, function (currentFeature, currentIndex, currentSubIndex) { |
|
if (currentIndex === 0 && currentSubIndex === 0 && initialValue === undefined) { |
|
previousValue = currentFeature; |
|
} else { |
|
previousValue = callback(previousValue, currentFeature, currentIndex, currentSubIndex); |
|
} |
|
}); |
|
return previousValue; |
|
} |
|
|
|
/** |
|
* Create Feature |
|
* |
|
* @private |
|
* @param {Geometry} geometry GeoJSON Geometry |
|
* @param {Object} properties Properties |
|
* @returns {Feature} GeoJSON Feature |
|
*/ |
|
function feature(geometry, properties) { |
|
if (!geometry) throw new Error('No geometry passed'); |
|
|
|
return { |
|
type: 'Feature', |
|
properties: properties || {}, |
|
geometry: geometry |
|
}; |
|
} |
|
|
|
module.exports = { |
|
coordEach: coordEach, |
|
coordReduce: coordReduce, |
|
propEach: propEach, |
|
propReduce: propReduce, |
|
featureEach: featureEach, |
|
featureReduce: featureReduce, |
|
coordAll: coordAll, |
|
geomEach: geomEach, |
|
geomReduce: geomReduce, |
|
flattenEach: flattenEach, |
|
flattenReduce: flattenReduce |
|
}; |
|
|
|
},{}],14:[function(require,module,exports){ |
|
var coordEach = require('@turf/meta').coordEach; |
|
|
|
/** |
|
* Takes a GeoJSON Feature or FeatureCollection and truncates the precision of the geometry. |
|
* |
|
* @name truncate |
|
* @param {FeatureCollection|Feature<any>} geojson any GeoJSON Feature, FeatureCollection, Geometry or GeometryCollection. |
|
* @param {number} [precision=6] coordinate decimal precision |
|
* @param {number} [coordinates=3] maximum number of coordinates (primarly used to remove z coordinates) |
|
* @param {boolean} [mutate=false] allows GeoJSON input to be mutated (significant performance increase if true) |
|
* @returns {FeatureCollection|Feature<any>} layer with truncated geometry |
|
* @example |
|
* var point = { |
|
* "type": "Feature", |
|
* "properties": {} |
|
* "geometry": { |
|
* "type": "Point", |
|
* "coordinates": [ |
|
* 70.46923055566859, |
|
* 58.11088890802906, |
|
* 1508 |
|
* ] |
|
* } |
|
* }; |
|
* var truncated = turf.truncate(point); |
|
* |
|
* //addToMap |
|
* var addToMap = [truncated]; |
|
*/ |
|
module.exports = function (geojson, precision, coordinates, mutate) { |
|
// default params |
|
precision = (precision === undefined || precision === null || isNaN(precision)) ? 6 : precision; |
|
coordinates = (coordinates === undefined || coordinates === null || isNaN(coordinates)) ? 3 : coordinates; |
|
|
|
// validation |
|
if (!geojson) throw new Error('<geojson> is required'); |
|
if (typeof precision !== 'number') throw new Error('<precision> must be a number'); |
|
if (typeof coordinates !== 'number') throw new Error('<coordinates> must be a number'); |
|
|
|
// prevent input mutation |
|
if (mutate === false || mutate === undefined) geojson = JSON.parse(JSON.stringify(geojson)); |
|
|
|
var factor = Math.pow(10, precision); |
|
|
|
// Truncate Coordinates |
|
coordEach(geojson, function (coords) { |
|
truncate(coords, factor, coordinates); |
|
}); |
|
return geojson; |
|
}; |
|
|
|
/** |
|
* Truncate Coordinates - Mutates coordinates in place |
|
* |
|
* @private |
|
* @param {Array<any>} coords Geometry Coordinates |
|
* @param {number} factor rounding factor for coordinate decimal precision |
|
* @param {number} coordinates maximum number of coordinates (primarly used to remove z coordinates) |
|
* @returns {Array<any>} mutated coordinates |
|
*/ |
|
function truncate(coords, factor, coordinates) { |
|
// Remove extra coordinates (usually elevation coordinates and more) |
|
if (coords.length > coordinates) coords.splice(coordinates, coords.length); |
|
|
|
// Truncate coordinate decimals |
|
for (var i = 0; i < coords.length; i++) { |
|
coords[i] = Math.round(coords[i] * factor) / factor; |
|
} |
|
return coords; |
|
} |
|
|
|
},{"@turf/meta":13}]},{},[2]); |