This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******/ (function(modules) { // webpackBootstrap | |
/******/ // The module cache | |
/******/ var installedModules = {}; | |
/******/ // The require function | |
/******/ function __webpack_require__(moduleId) { | |
/******/ // Check if module is in cache | |
/******/ if(installedModules[moduleId]) | |
/******/ return installedModules[moduleId].exports; | |
/******/ // Create a new module (and put it into the cache) | |
/******/ var module = installedModules[moduleId] = { | |
/******/ exports: {}, | |
/******/ id: moduleId, | |
/******/ loaded: false | |
/******/ }; | |
/******/ // Execute the module function | |
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); | |
/******/ // Flag the module as loaded | |
/******/ module.loaded = true; | |
/******/ // Return the exports of the module | |
/******/ return module.exports; | |
/******/ } | |
/******/ // expose the modules object (__webpack_modules__) | |
/******/ __webpack_require__.m = modules; | |
/******/ // expose the module cache | |
/******/ __webpack_require__.c = installedModules; | |
/******/ // __webpack_public_path__ | |
/******/ __webpack_require__.p = "client/"; | |
/******/ // Load entry module and return exports | |
/******/ return __webpack_require__(0); | |
/******/ }) | |
/************************************************************************/ | |
/******/ ([ | |
/* 0 */ | |
/***/ function(module, exports, __webpack_require__) { | |
/* WEBPACK VAR INJECTION */(function(global) {'use strict'; | |
__webpack_require__(1); | |
var _Map = __webpack_require__(5); | |
var _Map2 = _interopRequireDefault(_Map); | |
var _react = __webpack_require__(106); | |
var _react2 = _interopRequireDefault(_react); | |
var _reactDom = __webpack_require__(139); | |
var _reactDom2 = _interopRequireDefault(_reactDom); | |
__webpack_require__(277); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
/* global mapboxgl */ | |
global.mapboxgl = __webpack_require__(101); | |
__webpack_require__(278); | |
// MAPBOX SETUP | |
mapboxgl.accessToken = 'pk.eyJ1IjoiYW1uYXV0aWNhbCIsImEiOiJjaXJveHpjZmcwZTExZmdtOGtwOXhqZzdwIn0.Bm2v9q6DJ0TTXIjj3SI97g'; | |
// instantiate map | |
var m = new _Map2.default(); | |
// instantiate filter | |
// ReactDOM.render(<FilterBar />, document.getElementById('filterbar')); | |
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) | |
/***/ }, | |
/* 1 */ | |
/***/ function(module, exports, __webpack_require__) { | |
// style-loader: Adds some css to the DOM by adding a <style> tag | |
// load the styles | |
var content = __webpack_require__(2); | |
if(typeof content === 'string') content = [[module.id, content, '']]; | |
// add the styles to the DOM | |
var update = __webpack_require__(4)(content, {}); | |
if(content.locals) module.exports = content.locals; | |
// Hot Module Replacement | |
if(false) { | |
// When the styles change, update the <style> tags | |
if(!content.locals) { | |
module.hot.accept("!!./../../node_modules/css-loader/index.js!./../../node_modules/stylus-loader/index.js!./main.styl", function() { | |
var newContent = require("!!./../../node_modules/css-loader/index.js!./../../node_modules/stylus-loader/index.js!./main.styl"); | |
if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; | |
update(newContent); | |
}); | |
} | |
// When the module is disposed, remove the <style> tags | |
module.hot.dispose(function() { update(); }); | |
} | |
/***/ }, | |
/* 2 */ | |
/***/ function(module, exports, __webpack_require__) { | |
exports = module.exports = __webpack_require__(3)(); | |
// imports | |
// module | |
exports.push([module.id, "body {\n margin: 0;\n padding: 0;\n background-color: GhostWhite;\n}\nhr {\n padding: 0px;\n margin: 0px;\n margin-top: 0px;\n margin-bottom: 10px;\n border-color: #59a4d9;\n}\n#features {\n display: none;\n}\n#map {\n position: absolute;\n height: 80vh;\n width: 90vw;\n top: 50%;\n left: 50%;\n margin-top: -40vh;\n margin-left: -45vw;\n}\n.mapboxgl-canvas-container.mapboxgl-interactive,\n.mapboxgl-ctrl-nav-compass {\n cursor: -webkit-grab;\n cursor: -moz-grab;\n cursor: grab;\n}\n.mapboxgl-canvas-container.mapboxgl-interactive:active,\n.mapboxgl-ctrl-nav-compass:active {\n cursor: -webkit-grabbing;\n cursor: -moz-grabbing;\n cursor: grabbing;\n}\n.mapboxgl-popup {\n max-width: 270px;\n font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n z-index: 1000;\n cursor: grab;\n overflow: auto;\n}\n.mapboxgl-popup-close-button {\n position: absolute;\n right: 0;\n top: 0;\n height: 25px;\n width: 25px;\n border: none;\n border-radius: 0 3px 0 3px;\n cursor: pointer;\n font-size: 20px;\n text-align: center;\n vertical-align: middle;\n line-height: 12.5px;\n color: #fff;\n background-color: #52a1d8;\n}\n.mapboxgl-popup-close-button:hover {\n background-color: #63b6e5;\n color: #fff;\n}\n#popup-title {\n color: #000;\n max-width: 230px;\n}\n#popup-subtitle {\n color: #184668;\n max-width: 265px;\n margin-bottom: 0px;\n}\nsmall {\n position: relative;\n margin-bottom: 50px;\n color: #000;\n}\n.read-more-state {\n display: none;\n}\n.read-more-target {\n opacity: 0;\n max-height: 0;\n font-size: 0;\n transition: 0.25s ease;\n}\n.read-more-state:checked ~ .read-more-wrap .read-more-target {\n opacity: 1;\n font-size: inherit;\n max-height: 999em;\n}\n.read-more-ellipses {\n font-weight: bold;\n}\n.read-more-state:checked ~ .read-more-wrap .read-more-ellipses {\n display: none;\n}\n.read-more-state ~ .read-more-trigger:before {\n content: 'Show More';\n}\n.read-more-state:checked ~ .read-more-trigger:before {\n content: 'Show Less';\n}\n.read-more-trigger {\n position: absolute;\n margin-top: 1px;\n cursor: pointer;\n/*display: inline-block;*/\n left: 155.781px;\n bottom: 26px;\n padding: 0 0.5em;\n color: #2671a6;\n font-size: 0.9em;\n line-height: 2;\n border: 1px solid #ddd;\n border-radius: 0.25em;\n border-color: #2671a6;\n}\n.read-more-trigger:hover {\n color: #fff;\n background-color: #52a1d8;\n border-color: #52a1d8;\n}\n.button {\n background-color: #3887be;\n text-align: center;\n color: #fff;\n display: inline-block;\n margin: 0px;\n padding: 10px;\n position: absolute;\n bottom: 10px;\n left: 10px;\n border: none;\n cursor: pointer;\n border-radius: 3px;\n white-space: nowrap;\n text-overflow: ellipsis;\n font-family: 'Open Sans Bold', sans-serif;\n font-size: 12px;\n text-align: center;\n vertical-align: middle;\n -webkit-appearance: none;\n -webkit-font-smoothing: antialiased;\n}\n.button.icon.home {\n position: absolute;\n left: 10px;\n top: 160px;\n height: 30px;\n width: 30px;\n color: #000;\n background: #fff;\n/*border: 1px solid rgba(0,0,0,0.1);*/\n box-shadow: 0px 0px 5px rgba(0,0,0,0.35);\n padding: 4.5px;\n cursor: pointer;\n z-index: 1000;\n}\n.button.icon.home:hover {\n background-color: #ddd;\n}\n.rounded-toggle {\n margin-top: 0px;\n margin-bottom: 0px;\n padding: 2.5px;\n border-radius: 3px;\n vertical-align: middle;\n line-height: 15.5px;\n background: rgba(0,0,0,0.1);\n box-shadow: 0px 0px 5px rgba(0,0,0,0.35);\n}\n.rounded-toggle.inline {\n position: absolute;\n bottom: 10px;\n left: 10px;\n z-index: 1000;\n background: #fff;\n}\n.rounded-toggle > * {\n color: #133853;\n border-radius: 3px;\n}\n.rounded-toggle input[type=radio]:checked + label,\n.rounded-toggle .active {\n background: #52a1d8;\n color: #fff;\n}\n.checkbox-inline {\n margin-top: 0px;\n margin-bottom: 0px;\n padding: 2.5px;\n border-radius: 3px 3px 0 0;\n vertical-align: middle;\n background: rgba(0,0,0,0.1);\n position: absolute;\n bottom: 40px;\n left: 10px;\n z-index: 1000;\n background: #fff;\n}\n.subproduct-checkbox {\n position: relative;\n width: 100px;\n height: 100px;\n}\n", ""]); | |
// exports | |
/***/ }, | |
/* 3 */ | |
/***/ function(module, exports) { | |
/* | |
MIT License http://www.opensource.org/licenses/mit-license.php | |
Author Tobias Koppers @sokra | |
*/ | |
// css base code, injected by the css-loader | |
module.exports = function() { | |
var list = []; | |
// return the list of modules as css string | |
list.toString = function toString() { | |
var result = []; | |
for(var i = 0; i < this.length; i++) { | |
var item = this[i]; | |
if(item[2]) { | |
result.push("@media " + item[2] + "{" + item[1] + "}"); | |
} else { | |
result.push(item[1]); | |
} | |
} | |
return result.join(""); | |
}; | |
// import a list of modules into the list | |
list.i = function(modules, mediaQuery) { | |
if(typeof modules === "string") | |
modules = [[null, modules, ""]]; | |
var alreadyImportedModules = {}; | |
for(var i = 0; i < this.length; i++) { | |
var id = this[i][0]; | |
if(typeof id === "number") | |
alreadyImportedModules[id] = true; | |
} | |
for(i = 0; i < modules.length; i++) { | |
var item = modules[i]; | |
// skip already imported module | |
// this implementation is not 100% perfect for weird media query combinations | |
// when a module is imported multiple times with different media queries. | |
// I hope this will never occur (Hey this way we have smaller bundles) | |
if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { | |
if(mediaQuery && !item[2]) { | |
item[2] = mediaQuery; | |
} else if(mediaQuery) { | |
item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; | |
} | |
list.push(item); | |
} | |
} | |
}; | |
return list; | |
}; | |
/***/ }, | |
/* 4 */ | |
/***/ function(module, exports, __webpack_require__) { | |
/* | |
MIT License http://www.opensource.org/licenses/mit-license.php | |
Author Tobias Koppers @sokra | |
*/ | |
var stylesInDom = {}, | |
memoize = function(fn) { | |
var memo; | |
return function () { | |
if (typeof memo === "undefined") memo = fn.apply(this, arguments); | |
return memo; | |
}; | |
}, | |
isOldIE = memoize(function() { | |
return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()); | |
}), | |
getHeadElement = memoize(function () { | |
return document.head || document.getElementsByTagName("head")[0]; | |
}), | |
singletonElement = null, | |
singletonCounter = 0, | |
styleElementsInsertedAtTop = []; | |
module.exports = function(list, options) { | |
if(false) { | |
if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); | |
} | |
options = options || {}; | |
// Force single-tag solution on IE6-9, which has a hard limit on the # of <style> | |
// tags it will allow on a page | |
if (typeof options.singleton === "undefined") options.singleton = isOldIE(); | |
// By default, add <style> tags to the bottom of <head>. | |
if (typeof options.insertAt === "undefined") options.insertAt = "bottom"; | |
var styles = listToStyles(list); | |
addStylesToDom(styles, options); | |
return function update(newList) { | |
var mayRemove = []; | |
for(var i = 0; i < styles.length; i++) { | |
var item = styles[i]; | |
var domStyle = stylesInDom[item.id]; | |
domStyle.refs--; | |
mayRemove.push(domStyle); | |
} | |
if(newList) { | |
var newStyles = listToStyles(newList); | |
addStylesToDom(newStyles, options); | |
} | |
for(var i = 0; i < mayRemove.length; i++) { | |
var domStyle = mayRemove[i]; | |
if(domStyle.refs === 0) { | |
for(var j = 0; j < domStyle.parts.length; j++) | |
domStyle.parts[j](); | |
delete stylesInDom[domStyle.id]; | |
} | |
} | |
}; | |
} | |
function addStylesToDom(styles, options) { | |
for(var i = 0; i < styles.length; i++) { | |
var item = styles[i]; | |
var domStyle = stylesInDom[item.id]; | |
if(domStyle) { | |
domStyle.refs++; | |
for(var j = 0; j < domStyle.parts.length; j++) { | |
domStyle.parts[j](item.parts[j]); | |
} | |
for(; j < item.parts.length; j++) { | |
domStyle.parts.push(addStyle(item.parts[j], options)); | |
} | |
} else { | |
var parts = []; | |
for(var j = 0; j < item.parts.length; j++) { | |
parts.push(addStyle(item.parts[j], options)); | |
} | |
stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts}; | |
} | |
} | |
} | |
function listToStyles(list) { | |
var styles = []; | |
var newStyles = {}; | |
for(var i = 0; i < list.length; i++) { | |
var item = list[i]; | |
var id = item[0]; | |
var css = item[1]; | |
var media = item[2]; | |
var sourceMap = item[3]; | |
var part = {css: css, media: media, sourceMap: sourceMap}; | |
if(!newStyles[id]) | |
styles.push(newStyles[id] = {id: id, parts: [part]}); | |
else | |
newStyles[id].parts.push(part); | |
} | |
return styles; | |
} | |
function insertStyleElement(options, styleElement) { | |
var head = getHeadElement(); | |
var lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1]; | |
if (options.insertAt === "top") { | |
if(!lastStyleElementInsertedAtTop) { | |
head.insertBefore(styleElement, head.firstChild); | |
} else if(lastStyleElementInsertedAtTop.nextSibling) { | |
head.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling); | |
} else { | |
head.appendChild(styleElement); | |
} | |
styleElementsInsertedAtTop.push(styleElement); | |
} else if (options.insertAt === "bottom") { | |
head.appendChild(styleElement); | |
} else { | |
throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'."); | |
} | |
} | |
function removeStyleElement(styleElement) { | |
styleElement.parentNode.removeChild(styleElement); | |
var idx = styleElementsInsertedAtTop.indexOf(styleElement); | |
if(idx >= 0) { | |
styleElementsInsertedAtTop.splice(idx, 1); | |
} | |
} | |
function createStyleElement(options) { | |
var styleElement = document.createElement("style"); | |
styleElement.type = "text/css"; | |
insertStyleElement(options, styleElement); | |
return styleElement; | |
} | |
function createLinkElement(options) { | |
var linkElement = document.createElement("link"); | |
linkElement.rel = "stylesheet"; | |
insertStyleElement(options, linkElement); | |
return linkElement; | |
} | |
function addStyle(obj, options) { | |
var styleElement, update, remove; | |
if (options.singleton) { | |
var styleIndex = singletonCounter++; | |
styleElement = singletonElement || (singletonElement = createStyleElement(options)); | |
update = applyToSingletonTag.bind(null, styleElement, styleIndex, false); | |
remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true); | |
} else if(obj.sourceMap && | |
typeof URL === "function" && | |
typeof URL.createObjectURL === "function" && | |
typeof URL.revokeObjectURL === "function" && | |
typeof Blob === "function" && | |
typeof btoa === "function") { | |
styleElement = createLinkElement(options); | |
update = updateLink.bind(null, styleElement); | |
remove = function() { | |
removeStyleElement(styleElement); | |
if(styleElement.href) | |
URL.revokeObjectURL(styleElement.href); | |
}; | |
} else { | |
styleElement = createStyleElement(options); | |
update = applyToTag.bind(null, styleElement); | |
remove = function() { | |
removeStyleElement(styleElement); | |
}; | |
} | |
update(obj); | |
return function updateStyle(newObj) { | |
if(newObj) { | |
if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) | |
return; | |
update(obj = newObj); | |
} else { | |
remove(); | |
} | |
}; | |
} | |
var replaceText = (function () { | |
var textStore = []; | |
return function (index, replacement) { | |
textStore[index] = replacement; | |
return textStore.filter(Boolean).join('\n'); | |
}; | |
})(); | |
function applyToSingletonTag(styleElement, index, remove, obj) { | |
var css = remove ? "" : obj.css; | |
if (styleElement.styleSheet) { | |
styleElement.styleSheet.cssText = replaceText(index, css); | |
} else { | |
var cssNode = document.createTextNode(css); | |
var childNodes = styleElement.childNodes; | |
if (childNodes[index]) styleElement.removeChild(childNodes[index]); | |
if (childNodes.length) { | |
styleElement.insertBefore(cssNode, childNodes[index]); | |
} else { | |
styleElement.appendChild(cssNode); | |
} | |
} | |
} | |
function applyToTag(styleElement, obj) { | |
var css = obj.css; | |
var media = obj.media; | |
if(media) { | |
styleElement.setAttribute("media", media) | |
} | |
if(styleElement.styleSheet) { | |
styleElement.styleSheet.cssText = css; | |
} else { | |
while(styleElement.firstChild) { | |
styleElement.removeChild(styleElement.firstChild); | |
} | |
styleElement.appendChild(document.createTextNode(css)); | |
} | |
} | |
function updateLink(linkElement, obj) { | |
var css = obj.css; | |
var sourceMap = obj.sourceMap; | |
if(sourceMap) { | |
// http://stackoverflow.com/a/26603875 | |
css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */"; | |
} | |
var blob = new Blob([css], { type: "text/css" }); | |
var oldSrc = linkElement.href; | |
linkElement.href = URL.createObjectURL(blob); | |
if(oldSrc) | |
URL.revokeObjectURL(oldSrc); | |
} | |
/***/ }, | |
/* 5 */ | |
/***/ function(module, exports, __webpack_require__) { | |
/* WEBPACK VAR INJECTION */(function(global) {'use strict'; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | |
var _popup = __webpack_require__(6); | |
var _popup2 = _interopRequireDefault(_popup); | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | |
/* global mapboxgl, fetch, document */ | |
var styleSatellite = 'mapbox://styles/amnautical/cis3qzy4t001bgrm8kf2c3rxy'; | |
var styleAtlas = 'mapbox://styles/amnautical/cirxxvcxf000ugbm2sxnyi067'; | |
var debounce = __webpack_require__(7); | |
global.turf = __webpack_require__(9); | |
global.mapboxgl = __webpack_require__(101); | |
var Map = function () { | |
function Map(cont) { | |
var _this = this; | |
_classCallCheck(this, Map); | |
this.map = new mapboxgl.Map({ | |
container: cont || 'map', | |
style: styleSatellite, | |
repaint: true, | |
center: [0, 38], | |
zoom: 1 | |
}); | |
this.firstDraw = true; | |
this.controlsLoaded = false; | |
this.bindEvents(); | |
// tried to bind all events but didn't work for some reason | |
this.map.on('load', function () { | |
_this.map.on('mousemove', debounce(_this.onMouseMove.bind(_this), 15)); | |
}); | |
} | |
_createClass(Map, [{ | |
key: 'bindEvents', | |
value: function bindEvents() { | |
this.map.on('style.load', this.onStyleLoaded.bind(this)); | |
this.map.on('click', this.onMapClicked.bind(this)); | |
this.map.on('dblclick', this.onMapDoubleClicked.bind(this)); | |
} | |
}, { | |
key: 'onMapDoubleClicked', | |
value: function onMapDoubleClicked(e) { | |
var features = this.map.queryRenderedFeatures(e.point, { layers: ['polygon-fills-invisi'] }); | |
if (!features.length) { | |
return; | |
} | |
this.map.fitBounds(JSON.parse(features[0].properties.bbox), { padding: 30 }); | |
// this.map.fitBounds(bbox, { padding: 30 }); | |
} | |
}, { | |
key: 'onMouseMove', | |
value: function onMouseMove(e) { | |
var features = this.map.queryRenderedFeatures(e.point, { layers: ['polygon-fills-invisi'] }); | |
if (features.length) { | |
this.map.setFilter('polygon-outlines-hover', ["==", "description", features[0].properties.description]); | |
} else { | |
this.map.setFilter('polygon-outlines-hover', ["==", "description", ""]); | |
} | |
} | |
}, { | |
key: 'onMapClicked', | |
value: function onMapClicked(e) { | |
var features = this.map.queryRenderedFeatures(e.point, { layers: ['polygon-fills-invisi'] }); | |
// clicking outside of a polygon | |
if (!features.length) { | |
this.map.setFilter('polygon-fills-selected', ["==", "description", ""]); | |
this.map.setFilter('polygon-outlines-selected', ["==", "description", ""]); | |
} else { | |
var props = features[0].properties; | |
var desc = props.description; | |
var title = props.title; | |
console.log(props); | |
var html = props.html; | |
html = html.replace(/\s+/g, ' ').trim(); | |
html = html.split('<p>')[1].split('</p>')[0]; | |
var src = JSON.parse(props.images)[0].src; | |
this.map.setFilter('polygon-fills-selected', ["==", "description", props.description]); | |
this.map.setFilter('polygon-outlines-selected', ["==", "description", props.description]); | |
var pop = new mapboxgl.Popup().setLngLat(e.lngLat).setHTML((0, _popup2.default)(desc, title, html, src)).addTo(this.map); | |
} | |
} | |
}, { | |
key: 'onStyleLoaded', | |
value: function onStyleLoaded() { | |
this.drawFromUrl('https://gist.githubusercontent.com/eltonjuan/ef8d053ef89ca9100f11b332c3f5ab02/raw/f3d94d9a29a0bfe20d60a438b35f2209d6a24eb1/wifHTML.json'); | |
} | |
}, { | |
key: 'drawFromUrl', | |
value: function drawFromUrl(dataUrl) { | |
var _this2 = this; | |
this.labelGeojson = { "type": "FeatureCollection", "features": [] }; | |
fetch(dataUrl).then(function (res) { | |
return res.json(); | |
}).then(function (json) { | |
json.stops = json.features[0].properties.polygonStops; | |
json.labelStops = json.features[0].properties.labelStops; | |
json.features.forEach(function (feature) { | |
var props = feature.properties; | |
var centroid = turf.centroid(feature); | |
centroid.properties = { | |
name: props.name, | |
icon: props.labelIcon, | |
region: props.region | |
}; | |
_this2.labelGeojson.features.push(centroid); | |
}); | |
_this2.geojson = json; | |
_this2.drawLayers(json); | |
_this2.addControls(); | |
}); | |
} | |
}, { | |
key: 'addControls', | |
value: function addControls() { | |
if (!this.controlsLoaded) { | |
// LAYER SWITCH | |
var toggles = document.querySelectorAll('[name="rtoggle"]'); | |
var toggle = document.getElementById('styleToggle'); | |
toggle.onclick = this.swapStyles.bind(this); | |
// GEOCODER | |
this.map.addControl(new mapboxgl.Geocoder()); | |
// ZOOM CONTROLS | |
this.map.addControl(new mapboxgl.Navigation({ | |
position: 'top-left' | |
})); | |
} | |
this.controlsLoaded = true; | |
} | |
}, { | |
key: 'swapStyles', | |
value: function swapStyles(e) { | |
var id = e.target.id; | |
switch (id) { | |
case "satellite": | |
this.map.setStyle(styleSatellite); | |
break; | |
case "atlas": | |
this.map.setStyle(styleAtlas); | |
break; | |
default: | |
break; | |
} | |
} | |
}, { | |
key: 'resetBounds', | |
value: function resetBounds() { | |
var bbox = turf.bbox(this.geojson); | |
this.map.fitBounds(bbox, { padding: '20' }); | |
} | |
}, { | |
key: 'drawLayers', | |
value: function drawLayers(geojson) { | |
if (this.firstDraw) { | |
var bbox = turf.bbox(geojson); | |
this.map.fitBounds(bbox, { padding: '20' }); | |
var homeButton = document.getElementById('fullExtentToggle'); | |
homeButton.onclick = this.resetBounds.bind(this); | |
} | |
this.map.addSource('garmin_labels', { | |
type: 'geojson', | |
data: this.labelGeojson | |
}); | |
this.map.addSource('garmin', { | |
type: 'geojson', | |
data: geojson | |
}); | |
this.map.addLayer({ | |
'id': 'polygon-outlines', | |
'type': 'line', | |
'source': 'garmin', | |
'paint': { | |
'line-width': 2, | |
'line-opacity': .65, | |
'line-color': { | |
property: 'region', | |
type: 'categorical', | |
stops: geojson.stops | |
} | |
} | |
}); | |
this.map.addLayer({ | |
"id": 'polygon-fills-invisi', | |
"type": "fill", | |
"source": 'garmin', | |
'layout': {}, | |
'paint': { | |
'fill-opacity': 0 | |
} | |
}, 'atlas'); | |
this.map.addLayer({ | |
'id': 'polygon-outlines-hover', | |
'type': 'line', | |
'source': 'garmin', | |
'paint': { | |
'line-width': 4, | |
'line-opacity': 1, | |
'line-color': { | |
property: 'region', | |
type: 'categorical', | |
stops: geojson.stops | |
} | |
}, | |
"filter": ["==", "description", ""] | |
}); | |
this.map.addLayer({ | |
"id": 'polygon-outlines-selected', | |
"type": "line", | |
"source": 'garmin', | |
'layout': {}, | |
'paint': { | |
'line-width': 2, | |
'line-opacity': 1, | |
'line-color': { | |
property: 'region', | |
type: 'categorical', | |
stops: geojson.stops | |
} | |
}, | |
"filter": ["==", "description", ""] | |
}); | |
this.map.addLayer({ | |
"id": 'polygon-fills-selected', | |
"type": "fill", | |
"source": 'garmin', | |
'paint': { | |
'fill-color': { | |
property: 'region', | |
type: 'categorical', | |
stops: geojson.stops | |
}, | |
'fill-opacity': .15 | |
}, | |
"filter": ["==", "description", ""] | |
}, 'atlas'); | |
this.map.addLayer({ | |
type: 'symbol', | |
id: 'polygon-labels-text', | |
source: 'garmin', | |
layout: { | |
'icon-image': '{labelIcon}' | |
} | |
}); | |
this.map.addLayer({ | |
"id": "polygon-labels-text", | |
"type": "symbol", | |
"source": "garmin_labels", | |
"layout": { | |
"text-field": "{name}", | |
"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], | |
"text-anchor": "top", | |
"icon-image": "{icon}", | |
"icon-text-fit": "both", | |
"icon-text-fit-padding": [0, 6, 2, 2] | |
}, | |
"paint": { | |
"text-color": { | |
property: 'region', | |
type: 'categorical', | |
stops: geojson.labelStops | |
} | |
} | |
}); | |
this.firstDraw = false; | |
} | |
}]); | |
return Map; | |
}(); | |
exports.default = Map; | |
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) | |
/***/ }, | |
/* 6 */ | |
/***/ function(module, exports) { | |
"use strict"; | |
Object.defineProperty(exports, "__esModule", { | |
value: true | |
}); | |
exports.default = function (desc, title, html, src) { | |
var MAX_CHARS = 220; | |
var splitIndex = html.indexOf(" ", MAX_CHARS); | |
var pReadPreview = html.slice(0, splitIndex); | |
var pReadMore = " ".concat(html.slice(splitIndex + 1)); | |
var descriptionHTML = ''; | |
if (html.length > MAX_CHARS + 35) { | |
descriptionHTML = "\n <input type=\"checkbox\" class=\"read-more-state\" id=\"post-1\"/> <small class = \"read-more-wrap\">" + pReadPreview + "<span class = \"read-more-ellipses\">...</span><span class = \"read-more-target\">" + pReadMore + "</span></small> <label for=\"post-1\" class=\"read-more-trigger\"></label> "; | |
} else { | |
descriptionHTML = "<small>" + html + "</small>"; | |
} | |
return "\n <div class = \"pop-up-container\">\n <h3 id = 'popup-title'>" + desc + "</h3>\n <h4 id = 'popup-subtitle'>" + title + "</h4>\n <hr id = 'popup-title'>\n " + descriptionHTML + " \n <a href='" + src + "' target = '_blank' class='button icon next' id='viewProductButton'>VIEW PRODUCT</a>\n </div>\n "; | |
}; | |
/***/ }, | |
/* 7 */ | |
/***/ function(module, exports, __webpack_require__) { | |
/** | |
* Module dependencies. | |
*/ | |
var now = __webpack_require__(8); | |
/** | |
* Returns a function, that, as long as it continues to be invoked, will not | |
* be triggered. The function will be called after it stops being called for | |
* N milliseconds. If `immediate` is passed, trigger the function on the | |
* leading edge, instead of the trailing. | |
* | |
* @source underscore.js | |
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ | |
* @param {Function} function to wrap | |
* @param {Number} timeout in ms (`100`) | |
* @param {Boolean} whether to execute at the beginning (`false`) | |
* @api public | |
*/ | |
module.exports = function debounce(func, wait, immediate){ | |
var timeout, args, context, timestamp, result; | |
if (null == wait) wait = 100; | |
function later() { | |
var last = now() - timestamp; | |
if (last < wait && last > 0) { | |
timeout = setTimeout(later, wait - last); | |
} else { | |
timeout = null; | |
if (!immediate) { | |
result = func.apply(context, args); | |
if (!timeout) context = args = null; | |
} | |
} | |
}; | |
return function debounced() { | |
context = this; | |
args = arguments; | |
timestamp = now(); | |
var callNow = immediate && !timeout; | |
if (!timeout) timeout = setTimeout(later, wait); | |
if (callNow) { | |
result = func.apply(context, args); | |
context = args = null; | |
} | |
return result; | |
}; | |
}; | |
/***/ }, | |
/* 8 */ | |
/***/ function(module, exports) { | |
module.exports = Date.now || now | |
function now() { | |
return new Date().getTime() | |
} | |
/***/ }, | |
/* 9 */ | |
/***/ function(module, exports, __webpack_require__) { | |
/*eslint global-require: 0*/ | |
/** | |
* Turf is a modular geospatial analysis engine written in JavaScript. It performs geospatial | |
* processing tasks with GeoJSON data and can be run on a server or in a browser. | |
* | |
* @module turf | |
* @summary Geospatial analysis for JavaScript | |
*/ | |
module.exports = { | |
isolines: __webpack_require__(10), | |
convex: __webpack_require__(24), | |
within: __webpack_require__(53), | |
concave: __webpack_require__(54), | |
difference: __webpack_require__(57), | |
collect: __webpack_require__(59), | |
flip: __webpack_require__(60), | |
simplify: __webpack_require__(61), | |
bezier: __webpack_require__(63), | |
tag: __webpack_require__(65), | |
sample: __webpack_require__(66), | |
envelope: __webpack_require__(67), | |
square: __webpack_require__(20), | |
midpoint: __webpack_require__(69), | |
buffer: __webpack_require__(74), | |
center: __webpack_require__(77), | |
centroid: __webpack_require__(78), | |
combine: __webpack_require__(79), | |
distance: __webpack_require__(21), | |
explode: __webpack_require__(80), | |
bbox: __webpack_require__(17), | |
tesselate: __webpack_require__(81), | |
bboxPolygon: __webpack_require__(68), | |
inside: __webpack_require__(13), | |
intersect: __webpack_require__(83), | |
nearest: __webpack_require__(85), | |
planepoint: __webpack_require__(19), | |
random: __webpack_require__(86), | |
tin: __webpack_require__(11), | |
union: __webpack_require__(55), | |
bearing: __webpack_require__(70), | |
destination: __webpack_require__(72), | |
kinks: __webpack_require__(88), | |
pointOnSurface: __webpack_require__(89), | |
area: __webpack_require__(90), | |
along: __webpack_require__(93), | |
lineDistance: __webpack_require__(94), | |
lineSlice: __webpack_require__(95), | |
pointOnLine: __webpack_require__(96), | |
pointGrid: __webpack_require__(97), | |
squareGrid: __webpack_require__(98), | |
triangleGrid: __webpack_require__(99), | |
hexGrid: __webpack_require__(100) | |
}; | |
var helpers = __webpack_require__(12); | |
module.exports.point = helpers.point; | |
module.exports.polygon = helpers.polygon; | |
module.exports.lineString = helpers.lineString; | |
module.exports.multiPoint = helpers.multiPoint; | |
module.exports.multiPolygon = helpers.multiPolygon; | |
module.exports.multiLineString = helpers.multiLineString; | |
module.exports.feature = helpers.feature; | |
module.exports.featureCollection = helpers.featureCollection; | |
module.exports.geometryCollection = helpers.geometryCollection; | |
/***/ }, | |
/* 10 */ | |
/***/ function(module, exports, __webpack_require__) { | |
//https://github.com/jasondavies/conrec.js | |
//http://stackoverflow.com/questions/263305/drawing-a-topographical-map | |
var tin = __webpack_require__(11); | |
var inside = __webpack_require__(13); | |
var grid = __webpack_require__(15); | |
var bbox = __webpack_require__(17); | |
var planepoint = __webpack_require__(19); | |
var featurecollection = __webpack_require__(12).featureCollection; | |
var linestring = __webpack_require__(12).lineString; | |
var square = __webpack_require__(20); | |
var Conrec = __webpack_require__(23); | |
/** | |
* Takes {@link Point|points} with z-values and an array of | |
* value breaks and generates [isolines](http://en.wikipedia.org/wiki/Isoline). | |
* | |
* @name isolines | |
* @param {FeatureCollection<Point>} points input points | |
* @param {string} z the property name in `points` from which z-values will be pulled | |
* @param {number} resolution resolution of the underlying grid | |
* @param {Array<number>} breaks where to draw contours | |
* @returns {FeatureCollection<LineString>} isolines | |
* @example | |
* // create random points with random | |
* // z-values in their properties | |
* var points = turf.random('point', 100, { | |
* bbox: [0, 30, 20, 50] | |
* }); | |
* for (var i = 0; i < points.features.length; i++) { | |
* points.features[i].properties.z = Math.random() * 10; | |
* } | |
* var breaks = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; | |
* var isolined = turf.isolines(points, 'z', 15, breaks); | |
* //=isolined | |
*/ | |
module.exports = function (points, z, resolution, breaks) { | |
var tinResult = tin(points, z); | |
var bboxBBox = bbox(points); | |
var squareBBox = square(bboxBBox); | |
var gridResult = grid(squareBBox, resolution); | |
var data = []; | |
for (var i = 0; i < gridResult.features.length; i++) { | |
var pt = gridResult.features[i]; | |
for (var j = 0; j < tinResult.features.length; j++) { | |
var triangle = tinResult.features[j]; | |
if (inside(pt, triangle)) { | |
pt.properties = {}; | |
pt.properties[z] = planepoint(pt, triangle); | |
} | |
} | |
} | |
var depth = Math.sqrt(gridResult.features.length); | |
for (var x = 0; x < depth; x++) { | |
var xGroup = gridResult.features.slice(x * depth, (x + 1) * depth); | |
var xFlat = []; | |
for (var g = 0; g < xGroup.length; g++) { | |
if (xGroup[g].properties) { | |
xFlat.push(xGroup[g].properties[z]); | |
} else { | |
xFlat.push(0); | |
} | |
} | |
data.push(xFlat); | |
} | |
var interval = (squareBBox[2] - squareBBox[0]) / depth; | |
var xCoordinates = []; | |
var yCoordinates = []; | |
for (var d = 0; d < depth; d++) { | |
xCoordinates.push(d * interval + squareBBox[0]); | |
yCoordinates.push(d * interval + squareBBox[1]); | |
} | |
var c = new Conrec(); | |
c.contour(data, 0, resolution, 0, resolution, xCoordinates, yCoordinates, breaks.length, breaks); | |
var contourList = c.contourList(); | |
var fc = featurecollection([]); | |
contourList.forEach(function (c) { | |
if (c.length > 2) { | |
var polyCoordinates = []; | |
c.forEach(function (coord) { | |
polyCoordinates.push([coord.x, coord.y]); | |
}); | |
var poly = linestring(polyCoordinates); | |
poly.properties = {}; | |
poly.properties[z] = c.level; | |
fc.features.push(poly); | |
} | |
}); | |
return fc; | |
}; | |
/***/ }, | |
/* 11 */ | |
/***/ function(module, exports, __webpack_require__) { | |
//http://en.wikipedia.org/wiki/Delaunay_triangulation | |
//https://github.com/ironwallaby/delaunay | |
var polygon = __webpack_require__(12).polygon; | |
var featurecollection = __webpack_require__(12).featureCollection; | |
/** | |
* Takes a set of {@link Point|points} and the name of a z-value property and | |
* creates a [Triangulated Irregular Network](http://en.wikipedia.org/wiki/Triangulated_irregular_network), | |
* or a TIN for short, returned as a collection of Polygons. These are often used | |
* for developing elevation contour maps or stepped heat visualizations. | |
* | |
* This triangulates the points, as well as adds properties called `a`, `b`, | |
* and `c` representing the value of the given `propertyName` at each of | |
* the points that represent the corners of the triangle. | |
* | |
* @name tin | |
* @param {FeatureCollection<Point>} points input points | |
* @param {String=} z name of the property from which to pull z values | |
* This is optional: if not given, then there will be no extra data added to the derived triangles. | |
* @return {FeatureCollection<Polygon>} TIN output | |
* @example | |
* // generate some random point data | |
* var points = turf.random('points', 30, { | |
* bbox: [50, 30, 70, 50] | |
* }); | |
* //=points | |
* // add a random property to each point between 0 and 9 | |
* for (var i = 0; i < points.features.length; i++) { | |
* points.features[i].properties.z = ~~(Math.random() * 9); | |
* } | |
* var tin = turf.tin(points, 'z') | |
* for (var i = 0; i < tin.features.length; i++) { | |
* var properties = tin.features[i].properties; | |
* // roughly turn the properties of each | |
* // triangle into a fill color | |
* // so we can visualize the result | |
* properties.fill = '#' + properties.a + | |
* properties.b + properties.c; | |
* } | |
* //=tin | |
*/ | |
module.exports = function (points, z) { | |
//break down points | |
return featurecollection(triangulate(points.features.map(function (p) { | |
var point = { | |
x: p.geometry.coordinates[0], | |
y: p.geometry.coordinates[1] | |
}; | |
if (z) point.z = p.properties[z]; | |
return point; | |
})).map(function (triangle) { | |
return polygon([[ | |
[triangle.a.x, triangle.a.y], | |
[triangle.b.x, triangle.b.y], | |
[triangle.c.x, triangle.c.y], | |
[triangle.a.x, triangle.a.y] | |
]], { | |
a: triangle.a.z, | |
b: triangle.b.z, | |
c: triangle.c.z | |
}); | |
})); | |
}; | |
function Triangle(a, b, c) { | |
this.a = a; | |
this.b = b; | |
this.c = c; | |
var A = b.x - a.x, | |
B = b.y - a.y, | |
C = c.x - a.x, | |
D = c.y - a.y, | |
E = A * (a.x + b.x) + B * (a.y + b.y), | |
F = C * (a.x + c.x) + D * (a.y + c.y), | |
G = 2 * (A * (c.y - b.y) - B * (c.x - b.x)), | |
minx, miny, dx, dy; | |
// If the points of the triangle are collinear, then just find the | |
// extremes and use the midpoint as the center of the circumcircle. | |
if (Math.abs(G) < 0.000001) { | |
minx = Math.min(a.x, b.x, c.x); | |
miny = Math.min(a.y, b.y, c.y); | |
dx = (Math.max(a.x, b.x, c.x) - minx) * 0.5; | |
dy = (Math.max(a.y, b.y, c.y) - miny) * 0.5; | |
this.x = minx + dx; | |
this.y = miny + dy; | |
this.r = dx * dx + dy * dy; | |
} else { | |
this.x = (D * E - B * F) / G; | |
this.y = (A * F - C * E) / G; | |
dx = this.x - a.x; | |
dy = this.y - a.y; | |
this.r = dx * dx + dy * dy; | |
} | |
} | |
function byX(a, b) { | |
return b.x - a.x; | |
} | |
function dedup(edges) { | |
var j = edges.length, | |
a, b, i, m, n; | |
outer: | |
while (j) { | |
b = edges[--j]; | |
a = edges[--j]; | |
i = j; | |
while (i) { | |
n = edges[--i]; | |
m = edges[--i]; | |
if ((a === m && b === n) || (a === n && b === m)) { | |
edges.splice(j, 2); | |
edges.splice(i, 2); | |
j -= 2; | |
continue outer; | |
} | |
} | |
} | |
} | |
function triangulate(vertices) { | |
// Bail if there aren't enough vertices to form any triangles. | |
if (vertices.length < 3) | |
return []; | |
// Ensure the vertex array is in order of descending X coordinate | |
// (which is needed to ensure a subquadratic runtime), and then find | |
// the bounding box around the points. | |
vertices.sort(byX); | |
var i = vertices.length - 1, | |
xmin = vertices[i].x, | |
xmax = vertices[0].x, | |
ymin = vertices[i].y, | |
ymax = ymin; | |
while (i--) { | |
if (vertices[i].y < ymin) | |
ymin = vertices[i].y; | |
if (vertices[i].y > ymax) | |
ymax = vertices[i].y; | |
} | |
//Find a supertriangle, which is a triangle that surrounds all the | |
//vertices. This is used like something of a sentinel value to remove | |
//cases in the main algorithm, and is removed before we return any | |
// results. | |
// Once found, put it in the "open" list. (The "open" list is for | |
// triangles who may still need to be considered; the "closed" list is | |
// for triangles which do not.) | |
var dx = xmax - xmin, | |
dy = ymax - ymin, | |
dmax = (dx > dy) ? dx : dy, | |
xmid = (xmax + xmin) * 0.5, | |
ymid = (ymax + ymin) * 0.5, | |
open = [ | |
new Triangle({ | |
x: xmid - 20 * dmax, | |
y: ymid - dmax, | |
__sentinel: true | |
}, { | |
x: xmid, | |
y: ymid + 20 * dmax, | |
__sentinel: true | |
}, { | |
x: xmid + 20 * dmax, | |
y: ymid - dmax, | |
__sentinel: true | |
} | |
)], | |
closed = [], | |
edges = [], | |
j, a, b; | |
// Incrementally add each vertex to the mesh. | |
i = vertices.length; | |
while (i--) { | |
// For each open triangle, check to see if the current point is | |
// inside it's circumcircle. If it is, remove the triangle and add | |
// it's edges to an edge list. | |
edges.length = 0; | |
j = open.length; | |
while (j--) { | |
// If this point is to the right of this triangle's circumcircle, | |
// then this triangle should never get checked again. Remove it | |
// from the open list, add it to the closed list, and skip. | |
dx = vertices[i].x - open[j].x; | |
if (dx > 0 && dx * dx > open[j].r) { | |
closed.push(open[j]); | |
open.splice(j, 1); | |
continue; | |
} | |
// If not, skip this triangle. | |
dy = vertices[i].y - open[j].y; | |
if (dx * dx + dy * dy > open[j].r) | |
continue; | |
// Remove the triangle and add it's edges to the edge list. | |
edges.push( | |
open[j].a, open[j].b, | |
open[j].b, open[j].c, | |
open[j].c, open[j].a | |
); | |
open.splice(j, 1); | |
} | |
// Remove any doubled edges. | |
dedup(edges); | |
// Add a new triangle for each edge. | |
j = edges.length; | |
while (j) { | |
b = edges[--j]; | |
a = edges[--j]; | |
open.push(new Triangle(a, b, vertices[i])); | |
} | |
} | |
// Copy any remaining open triangles to the closed list, and then | |
// remove any triangles that share a vertex with the supertriangle. | |
Array.prototype.push.apply(closed, open); | |
i = closed.length; | |
while (i--) | |
if (closed[i].a.__sentinel || | |
closed[i].b.__sentinel || | |
closed[i].c.__sentinel) | |
closed.splice(i, 1); | |
return closed; | |
} | |
/***/ }, | |
/* 12 */ | |
/***/ function(module, exports) { | |
/** | |
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. | |
* | |
* @name feature | |
* @param {Geometry} geometry input geometry | |
* @param {Object} properties properties | |
* @returns {FeatureCollection} a FeatureCollection of input features | |
* @example | |
* var geometry = { | |
* "type": "Point", | |
* "coordinates": [ | |
* 67.5, | |
* 32.84267363195431 | |
* ] | |
* } | |
* | |
* var feature = turf.feature(geometry); | |
* | |
* //=feature | |
*/ | |
function feature(geometry, properties) { | |
return { | |
type: 'Feature', | |
properties: properties || {}, | |
geometry: geometry | |
}; | |
} | |
module.exports.feature = feature; | |
/** | |
* Takes coordinates and properties (optional) and returns a new {@link Point} feature. | |
* | |
* @name point | |
* @param {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 pt1 = turf.point([-75.343, 39.984]); | |
* | |
* //=pt1 | |
*/ | |
module.exports.point = function (coordinates, properties) { | |
if (!Array.isArray(coordinates)) throw new Error('Coordinates must be an array'); | |
if (coordinates.length < 2) throw new Error('Coordinates must be at least 2 numbers long'); | |
return feature({ | |
type: 'Point', | |
coordinates: coordinates.slice() | |
}, 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 | |
*/ | |
module.exports.polygon = function (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 | |
*/ | |
module.exports.lineString = function (coordinates, properties) { | |
if (!coordinates) { | |
throw new Error('No coordinates passed'); | |
} | |
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 fc = turf.featureCollection(features); | |
* | |
* //=fc | |
*/ | |
module.exports.featureCollection = function (features) { | |
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 | |
* | |
*/ | |
module.exports.multiLineString = function (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 | |
* | |
*/ | |
module.exports.multiPoint = function (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 | |
* | |
*/ | |
module.exports.multiPolygon = function (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 geometrycollection feature | |
* @example | |
* var pt = { | |
* "type": "Point", | |
* "coordinates": [100, 0] | |
* }; | |
* var line = { | |
* "type": "LineString", | |
* "coordinates": [ [101, 0], [102, 1] ] | |
* }; | |
* var collection = turf.geometrycollection([[0,0],[10,10]]); | |
* | |
* //=collection | |
*/ | |
module.exports.geometryCollection = function (geometries, properties) { | |
return feature({ | |
type: 'GeometryCollection', | |
geometries: geometries | |
}, properties); | |
}; | |
var factors = { | |
miles: 3960, | |
nauticalmiles: 3441.145, | |
degrees: 57.2957795, | |
radians: 1, | |
inches: 250905600, | |
yards: 6969600, | |
meters: 6373000, | |
metres: 6373000, | |
kilometers: 6373, | |
kilometres: 6373 | |
}; | |
/* | |
* Convert a distance measurement from radians to a more friendly unit. | |
* | |
* @name radiansToDistance | |
* @param {number} distance in radians across the sphere | |
* @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, | |
* inches, yards, metres, meters, kilometres, kilometers. | |
* @returns {number} distance | |
*/ | |
module.exports.radiansToDistance = function (radians, units) { | |
var factor = factors[units || 'kilometers']; | |
if (factor === undefined) { | |
throw new Error('Invalid unit'); | |
} | |
return radians * factor; | |
}; | |
/* | |
* Convert a distance measurement from a real-world unit into radians | |
* | |
* @name distanceToRadians | |
* @param {number} distance in real units | |
* @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, | |
* inches, yards, metres, meters, kilometres, kilometers. | |
* @returns {number} radians | |
*/ | |
module.exports.distanceToRadians = function (distance, units) { | |
var factor = factors[units || 'kilometers']; | |
if (factor === undefined) { | |
throw new Error('Invalid unit'); | |
} | |
return distance / factor; | |
}; | |
/* | |
* Convert a distance measurement from a real-world unit into degrees | |
* | |
* @name distanceToRadians | |
* @param {number} distance in real units | |
* @param {string=kilometers} units: one of miles, nauticalmiles, degrees, radians, | |
* inches, yards, metres, meters, kilometres, kilometers. | |
* @returns {number} degrees | |
*/ | |
module.exports.distanceToDegrees = function (distance, units) { | |
var factor = factors[units || 'kilometers']; | |
if (factor === undefined) { | |
throw new Error('Invalid unit'); | |
} | |
return (distance / factor) * 57.2958; | |
}; | |
/***/ }, | |
/* 13 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var invariant = __webpack_require__(14); | |
// 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 | |
* @return {Boolean} `true` if the Point is inside the Polygon; `false` if the Point is not inside the Polygon | |
* @example | |
* var pt1 = { | |
* "type": "Feature", | |
* "properties": { | |
* "marker-color": "#f00" | |
* }, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [-111.467285, 40.75766] | |
* } | |
* }; | |
* var pt2 = { | |
* "type": "Feature", | |
* "properties": { | |
* "marker-color": "#0f0" | |
* }, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [-111.873779, 40.647303] | |
* } | |
* }; | |
* var poly = { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Polygon", | |
* "coordinates": [[ | |
* [-112.074279, 40.52215], | |
* [-112.074279, 40.853293], | |
* [-111.610107, 40.853293], | |
* [-111.610107, 40.52215], | |
* [-112.074279, 40.52215] | |
* ]] | |
* } | |
* }; | |
* | |
* var features = { | |
* "type": "FeatureCollection", | |
* "features": [pt1, pt2, poly] | |
* }; | |
* | |
* //=features | |
* | |
* var isInside1 = turf.inside(pt1, poly); | |
* //=isInside1 | |
* | |
* var isInside2 = turf.inside(pt2, poly); | |
* //=isInside2 | |
*/ | |
module.exports = function input(point, polygon) { | |
var pt = invariant.getCoord(point); | |
var polys = polygon.geometry.coordinates; | |
// normalize to multipolygon | |
if (polygon.geometry.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])) { | |
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])) { | |
inHole = true; | |
} | |
k++; | |
} | |
if (!inHole) insidePoly = true; | |
} | |
} | |
return insidePoly; | |
}; | |
// pt is [x,y] and ring is [[x,y], [x,y],..] | |
function inRing(pt, ring) { | |
var isInside = false; | |
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 intersect = ((yi > pt[1]) !== (yj > pt[1])) && | |
(pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi); | |
if (intersect) isInside = !isInside; | |
} | |
return isInside; | |
} | |
/***/ }, | |
/* 14 */ | |
/***/ function(module, exports) { | |
/** | |
* Unwrap a coordinate from a Feature with a Point geometry, a Point | |
* geometry, or a single coordinate. | |
* | |
* @param {*} obj any value | |
* @returns {Array<number>} a coordinate | |
*/ | |
function getCoord(obj) { | |
if (Array.isArray(obj) && | |
typeof obj[0] === 'number' && | |
typeof obj[1] === 'number') { | |
return obj; | |
} else if (obj) { | |
if (obj.type === 'Feature' && | |
obj.geometry && | |
obj.geometry.type === 'Point' && | |
Array.isArray(obj.geometry.coordinates)) { | |
return obj.geometry.coordinates; | |
} else if (obj.type === 'Point' && | |
Array.isArray(obj.coordinates)) { | |
return obj.coordinates; | |
} | |
} | |
throw new Error('A coordinate, feature, or point geometry is required'); | |
} | |
/** | |
* Enforce expectations about types of GeoJSON objects for Turf. | |
* | |
* @alias 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. | |
* | |
* @alias 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 (!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. | |
* | |
* @alias 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 (!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); | |
} | |
} | |
} | |
module.exports.geojsonType = geojsonType; | |
module.exports.collectionOf = collectionOf; | |
module.exports.featureOf = featureOf; | |
module.exports.getCoord = getCoord; | |
/***/ }, | |
/* 15 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var point = __webpack_require__(16); | |
/** | |
* Takes a bounding box and a cell depth and returns a {@link FeatureCollection} of {@link Point} features in a grid. | |
* | |
* @module turf/grid | |
* @category interpolation | |
* @param {Array<number>} extent extent in [minX, minY, maxX, maxY] order | |
* @param {Number} depth how many cells to output | |
* @return {FeatureCollection} grid as FeatureCollection with {@link Point} features | |
* @example | |
* var extent = [-70.823364, -33.553984, -70.473175, -33.302986]; | |
* var depth = 10; | |
* | |
* var grid = turf.grid(extent, depth); | |
* | |
* //=grid | |
*/ | |
module.exports = function(extents, depth) { | |
var xmin = extents[0]; | |
var ymin = extents[1]; | |
var xmax = extents[2]; | |
var ymax = extents[3]; | |
var interval = (xmax - xmin) / depth; | |
var coords = []; | |
var fc = { | |
type: 'FeatureCollection', | |
features: [] | |
}; | |
for (var x=0; x<=depth; x++){ | |
for (var y=0;y<=depth; y++){ | |
fc.features.push(point([(x * interval) + xmin, (y * interval) + ymin])); | |
} | |
} | |
return fc; | |
} | |
/***/ }, | |
/* 16 */ | |
/***/ function(module, exports) { | |
/** | |
* Takes coordinates and properties (optional) and returns a new {@link Point} feature. | |
* | |
* @module turf/point | |
* @category helper | |
* @param {number} longitude position west to east in decimal degrees | |
* @param {number} latitude position south to north in decimal degrees | |
* @param {Object} properties an Object that is used as the {@link Feature}'s | |
* properties | |
* @return {Point} a Point feature | |
* @example | |
* var pt1 = turf.point([-75.343, 39.984]); | |
* | |
* //=pt1 | |
*/ | |
var isArray = Array.isArray || function(arg) { | |
return Object.prototype.toString.call(arg) === '[object Array]'; | |
}; | |
module.exports = function(coordinates, properties) { | |
if (!isArray(coordinates)) throw new Error('Coordinates must be an array'); | |
if (coordinates.length < 2) throw new Error('Coordinates must be at least 2 numbers long'); | |
return { | |
type: "Feature", | |
geometry: { | |
type: "Point", | |
coordinates: coordinates | |
}, | |
properties: properties || {} | |
}; | |
}; | |
/***/ }, | |
/* 17 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var each = __webpack_require__(18).coordEach; | |
/** | |
* Takes a set of features, calculates the bbox of all input features, and returns a bounding box. | |
* | |
* @name bbox | |
* @param {(Feature|FeatureCollection)} geojson input features | |
* @return {Array<number>} the bounding box of `input` given | |
* as an array in WSEN order (west, south, east, north) | |
* @example | |
* var input = { | |
* "type": "FeatureCollection", | |
* "features": [ | |
* { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [114.175329, 22.2524] | |
* } | |
* }, { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [114.170007, 22.267969] | |
* } | |
* }, { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [114.200649, 22.274641] | |
* } | |
* }, { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [114.186744, 22.265745] | |
* } | |
* } | |
* ] | |
* }; | |
* | |
* var bbox = turf.bbox(input); | |
* | |
* var bboxPolygon = turf.bboxPolygon(bbox); | |
* | |
* var resultFeatures = input.features.concat(bboxPolygon); | |
* var result = { | |
* "type": "FeatureCollection", | |
* "features": resultFeatures | |
* }; | |
* | |
* //=result | |
*/ | |
module.exports = function (geojson) { | |
var bbox = [Infinity, Infinity, -Infinity, -Infinity]; | |
each(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; | |
}; | |
/***/ }, | |
/* 18 */ | |
/***/ function(module, exports) { | |
/** | |
* Iterate over coordinates in any GeoJSON object, similar to | |
* Array.forEach. | |
* | |
* @param {Object} layer any GeoJSON object | |
* @param {Function} callback a method that takes (value) | |
* @param {boolean=} excludeWrapCoord whether or not to include | |
* the final coordinate of LinearRings that wraps the ring in its iteration. | |
* @example | |
* var point = { type: 'Point', coordinates: [0, 0] }; | |
* coordEach(point, function(coords) { | |
* // coords is equal to [0, 0] | |
* }); | |
*/ | |
function coordEach(layer, callback, excludeWrapCoord) { | |
var i, j, k, g, l, geometry, stopG, coords, | |
geometryMaybeCollection, | |
wrapShrink = 0, | |
isGeometryCollection, | |
isFeatureCollection = layer.type === 'FeatureCollection', | |
isFeature = layer.type === 'Feature', | |
stop = isFeatureCollection ? layer.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 ? layer.features[i].geometry : | |
(isFeature ? layer.geometry : layer)); | |
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); | |
} else if (geometry.type === 'LineString' || geometry.type === 'MultiPoint') { | |
for (j = 0; j < coords.length; j++) callback(coords[j]); | |
} 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]); | |
} 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]); | |
} else { | |
throw new Error('Unknown Geometry Type'); | |
} | |
} | |
} | |
} | |
module.exports.coordEach = coordEach; | |
/** | |
* Reduce coordinates 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 coordinates is unnecessary. | |
* | |
* @param {Object} layer any GeoJSON object | |
* @param {Function} callback a method that takes (memo, value) and returns | |
* a new memo | |
* @param {*} memo the starting value of memo: can be any type. | |
* @param {boolean=} excludeWrapCoord whether or not to include | |
* the final coordinate of LinearRings that wraps the ring in its iteration. | |
* @return {*} combined value | |
*/ | |
function coordReduce(layer, callback, memo, excludeWrapCoord) { | |
coordEach(layer, function (coord) { | |
memo = callback(memo, coord); | |
}, excludeWrapCoord); | |
return memo; | |
} | |
module.exports.coordReduce = coordReduce; | |
/** | |
* Iterate over property objects in any GeoJSON object, similar to | |
* Array.forEach. | |
* | |
* @param {Object} layer any GeoJSON object | |
* @param {Function} callback a method that takes (value) | |
* @example | |
* var point = { type: 'Feature', geometry: null, properties: { foo: 1 } }; | |
* propEach(point, function(props) { | |
* // props is equal to { foo: 1} | |
* }); | |
*/ | |
function propEach(layer, callback) { | |
var i; | |
switch (layer.type) { | |
case 'FeatureCollection': | |
for (i = 0; i < layer.features.length; i++) { | |
callback(layer.features[i].properties); | |
} | |
break; | |
case 'Feature': | |
callback(layer.properties); | |
break; | |
} | |
} | |
module.exports.propEach = propEach; | |
/** | |
* 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. | |
* | |
* @param {Object} layer any GeoJSON object | |
* @param {Function} callback a method that takes (memo, coord) and returns | |
* a new memo | |
* @param {*} memo the starting value of memo: can be any type. | |
* @return {*} combined value | |
*/ | |
function propReduce(layer, callback, memo) { | |
propEach(layer, function (prop) { | |
memo = callback(memo, prop); | |
}); | |
return memo; | |
} | |
module.exports.propReduce = propReduce; | |
/** | |
* Iterate over features in any GeoJSON object, similar to | |
* Array.forEach. | |
* | |
* @param {Object} layer any GeoJSON object | |
* @param {Function} callback a method that takes (value) | |
* @example | |
* var feature = { type: 'Feature', geometry: null, properties: {} }; | |
* featureEach(feature, function(feature) { | |
* // feature == feature | |
* }); | |
*/ | |
function featureEach(layer, callback) { | |
if (layer.type === 'Feature') { | |
callback(layer); | |
} else if (layer.type === 'FeatureCollection') { | |
for (var i = 0; i < layer.features.length; i++) { | |
callback(layer.features[i]); | |
} | |
} | |
} | |
module.exports.featureEach = featureEach; | |
/** | |
* Get all coordinates from any GeoJSON object, returning an array of coordinate | |
* arrays. | |
* @param {Object} layer any GeoJSON object | |
* @return {Array<Array<Number>>} coordinate position array | |
*/ | |
function coordAll(layer) { | |
var coords = []; | |
coordEach(layer, function (coord) { | |
coords.push(coord); | |
}); | |
return coords; | |
} | |
module.exports.coordAll = coordAll; | |
/***/ }, | |
/* 19 */ | |
/***/ function(module, exports) { | |
/** | |
* Takes a triangular plane as a {@link Polygon} | |
* and a {@link Point} within that triangle and returns the z-value | |
* at that point. The Polygon needs to have properties `a`, `b`, and `c` | |
* that define the values at its three corners. | |
* | |
* @name planepoint | |
* @param {Feature<Point>} point the Point for which a z-value will be calculated | |
* @param {Feature<Polygon>} triangle a Polygon feature with three vertices | |
* @return {Number} the z-value for `interpolatedPoint` | |
* @example | |
* var point = { | |
* "type": "Feature", | |
* "properties": {}, | |
* "geometry": { | |
* "type": "Point", | |
* "coordinates": [-75.3221, 39.529] | |
* } | |
* }; | |
* var point = turf.point([-75.3221, 39.529]); | |
* // triangle is a polygon with "a", "b", | |
* // and "c" values representing | |
* // the values of the coordinates in order. | |
* var triangle = { | |
* "type": "Feature", | |
* "properties": { | |
* "a": 11, | |
* "b": 122, | |
* "c": 44 | |
* }, | |
* "geometry": { | |
* "type": "Polygon", | |
* "coordinates": [[ | |
* [-75.1221, 39.57], | |
* [-75.58, 39.18], | |
* [-75.97, 39.86], | |
* [-75.1221, 39.57] | |
* ]] | |
* } | |
* }; | |
* | |
* var features = { | |
* "type": "FeatureCollection", | |
* "features": [triangle, point] | |
* }; | |
* | |
* var zValue = turf.planepoint(point, triangle); | |
* | |
* //=features | |
* | |
* //=zValue | |
*/ | |
module.exports = function (point, triangle) { | |
var x = point.geometry.coordinates[0], | |
y = point.geometry.coordinates[1], | |
x1 = triangle.geometry.coordinates[0][0][0], | |
y1 = triangle.geometry.coordinates[0][0][1], | |
z1 = triangle.properties.a, | |
x2 = triangle.geometry.coordinates[0][1][0], | |
y2 = triangle.geometry.coordinates[0][1][1], | |
z2 = triangle.properties.b, | |
x3 = triangle.geometry.coordinates[0][2][0], | |
y3 = triangle.geometry.coordinates[0][2][1], | |
z3 = triangle.properties.c; | |
var z = (z3 * (x - x1) * (y - y2) + z1 * (x - x2) * (y - y3) + z2 * (x - x3) * (y - y1) - | |
z2 * (x - x1) * (y - y3) - z3 * (x - x2) * (y - y1) - z1 * (x - x3) * (y - y2)) / | |
((x - x1) * (y - y2) + (x - x2) * (y - y3) + (x - x3) * (y - y1) - | |
(x - x1) * (y - y3) - (x - x2) * (y - y1) - (x - x3) * (y - y2)); | |
return z; | |
}; | |
/***/ }, | |
/* 20 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var distance = __webpack_require__(21); | |
/** | |
* Takes a bounding box and calculates the minimum square bounding box that | |
* would contain the input. | |
* | |
* @name square | |
* @param {Array<number>} bbox a bounding box | |
* @return {Array<number>} a square surrounding `bbox` | |
* @example | |
* var bbox = [-20,-20,-15,0]; | |
* | |
* var squared = turf.square(bbox); | |
* | |
* var features = { | |
* "type": "FeatureCollection", | |
* "features": [ | |
* turf.bboxPolygon(bbox), | |
* turf.bboxPolygon(squared) | |
* ] | |
* }; | |
* | |
* //=features | |
*/ | |
module.exports = function (bbox) { | |
var horizontalDistance = distance(bbox.slice(0, 2), [bbox[2], bbox[1]], 'miles'); | |
var verticalDistance = distance(bbox.slice(0, 2), [bbox[0], bbox[3]], 'miles'); | |
if (horizontalDistance >= verticalDistance) { | |
var verticalMidpoint = (bbox[1] + bbox[3]) / 2; | |
return [ | |
bbox[0], | |
verticalMidpoint - ((bbox[2] - bbox[0]) / 2), | |
bbox[2], | |
verticalMidpoint + ((bbox[2] - bbox[0]) / 2) | |
]; | |
} else { | |
var horizontalMidpoint = (bbox[0] + bbox[2]) / 2; | |
return [ | |
horizontalMidpoint - ((bbox[3] - bbox[1]) / 2), | |
bbox[1], | |
horizontalMidpoint + ((bbox[3] - bbox[1]) / 2), | |
bbox[3] | |
]; | |
} | |
}; | |
/***/ }, | |
/* 21 */ | |
/***/ function(module, exports, __webpack_require__) { | |
var getCoord = __webpack_require__(22).getCoord; | |
var radiansToDistance = __webpack_require__(12).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 {Feature<Point>} from origin point | |
* @param {Feature<Point>} to destination point | |
* @param {String} [units=kilometers] can be degrees, radians, miles, or kilometers | |
* @return {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 units = "miles"; | |
* | |
* var points = { | |
* "type": "FeatureCollection", | |
* "features": [from, to] | |
* }; | |
* | |
* //=points | |
* | |
* var distance = turf.distance(from, to, units); | |
* | |
* //=distance | |
*/ | |
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); | |
}; | |
/***/ }, | |
/* 22 */ | |
/***/ function(module, exports) { | |
/** | |
* Unwrap a coordinate from a Feature with a Point geometry, a Point | |
* geometry, or a single coordinate. | |
* | |
* @param {*} obj any value | |
* @returns {Array<number>} a coordinate | |
*/ | |
function getCoord(obj) { | |
if (Array.isArray(obj) && | |
typeof obj[0] === 'number' && | |
typeof obj[1] === 'number') { | |
return obj; | |
} else if (obj) { | |
if (obj.type === 'Feature' && | |
obj.geometry && | |
obj.geometry.type === 'Point' && | |
Array.isArray(obj.geometry.coordinates)) { | |
return obj.geometry.coordinates; | |
} else if (obj.type === 'Point' && | |
Array.isArray(obj.coordinates)) { | |
return obj.coordinates; | |
} | |
} | |
throw new Error('A coordinate, feature, or point geometry is required'); | |
} | |
/** | |
* Enforce expectations about types of GeoJSON objects for Turf. | |
* | |
* @alias 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. | |
* | |
* @alias 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 (!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. | |
* | |
* @alias 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 (!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); | |
} | |
} | |
} | |
module.exports.geojsonType = geojsonType; | |
module.exports.collectionOf = collectionOf; | |
module.exports.featureOf = featureOf; | |
module.exports.getCoord = getCoord; | |
/***/ }, | |
/* 23 */ | |
/***/ function(module, exports) { | |
/* eslint-disable */ | |
/* | |
* Copyright (c) 2010, Jason Davies. | |