├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .size-limit ├── LICENSE ├── README.md ├── _extra └── images │ ├── bars.png │ ├── colorworld.png │ ├── maritime.png │ ├── moscow.png │ └── world.png ├── bundle.js ├── examples ├── APIs │ ├── d3-globe.html │ ├── d3.html │ ├── google.html │ ├── leaflet.html │ └── yandex.html ├── disputed-borders.html ├── example.html ├── geocode-example.html ├── maritime.html ├── recombination │ └── barcelona.html └── static-data.html ├── geocoder.md ├── package.json ├── src ├── browserBundle.js ├── collections │ ├── google.js │ ├── leaflet.js │ ├── unbounded.js │ └── yandex.js ├── connect │ └── yandex.js ├── geocode.js ├── index.js ├── regions.js ├── settings.js └── utils │ ├── buildIdTable.js │ ├── convertCoordinate.js │ ├── decoder.js │ ├── geometryDecode.js │ ├── load_native.js │ ├── nextTick.js │ ├── recombine.js │ ├── region.js │ ├── setupGeometry.js │ └── shortestPath.js ├── tests ├── geocode.spec.js └── regions.spec.js ├── umd └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"], 3 | "plugins": ["transform-object-rest-spread"] 4 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint:recommended", 4 | "plugins": [ 5 | "mocha" 6 | ], 7 | "env": { 8 | "browser": true, 9 | "node": true, 10 | "es6": true, 11 | "mocha": true 12 | }, 13 | "rules": { 14 | "prefer-const": [ 15 | "error", 16 | { 17 | "destructuring": "any", 18 | "ignoreReadBeforeAssign": false 19 | } 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /.size-limit: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | path: "lib/index.js", 4 | limit: "5 KB" 5 | } 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 esosedi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # regions (code name osme) 2 | The source of World's administrative divisions. 3 | 4 | This is a module designed for: 5 | - [Yandex](https://tech.yandex.com/maps/), 6 | - [Google](https://developers.google.com/maps/), 7 | - [Leaflet](http://leafletjs.com/), 8 | - any other JS Maps to outline countries, counties and regions of the world. 9 | - being just a getJSON provider 10 | 11 | 12 | Each time you want to display borders - use the regions, Luke. 13 | 14 | [](https://nodei.co/npm/osme/) 15 | 16 | Runs on top of information from [OpenStreetMap](http://openstreetmap.org), [Wikipedia](http://en.wikipedia.org), [GeoNames](http://geonames.org), [eSosedi](http://ru.esosedi.org) and some other sources. 17 | 18 | Created for and used by [esosedi.org](http://ru.esosedi.org) project - one of largest cartographical site in the World. 19 | 20 | * This is neither lib nor API. This is a service. 21 | 22 | ```js 23 | import osme from 'osme'; 24 | ``` 25 | or 26 | ```html 27 | 28 | // use window.osme 29 | ``` 30 |  31 | 32 | # API 33 | There is only 2 primary commands: 34 | * osme.geoJSON(addr, [options], [callback]):Promise - to get geoJSON for a region query 35 | * osme.geocode(point, [options], [callback], [errorCallback]):Promise - to find region by coordinates 36 | 37 | Plus we include build-in wrappers for Yandex Maps API, Google Maps API and Leaflet. 38 | * osme.toGoogle(geoJson) 39 | * osme.toYandex(geoJson) 40 | * osme.toLeaflet(geoJson) 41 | 42 | All collections will have interface of .add .remove .setStyles .addEvent .removeEvent. 43 | 44 | 45 | Result it very simple - you can display any continent, country or state on a map. 46 | 47 | # As Service 48 | 49 | The module consists in two parts, and this part is a client side. 50 | It does not contain _any_ data, always striming it from the server side at [data.esosedi.org](http://data.esosedi.org). 51 | Server-side also implements online `navigator` via database to help you find proper place. 52 | 53 | * base service runs as 'http' service. Not https!, to https is provided by cloudflare and geolocated.org. 54 | 55 | # What I can load? 56 | 57 | So, you can load: 58 | * `world` - all countries of the World. 59 | * geoScheme - 21 macro region of the World. 60 | _Africa, Americas, Asia, Europe, Oceania, Eastern Africa, Middle Africa, Northern Africa, Southern Africa, Western Africa, Cariebbean, Central America, Northern America, South America, Central Asia, Eastern Asia, South-Eastern Asia, Southern Asia, Western Asia, Eastern Europe, Northern Europe, Southern Europe, Western Europe, Australia and New Zealand, Melanesia, Micronesia, Polynesia._ 61 | * iso3166-1 code. Country code. US, AU, DE and so on 62 | * iso3166-2 code. Region. US-WA, AU-NSW, RU-MOW and so on 63 | * special exports. bigMoscow, Moscow, SaintPetersburg, bigPiter and so on. Open a Pull Request if you need a special one. 64 | * `number` - as a OpenStreetMap RelationID. Ie - you can get contour of USA using `US` or `148838`, there is no difference. 65 | 66 | # Example 67 | * And check /examples folder! 68 | 69 | ```javascript 70 | import osmeRegions from 'osme'; 71 | osme.geoJSON('FR').then( geojson => osme.toGoogle(geojson).add(map)); 72 | ``` 73 | 74 | A bit bigger one: 75 | ``` 76 | // ask for some region 77 | osme.geoJSON('US'/*addr*/, {lang: 'de'}, function (data) { 78 | // data is pure GEOJSON 79 | 80 | // you can create some helpers 81 | var yandexGeoObjectColletionWrapper = osme.toYandex(data); 82 | // or 83 | var googleDataWrapper = osme.toGoogle(data); 84 | // or 85 | var leafletDataWrapper = osme.toLeaflet(data); 86 | 87 | // call .add to add data into the map 88 | yandexGeoObjectColletionWrapper.add(map); 89 | // call .remove to remove 90 | googleDataWrapper.remove(); 91 | 92 | // call setStyles to setup styles 93 | leafletDataWrapper.setStyles(jsonFeatureIn => { 94 | return styleOptions 95 | }); 96 | 97 | // And you also can control events. 98 | *.addEvent(event,function(feature, apiType, apiObject, apiEvent){}); 99 | *.removeEvent(); 100 | }) 101 | 102 | // PS: OR you can use geoJSON as geoJSON. With out helpers 103 | new L.geoJson(data).addTo(map); 104 | ``` 105 | 106 | # .geoJSON 107 | * osme.geoJSON(addr, options, callback) 108 | Where: 109 | `addr` is OSM RelationId, [ISO3166-2](https://ru.wikipedia.org/wiki/ISO_3166-2) code(US/DE/GB or RU-MOS/US-TX etc, or [world's region name](https://en.wikipedia.org/wiki/Subregion) 110 | `options` is a object of { lang, quality, type, nocache, postFilter, recombine, scheme }. All are optional. 111 | 112 | - lang - prefered language (en,de,ru) 113 | - quality – set 0 to get geomentry for fullHD resolution. -1,0,+1,+2 for /4, x1, x4, x16 quality. 114 | - type - null|'coast'. 115 | - null to get `raw` `maritime` administrative borders, including terrotorial water. 116 | - "coast", to cut off coast lines. 117 | - nocache - turns of internal client-side cache 118 | - postFilter, recombine, scheme - to be used only by advanced users. 119 | 120 | 121 | If you dont know relationId(`addr`) for region you need, you can: 122 | 1. Traverse map database at [http://data.esosedi.org](http://data.esosedi.org). 123 | 2. Use reverse geocode, via this lib, or via REST call - http://data.esosedi.org/geocode/v1?[lng=(ru|en)]&point=x,y[&seq=?][&callback=?] 124 | 3. Use [iso3166](https://github.com/esosedi/3166) library to get administrative divisions as a list. 125 | 126 | ### type=coast 127 | Type coast will return information you want - pretty borders. Very hi-detailed borders. 128 | Here is comparison between borders for Greece with and without maritime. 129 | [Greece](/_extra/images/maritime.png?raw=true) 130 | Difference - 154kb versus 251. 131 | 132 | ### PS: 133 | Information available for ~300k regions in 3 languages(en, de, ru) and some secret modes. 134 | 135 | This module uses CORS to transport JSON via different hosts. 136 | 137 | You can store geojson produced by this module, or cache packed json files from orinal data endpoint. 138 | 139 | Just change data-endpoint by executing `osme.setHost` command. 140 | 141 | * Remember: We have to provide copyright information, and you have to display it. 142 | 143 | Data format is quite simple and compact. It is look like [topojson](https://github.com/mbostock/topojson), but more "binary" and contains data like schemes etc. 144 | After all you will get standard geoJSON. You can use it by your own risk. 145 | 146 | More Examples: 147 | ``` 148 | 149 | // request Moscow 150 | osme.geoJSON('RU-MOW', {lang: 'ru'}, function (data) { 151 | var collection = osme.toYandex(data, ymaps); 152 | collection.add(geoMap); 153 | 154 | geoMap.setBounds(collection.collection.getBounds(), {duration: 300}); 155 | 156 | var strokeColors = [ 157 | '#000', 158 | '#F0F', 159 | '#00F', 160 | '#0FF', 161 | ]; 162 | var meta = data.metaData, 163 | maxLevel = meta.levels[1] + 1; 164 | 165 | // colorize the collection 166 | collection.setStyles(function (object, yobject) { 167 | var level = object.properties.level; 168 | return ({ 169 | zIndex: level, 170 | zIndexHover: level, 171 | strokeWidth: Math.max(1, level == 2 ? 2 : (maxLevel - level)), 172 | strokeColor: strokeColors[maxLevel - level] || '#000', 173 | fillColor: '#FFE2', 174 | }); 175 | }); 176 | ``` 177 |  178 | 179 | # setStyles 180 | 181 | You can do anything like country coloring (http://jsfiddle.net/9o9ak7fb/18/), or making "old" Moscow (http://jsfiddle.net/9o9ak7fb/17/). 182 | OSMe provide geo data, you provide logic. 183 | 184 | ``` 185 | var countryColors={ 186 | 'CA': "F00", 187 | 'IN': "0F0", 188 | 'US': "00F", 189 | 'RU': "F0F" 190 | }; 191 | 192 | function setColors(collection, countryColors){ 193 | // You know this function 194 | collection.setStyles(function (object) { 195 | // get ISO counry code and color it 196 | var iso = (object.properties.properties.iso3166 ||'').toUpperCase(), 197 | color=countryColors[iso]; 198 | return ({ 199 | strokeWidth: 1, 200 | strokeColor: color?'#000':"666", 201 | fillColor: color || 'EEE', 202 | visible: !!color 203 | }); 204 | }); 205 | } 206 | 207 | //... 208 | osme.geoJSON('world',{}).then(data => { 209 | const collection = osme.toGoogle(data); 210 | setColors(collection, countryColors); 211 | collection.add(map); 212 | }); 213 | ``` 214 |  215 | 216 | # addEvents 217 | 218 | ```javascript 219 | //any event - click, dblclick and so on. 220 | const event = collection.addEvent('dblclick', function (object, type, target, event) { 221 | // object - object itself 222 | // type – [eventName, provider('yandex','google')] 223 | // target – Maps API`s feature (polygon) 224 | // event – original event 225 | event.preventDefault(); 226 | }); 227 | collection.removeEvent(event); 228 | ``` 229 | 230 | And what about boundary dispute? Crimea, Kosovo, etc.. 231 | 232 | # Magic of Recombine 233 | 234 | Recall strange parameter in options, field named `recombine`. This is not about boundaries, this is about recombination. 235 | It is almost as language - en-US, or en-GB.. 236 | 237 | * It can be string, and will be treated as key in scheme. Default equals to language. 238 | * Object with key - relation id, and value - javascript code. 239 | 240 | See disputed-borders.html in /examples. 241 | 242 | Recombination allow you to create new geometry by combination of others. 243 | 244 | For example something from internal cuisine - this code included in world.json file, and executed automatically 245 | ``` 246 | { 247 | disputedBorders: { 248 | ru: { 249 | 60199/*UA*/: 'return region.hasParent(60199) && region.osmId != 72639 && region.osmId != 1574364 && region.osmId!=421866;', 250 | 60189/*RU*/: 'return !region.hasParent(60189) && (region.osmId == 60189 || region.osmId == 72639 || region.osmId == 1574364)', 251 | } 252 | }, 253 | postFilter: 'return !region.hasParent(60199);', //remove UA* 254 | } 255 | ``` 256 | What this function do - it generates Ukraine without Crimea, or Russia with. 257 | - for #60199(Ukraine) - select all objects in 60199, but not Crimea and Kiev(internal shape) 258 | - for #60189(Russia) - selects RU, plus Crimea regions. 259 | - later - remove all regions of UA (exists in geoJSON file for this recombination) cos we require countries. 260 | 261 | You can set options.recombine to a string ('ru' in this example) to select desired scheme, or set new scheme object. 262 | 263 | * By default recombine===lang. 264 | 265 | By the same way you can join SJ to NO or GF to FR (one will understand). 266 | 267 | You can create Merica by joining US to CA and MX or create EuroUnion. 268 | 269 | The difference between recombination and just displaying everything you need - 270 | the result of recombination is `borderless`. You will get not a pack of shapes, but BIG one. 271 | 272 | Recombination can be used to join any set of regions in one. This is usefull in many cases. 273 | 274 | ``` 275 | osme.geoJSON('349035', {lang: 'en'}, function (data, pureData) { 276 | var coords=osme.recombine(pureData, { // yes, you can use pure data 277 | filter: function (region) { 278 | // somethere in Province of Barcelona (349035) and Barcelona(2417889) or adjacent 279 | // remember - you have to discard #349035 or you got duplicate. 280 | return region.hasParent(349035) && (region.hasBorderWith(2417889) || region.osmId == 2417889); 281 | } 282 | }); 283 | for(var j in coords.coordinates) { 284 | var region = new ymaps.GeoObject({ 285 | geometry: { 286 | type: 'Polygon', 287 | fillRule: 'nonZero', 288 | coordinates: osme.flipCoordinate([coords.coordinates[j]]) 289 | } 290 | }, { 291 | opacity: 0.8, 292 | fillColor: 'FEE', 293 | strokeColor: 'F00', 294 | strokeWidth: 2, 295 | pixelRendering: 'static', 296 | draggable: true 297 | }); 298 | geoMap.geoObjects.add(region); 299 | } 300 | } 301 | ``` 302 | And you got mini Barcelona 303 |  304 | 305 | Where is also exists options.scheme - yet another recombination function. It also sometimes exists in source geoJSON file. 306 | The goal still simple - some regions lays on the top of other, and do not have adjacent borders - Kiev, for example, and Kiev province. 307 | Scheme just adds "hole" to province. 308 | 309 | 310 | You dont need to understand all of this - just use. 311 | 312 | # Remember 313 | * ! As any UGC project, may contain, contain and will `contain errors`, holes in data and mistakes. 314 | 315 | 316 | Cheers, Kashey. -------------------------------------------------------------------------------- /_extra/images/bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esosedi/regions/d23acc7c1ee687b6111750b0ea26d1aa565f87a8/_extra/images/bars.png -------------------------------------------------------------------------------- /_extra/images/colorworld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esosedi/regions/d23acc7c1ee687b6111750b0ea26d1aa565f87a8/_extra/images/colorworld.png -------------------------------------------------------------------------------- /_extra/images/maritime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esosedi/regions/d23acc7c1ee687b6111750b0ea26d1aa565f87a8/_extra/images/maritime.png -------------------------------------------------------------------------------- /_extra/images/moscow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esosedi/regions/d23acc7c1ee687b6111750b0ea26d1aa565f87a8/_extra/images/moscow.png -------------------------------------------------------------------------------- /_extra/images/world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esosedi/regions/d23acc7c1ee687b6111750b0ea26d1aa565f87a8/_extra/images/world.png -------------------------------------------------------------------------------- /bundle.js: -------------------------------------------------------------------------------- 1 | (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} eventName 259 | * @param {Function} callback 260 | * @param {Object} [ctx] 261 | */ 262 | addEvent: function addEvent(eventName, callback, ctx) { 263 | collection.events.add(eventName, function (event) { 264 | var target = event.get("target"); 265 | callback.call(ctx, idTable[target.properties.get("osmId")], [eventName, "yandex"], target, event); 266 | }); 267 | }, 268 | removeEvent: function removeEvent(event) { 269 | collection.events.remove(event); 270 | } 271 | }; 272 | } 273 | 274 | exports.default = toYandex; 275 | },{"../settings":8,"../utils/buildIdTable":9,"../utils/convertCoordinate":10}],6:[function(require,module,exports){ 276 | "use strict"; 277 | 278 | Object.defineProperty(exports, "__esModule", { 279 | value: true 280 | }); 281 | 282 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 283 | 284 | var _settings = require("./settings"); 285 | 286 | var _settings2 = _interopRequireDefault(_settings); 287 | 288 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 289 | 290 | /** 291 | * Reverse geocode 292 | * @param {Numbrer[]} point - Point. 293 | * @param {Object} [options] 294 | * @param {Number} [options.seq] - Sequence number. 295 | * @param {String} [options.lang] - Language. 296 | * @param {Function} [callback] 297 | * @param {Function} [errorCallback] 298 | * @return {Promise} 299 | */ 300 | function geocode(point, options, _callback, _errorCallback) { 301 | var promise = void 0; 302 | var cb_resolve = void 0, 303 | cb_reject = void 0; 304 | 305 | var addr = _settings2.default.GEOCODEHOST; 306 | addr += "?point=" + +point[0] + "," + +point[1]; 307 | 308 | if (typeof options == "function") { 309 | _errorCallback = _callback; 310 | _callback = options; 311 | options = {}; 312 | } 313 | 314 | options = _extends({ 315 | lang: "en", 316 | seq: 0 317 | }, options || {}); 318 | 319 | if (options.seq) { 320 | addr += "&seq=" + +options.seq; 321 | } 322 | if (options.lang) { 323 | addr += "&lng=" + options.lang; 324 | } 325 | 326 | if (typeof Promise != "undefined") { 327 | promise = new Promise(function (resolve, reject) { 328 | cb_resolve = resolve; 329 | cb_reject = reject; 330 | }); 331 | } else { 332 | cb_resolve = cb_reject = function cb_reject() {}; 333 | } 334 | 335 | var callback = function callback(geojson) { 336 | cb_resolve(geojson); 337 | _callback && _callback(geojson); 338 | }; 339 | 340 | var errorCallback = function errorCallback(geojson) { 341 | cb_reject(geojson); 342 | _errorCallback && _errorCallback(geojson); 343 | }; 344 | 345 | _settings2.default.load(addr, function (json) { 346 | return callback(json); 347 | }, function (err) { 348 | return errorCallback(err); 349 | }); 350 | 351 | return promise; 352 | } 353 | 354 | exports.default = geocode; 355 | },{"./settings":8}],7:[function(require,module,exports){ 356 | "use strict"; 357 | 358 | Object.defineProperty(exports, "__esModule", { 359 | value: true 360 | }); 361 | 362 | var _settings = require("./settings"); 363 | 364 | var _settings2 = _interopRequireDefault(_settings); 365 | 366 | var _nextTick = require("./utils/nextTick"); 367 | 368 | var _nextTick2 = _interopRequireDefault(_nextTick); 369 | 370 | var _recombine = require("./utils/recombine"); 371 | 372 | var _recombine2 = _interopRequireDefault(_recombine); 373 | 374 | var _setupGeometry = require("./utils/setupGeometry"); 375 | 376 | var _setupGeometry2 = _interopRequireDefault(_setupGeometry); 377 | 378 | var _geocode = require("./geocode"); 379 | 380 | var _geocode2 = _interopRequireDefault(_geocode); 381 | 382 | var _google = require("./collections/google"); 383 | 384 | var _google2 = _interopRequireDefault(_google); 385 | 386 | var _yandex = require("./collections/yandex"); 387 | 388 | var _yandex2 = _interopRequireDefault(_yandex); 389 | 390 | var _leaflet = require("./collections/leaflet"); 391 | 392 | var _leaflet2 = _interopRequireDefault(_leaflet); 393 | 394 | var _unbounded = require("./collections/unbounded"); 395 | 396 | var _unbounded2 = _interopRequireDefault(_unbounded); 397 | 398 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 399 | 400 | var assertData = function assertData(errorCallback, data) { 401 | if (!data || data.error) { 402 | errorCallback("wrong data", data.error); 403 | } 404 | return data; 405 | }; 406 | 407 | /** 408 | * @name osmeRegions 409 | * @type Object 410 | */ 411 | /*! 412 | * OSMeRegions JavaScript Library 413 | * http://data.esosedi.org/regions/ 414 | * https://github.com/esosedi/regions 415 | * 416 | * @author Anton Korzunov 417 | * Released under the MIT license 418 | */ 419 | 420 | var osmeRegions = /** @lends osmeRegions */{ 421 | /** 422 | * override data host 423 | * @param host 424 | */ 425 | setHost: function setHost(host) { 426 | _settings2.default.HOST = host; 427 | }, 428 | 429 | /** 430 | * @param {Boolean} debug 431 | */ 432 | setDebug: function setDebug(debug) { 433 | _settings2.default.DEBUG = Boolean(debug); 434 | }, 435 | 436 | /** 437 | * allow recombination 438 | * @param regionsData 439 | * @param {Object} query 440 | * @param {Function} query.filter 441 | * @function 442 | */ 443 | recombine: _recombine2.default, 444 | 445 | /** 446 | * Loads GeoJSON from default host 447 | * @param {String} region OSMRelationId,ISO3166-2 code or world's region name(Asia, Europe etc) or absolute URL. 448 | * @param {Object} options 449 | * @param {String} [options.lang='en'] Language (en,de,ru). 450 | * @param {Number} [options.quality=0] Quality. 0 for fullHD resolution. -1,0,+1,+2 for /4, x1, x4, x16 quality. 451 | * @param {String} [options.type=''] Type of data. Can be empty or 'coast' (unstable mode). 452 | * @param {Boolean} [options.nocache] Turns off internal cache. 453 | * @param {Function} [options.postFilter] filtering function. 454 | * @param {String|Object} [options.recombine] recombination function. 455 | * @param {Object} [options.scheme] another recombination function. 456 | * @param {Function} [callback] 457 | * @param {Function} [errorCallback] 458 | * @return {Promise} 459 | */ 460 | geoJSON: function geoJSON(region, options, _callback, _errorCallback) { 461 | var _this = this; 462 | 463 | var promise = void 0; 464 | var cb_resolve = void 0, 465 | cb_reject = void 0; 466 | options = options || {}; 467 | 468 | if (typeof options === "function") { 469 | throw new Error("callback must be at third place"); 470 | } 471 | 472 | var lang = options.lang || "en"; 473 | var addr = typeof region === "string" ? lang + "_" + region : null; 474 | 475 | if (typeof Promise !== "undefined") { 476 | promise = new Promise(function (resolve, reject) { 477 | cb_resolve = resolve; 478 | cb_reject = reject; 479 | }); 480 | } else { 481 | cb_resolve = cb_reject = function cb_reject() {}; 482 | } 483 | var callback = function callback(geojson, data) { 484 | if (addr) { 485 | _settings2.default.cache[addr] = data; 486 | } 487 | cb_resolve(geojson, data); 488 | _callback && _callback(geojson, data); 489 | }; 490 | 491 | var errorCallback = function errorCallback(geojson) { 492 | cb_reject(geojson); 493 | _errorCallback && _errorCallback(geojson); 494 | }; 495 | 496 | if (addr) { 497 | if ((region + "").indexOf("http") === 0) { 498 | addr = region; 499 | } else { 500 | addr = (options.host || _settings2.default.HOST) + "?lang=" + addr; 501 | if (options.quality) { 502 | addr += "&q=" + (options.quality + 1); 503 | } 504 | if (options.type) { 505 | addr += "&type=" + options.type; 506 | } 507 | } 508 | 509 | if (!_settings2.default.cache[addr] || options.nocache) { 510 | this.loadData(addr, function (data) { 511 | (0, _nextTick2.default)(callback, [assertData(errorCallback, _this.parseData(data, options)), data]); 512 | }, errorCallback); 513 | } else { 514 | var data = _settings2.default.cache[addr]; 515 | (0, _nextTick2.default)(callback, [assertData(errorCallback, this.parseData(data, options)), data]); 516 | } 517 | } else { 518 | (0, _nextTick2.default)(callback, [assertData(errorCallback, this.parseData(region, options)), region]); 519 | } 520 | 521 | return promise; 522 | }, 523 | 524 | /** 525 | * overloadable data transfer function 526 | */ 527 | loadData: function loadData(path, callback, errorCallback) { 528 | return _settings2.default.load(path, callback, errorCallback); 529 | }, 530 | 531 | /** 532 | * parse default data format 533 | * @param {String} data 534 | * @returns {geoJSON} 535 | */ 536 | parseData: function parseData(data, options) { 537 | if (!data.meta) { 538 | return { 539 | error: data.error 540 | }; 541 | } 542 | return { 543 | type: "FeatureCollection", 544 | features: (0, _setupGeometry2.default)(data, options), 545 | metaData: data.meta 546 | }; 547 | }, 548 | 549 | /** 550 | * drops internal cache 551 | */ 552 | dropCache: function dropCache() { 553 | _settings2.default.cache = {}; 554 | }, 555 | 556 | _setCoordOrder: function _setCoordOrder(order) { 557 | _settings2.default.latLongOrder = order == "latlong"; 558 | }, 559 | 560 | /** 561 | * convert geoJSON to YMAPS collection 562 | * @param geoJson 563 | * @param [ym21] - Maps API namespace 564 | * @returns {osmeMapCollection} 565 | */ 566 | toYandex: _yandex2.default, 567 | 568 | /** 569 | * converts GeoJSON to Google.data object 570 | * @param geoJson 571 | * @param maps 572 | * @returns {osmeMapCollection} 573 | */ 574 | toGoogle: _google2.default, 575 | 576 | /** 577 | * converts GeoJSON to Leaflet object 578 | * @param geoJson 579 | * @param L 580 | * @returns {osmeMapCollection} 581 | */ 582 | toLeaflet: _leaflet2.default, 583 | 584 | /** 585 | * converts GeoJSON to GeoJSON with "unbounded" coordinates 586 | * @param geoJson 587 | * @returns {geoJson} 588 | */ 589 | toUnboundedGeoJSON: _unbounded2.default, 590 | 591 | /** 592 | * Reverse geocode 593 | * @param {Number[]} point - Point. 594 | * @param {Object} [options] 595 | * @param {Number} [options.seq] - Sequence number. 596 | * @param {String} [options.lang] - Language. 597 | * @param {Function} callback 598 | * @param {Function} [errorcallback] 599 | */ 600 | geocode: _geocode2.default 601 | }; 602 | 603 | exports.default = osmeRegions; 604 | },{"./collections/google":2,"./collections/leaflet":3,"./collections/unbounded":4,"./collections/yandex":5,"./geocode":6,"./settings":8,"./utils/nextTick":14,"./utils/recombine":15,"./utils/setupGeometry":17}],8:[function(require,module,exports){ 605 | "use strict"; 606 | 607 | Object.defineProperty(exports, "__esModule", { 608 | value: true 609 | }); 610 | 611 | var _load_native = require("./utils/load_native"); 612 | 613 | var _load_native2 = _interopRequireDefault(_load_native); 614 | 615 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 616 | 617 | var settings = { 618 | HOST: typeof window !== "undefined" && window.location.protocol === "https:" ? "https://osme.geolocated.org/regions/v1/" : "http://data.esosedi.org/regions/v1/", 619 | GEOCODEHOST: "http://data.esosedi.org/geocode/v1", 620 | DEBUG: false, 621 | cache: {}, 622 | 623 | latLongOrder: 0, 624 | 625 | load: _load_native2.default 626 | }; 627 | 628 | exports.default = settings; 629 | },{"./utils/load_native":13}],9:[function(require,module,exports){ 630 | "use strict"; 631 | 632 | Object.defineProperty(exports, "__esModule", { 633 | value: true 634 | }); 635 | function buildIdTable(geoJson) { 636 | var ret = {}, 637 | features = geoJson.features; 638 | for (var i = 0, l = features.length; i < l; ++i) { 639 | var feature = features[i]; 640 | if (feature && feature.properties) { 641 | ret[feature.properties.osmId] = feature; 642 | } 643 | } 644 | 645 | return ret; 646 | } 647 | 648 | exports.default = buildIdTable; 649 | },{}],10:[function(require,module,exports){ 650 | "use strict"; 651 | 652 | Object.defineProperty(exports, "__esModule", { 653 | value: true 654 | }); 655 | function flipa(a) { 656 | var b = []; 657 | for (var i = 0, l = a.length; i < l; ++i) { 658 | b[i] = [a[i][1], a[i][0]]; 659 | } 660 | return b; 661 | } 662 | 663 | function flip(a) { 664 | var b = []; 665 | for (var i = 0, l = a.length; i < l; ++i) { 666 | b[i] = flipa(a[i]); 667 | } 668 | return b; 669 | } 670 | 671 | function convertCoordinate(feature) { 672 | return { 673 | type: "Feature", 674 | geometry: { 675 | type: "Polygon", 676 | fillRule: feature.geometry.coordinates.length > 1 ? "evenOdd" : "nonZero", 677 | coordinates: flip(feature.geometry.coordinates) 678 | }, 679 | properties: feature.properties 680 | }; 681 | } 682 | 683 | exports.default = convertCoordinate; 684 | },{}],11:[function(require,module,exports){ 685 | "use strict"; 686 | 687 | Object.defineProperty(exports, "__esModule", { 688 | value: true 689 | }); 690 | var codingCoefficient = 1 / 1000000, 691 | fraction = 2, 692 | dividor = 1 / 0xffff; // target resolution 65k, real 4k 693 | 694 | /** 695 | * coordinateDecode 696 | * partof Yandex.Maps.API 697 | */ 698 | function decodeByteVector(x, N) { 699 | var point = 0; 700 | for (var i = 0; i < N; ++i) { 701 | point |= x.charCodeAt(i) << i * 8; 702 | } 703 | return point; 704 | } 705 | 706 | function clampx(x) { 707 | return Math.min(180, Math.max(-180, x)); 708 | } 709 | 710 | function clampy(y) { 711 | return Math.min(85, Math.max(-85, y)); 712 | } 713 | 714 | function fromBase64(input) { 715 | input = input.replace(/_/g, "/").replace(/-/g, "+"); 716 | if (typeof atob !== "undefined") { 717 | return atob(input); 718 | } else { 719 | // hide from webpack 720 | var B = eval("Buffer"); 721 | return new B(input, "base64").toString("binary"); 722 | } 723 | } 724 | 725 | function decodeLineBlock(encodedCoordinates) { 726 | var byteVector = fromBase64(encodedCoordinates), 727 | byteVectorLength = byteVector.length, 728 | bounds = [[decodeByteVector(byteVector.substr(0, 4), 4) * codingCoefficient, decodeByteVector(byteVector.substr(4, 4), 4) * codingCoefficient], [decodeByteVector(byteVector.substr(8, 4), 4) * codingCoefficient, decodeByteVector(byteVector.substr(12, 4), 4) * codingCoefficient]], 729 | dimension = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]], 730 | result = [], 731 | index = 16, 732 | fx = dimension[0] * dividor, 733 | fy = dimension[1] * dividor; 734 | 735 | function read() { 736 | var ret = decodeByteVector(byteVector.substr(index, fraction), fraction); 737 | index += fraction; 738 | return ret; 739 | } 740 | 741 | while (index < byteVectorLength) { 742 | var position = [clampy(read() * fx + bounds[0][0]), clampx(read() * fy + bounds[0][1])]; 743 | result.push([position[1], position[0]]); 744 | } 745 | return result; 746 | } 747 | 748 | function decodeWay(lineBlock, wayId, osmeData) { 749 | if (osmeData.wayCache[wayId]) { 750 | return osmeData.wayCache[wayId]; 751 | } 752 | return osmeData.wayCache[wayId] = decodeLineBlock(lineBlock); 753 | } 754 | 755 | exports.default = decodeWay; 756 | },{}],12:[function(require,module,exports){ 757 | "use strict"; 758 | 759 | Object.defineProperty(exports, "__esModule", { 760 | value: true 761 | }); 762 | exports.getFixedGeometry = exports.getGeometry = undefined; 763 | 764 | var _decoder = require("./decoder"); 765 | 766 | var _decoder2 = _interopRequireDefault(_decoder); 767 | 768 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 769 | 770 | function EQ(first, second, diff) { 771 | diff = diff || 1e-9; 772 | var dx = Math.abs(second[0] - first[0]), 773 | dy = Math.abs(second[1] - first[1]); 774 | return dx < diff && dy < diff; 775 | } 776 | 777 | function fixDegenerate(way, path) { 778 | var offset = 0, 779 | l = way.length, 780 | lp = path.length, 781 | limit = Math.min(l, lp), 782 | delta = 10 / 0xffff; //10 HOPS 783 | lp--; 784 | if (lp < 1) { 785 | return 0; 786 | } 787 | 788 | for (var i = 0; i < limit; ++i) { 789 | if (EQ(way[i], path[lp - i], delta)) { 790 | offset++; 791 | } else { 792 | break; 793 | } 794 | } 795 | 796 | return offset; 797 | } 798 | 799 | function getGeometry(regionId, osmeData, options) { 800 | var coordinates = [], 801 | fixedPoints = [], 802 | meta = [], 803 | paths = regionId.length ? regionId : osmeData.paths[regionId], 804 | 805 | //segments = [], 806 | osmeWays = osmeData.ways; 807 | 808 | options = options || {}; 809 | 810 | osmeData.wayCache = osmeData.wayCache || {}; 811 | 812 | if (!paths) { 813 | return false; 814 | } 815 | for (var pathId = 0, pathLength = paths.length; pathId < pathLength; ++pathId) { 816 | var path = paths[pathId]; 817 | var pathCoordinates = [], 818 | ways = [], 819 | segmentFixedPoints = [0]; 820 | if (typeof path == "number") { 821 | path = [path]; 822 | } 823 | for (var i = 0, l = path.length; i < l; ++i) { 824 | var wayId = Math.abs(path[i]); 825 | var way = (0, _decoder2.default)(osmeWays[wayId], wayId, osmeData); 826 | if (path[i] < 0) { 827 | way = way.slice(0); 828 | way.reverse(); 829 | } 830 | if (options.fixDegenerate) { 831 | var offset = fixDegenerate(way, pathCoordinates); 832 | if (offset) { 833 | way = way.slice(offset); 834 | } 835 | if (i == l - 1) { 836 | var tw = way.slice(0); 837 | tw.reverse(); 838 | offset = fixDegenerate(pathCoordinates, way); 839 | if (offset) { 840 | offset--; 841 | way.length = way.length - offset; 842 | pathCoordinates = pathCoordinates.slice(offset); 843 | } 844 | } 845 | } else { 846 | // edges have same coordinates 847 | if (pathCoordinates.length) { 848 | pathCoordinates.length = pathCoordinates.length - 1; 849 | } 850 | } 851 | 852 | pathCoordinates.push.apply(pathCoordinates, way); 853 | segmentFixedPoints.push(pathCoordinates.length - 1); 854 | ways.push(wayId); 855 | } 856 | pathCoordinates.push(pathCoordinates[0]); 857 | coordinates.push(pathCoordinates); 858 | fixedPoints.push(segmentFixedPoints); 859 | meta.push(ways); 860 | } 861 | 862 | return { 863 | type: "Polygon", 864 | fillRule: "nonZero", 865 | coordinates: coordinates, 866 | path: paths, 867 | fixedPoints: fixedPoints 868 | }; 869 | } 870 | 871 | function getFixedGeometry(regionId, osmeData) { 872 | return getGeometry(regionId, osmeData, { fixDegenerate: true }); 873 | } 874 | 875 | exports.getGeometry = getGeometry; 876 | exports.getFixedGeometry = getFixedGeometry; 877 | },{"./decoder":11}],13:[function(require,module,exports){ 878 | "use strict"; 879 | 880 | Object.defineProperty(exports, "__esModule", { 881 | value: true 882 | }); 883 | /** 884 | * Vanilla Ajax data transfer 885 | * @param {String} path 886 | * @param {Function} callback 887 | * @param {Function} errorCallback 888 | */ 889 | function load(path, callback, errorCallback) { 890 | try { 891 | var xhr = new XMLHttpRequest(); 892 | xhr.open("GET", path, true); 893 | xhr.onreadystatechange = function () { 894 | if (xhr.readyState === 4) { 895 | if (xhr.status === 200 || xhr.status === 304) { 896 | try { 897 | var response = JSON.parse(xhr.responseText); 898 | callback(response); 899 | } catch (e) { 900 | errorCallback(e); 901 | } 902 | } else { 903 | errorCallback(xhr); 904 | } 905 | } 906 | }; 907 | xhr.setRequestHeader("Content-Type", "application/json"); 908 | xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 909 | xhr.send(); 910 | } catch (e) { 911 | errorCallback(e); 912 | } 913 | } 914 | 915 | exports.default = load; 916 | },{}],14:[function(require,module,exports){ 917 | "use strict"; 918 | 919 | Object.defineProperty(exports, "__esModule", { 920 | value: true 921 | }); 922 | function nextTick(callback, args) { 923 | var _this = this; 924 | 925 | Promise.resolve().then(function () { 926 | return callback.apply(_this, args); 927 | }); 928 | } 929 | 930 | exports.default = nextTick; 931 | },{}],15:[function(require,module,exports){ 932 | "use strict"; 933 | 934 | Object.defineProperty(exports, "__esModule", { 935 | value: true 936 | }); 937 | 938 | var _region = require("./region"); 939 | 940 | var _region2 = _interopRequireDefault(_region); 941 | 942 | var _geometryDecode = require("./geometryDecode"); 943 | 944 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 945 | 946 | /** 947 | * recombination 948 | * @param regionsData 949 | * @param query 950 | * @returns {*} 951 | */ 952 | function recombineRegion(regionsData, query) { 953 | var regions = regionsData.regions, 954 | inpaths = regionsData.paths, 955 | passRegions = {}, 956 | paths = [], 957 | way; 958 | 959 | function filterPath(path) { 960 | var result = []; 961 | for (var i = 0, l = path.length; i < l; ++i) { 962 | if (1 || path[i].length > 1) { 963 | result.push([path[i]]); 964 | } 965 | } 966 | return result; 967 | } 968 | 969 | //fill regions and way counter 970 | for (var ri in regions) { 971 | if (regions.hasOwnProperty(ri)) { 972 | var tpaths = inpaths[ri]; 973 | var qf = query.filter((0, _region2.default)(ri, regionsData)); 974 | if (qf) { 975 | if (qf !== true) { 976 | if (qf.path) { 977 | tpaths = qf.path; 978 | } 979 | } 980 | if (tpaths && tpaths.length) { 981 | tpaths = filterPath(tpaths); 982 | if (tpaths.length) { 983 | passRegions[ri] = ri; 984 | paths.push.apply(paths, tpaths); 985 | } 986 | } 987 | } 988 | } 989 | } 990 | 991 | function joinPaths(patha, pathb) { 992 | var usedWays = {}, 993 | wayDirection = {}, 994 | wayLookup = {}; 995 | 996 | var apaths = [patha, pathb]; 997 | for (var _ri = 0; _ri < 2; ++_ri) { 998 | var _tpaths = apaths[_ri]; 999 | for (var pathId = 0, pathLength = _tpaths.length; pathId < pathLength; ++pathId) { 1000 | var path = _tpaths[pathId]; 1001 | if (typeof path == "number") { 1002 | path = [path]; 1003 | } 1004 | for (var i = 0, l = path.length; i < l; ++i) { 1005 | var _wayId = Math.abs(path[i]); 1006 | usedWays[_wayId] = (usedWays[_wayId] || 0) + 1; 1007 | } 1008 | } 1009 | } 1010 | 1011 | var //pass = 0, 1012 | lost = 0; 1013 | for (var _ri2 = 0; _ri2 < 2; ++_ri2) { 1014 | var _tpaths2 = apaths[_ri2]; 1015 | for (var _pathId = 0, _pathLength = _tpaths2.length; _pathId < _pathLength; ++_pathId) { 1016 | var _path = _tpaths2[_pathId]; 1017 | if (typeof _path == "number") { 1018 | _path = [_path]; 1019 | } 1020 | 1021 | for (var _i = 0, _l = _path.length; _i < _l; ++_i) { 1022 | var wayId = Math.abs(_path[_i]); 1023 | if (usedWays[wayId] === 1) { 1024 | //pass++; 1025 | var lw = +_path[(_i - 1 + _l) % _l], 1026 | rw = +_path[(_i + 1 + _l) % _l]; 1027 | wayLookup[lw] = wayLookup[lw] || []; 1028 | wayLookup[lw].push(_path[_i]); 1029 | wayDirection[_path[_i]] = [+lw, +_path[_i], +rw, _ri2, _pathId]; 1030 | } else { 1031 | lost++; 1032 | } 1033 | } 1034 | } 1035 | } 1036 | if (!lost) { 1037 | return false; 1038 | } 1039 | 1040 | function getWay() { 1041 | for (var i in wayDirection) { 1042 | if (testWay(i)) { 1043 | return +i; 1044 | } 1045 | } 1046 | return false; 1047 | } 1048 | 1049 | function testWay(i) { 1050 | return i && wayDirection.hasOwnProperty(i) && wayDirection[i][1]; 1051 | } 1052 | 1053 | // function reverse () { 1054 | // rpath.reverse(); 1055 | // for (var i = 0, l = rpath.length; i < l; ++i) { 1056 | // rpath[i] *= -1; 1057 | // } 1058 | // ord *= -1; 1059 | // return rpath; 1060 | // } 1061 | 1062 | var rpaths = [], 1063 | rpath = [], 1064 | ord = 1; 1065 | 1066 | function tryJoinWay(rpath, way) { 1067 | if (!wayDirection[way]) { 1068 | return false; 1069 | } 1070 | var lw = ord == -1 ? wayDirection[way][0] : 0, 1071 | rw = ord == +1 ? wayDirection[way][2] : 0; 1072 | if (testWay(rw)) { 1073 | way = rw; 1074 | rpath.push(+way * ord); 1075 | } else if (testWay(lw)) { 1076 | way = lw; 1077 | rpath.push(+way); 1078 | } else { 1079 | // indirect 1080 | var rwset = wayLookup[-wayDirection[way][2]]; 1081 | way = 0; 1082 | for (var j in rwset) { 1083 | rw = rwset[j]; 1084 | if (testWay(rw)) { 1085 | way = rw; 1086 | rpath.push(+way); 1087 | break; 1088 | } 1089 | } 1090 | if (!way) { 1091 | return false; 1092 | } 1093 | } 1094 | return way; 1095 | } 1096 | 1097 | while (false !== (way = getWay())) { 1098 | rpath = []; 1099 | ord = 1; 1100 | rpath.push(+way); 1101 | while (way) { 1102 | wayDirection[way][1] = 0; 1103 | var newWay = tryJoinWay(rpath, way); 1104 | if (!newWay) { 1105 | break; 1106 | } 1107 | way = newWay; 1108 | } 1109 | rpaths.push(rpath); 1110 | } 1111 | return rpaths; 1112 | } 1113 | 1114 | paths.sort(function (a, b) { 1115 | return Math.abs(a[0][0]) < Math.abs(b[0][0]); 1116 | }); 1117 | 1118 | var rpath = paths[0], 1119 | skip = { 0: 1 }, 1120 | skipCnt = 1, 1121 | rpaths = [], 1122 | l = paths.length, 1123 | freePass = 0, 1124 | joinPass = 0, 1125 | ccx = 0; 1126 | 1127 | while (skipCnt < l) { 1128 | joinPass = 0; 1129 | for (var i = 1, _l2 = paths.length; i < _l2; ++i) { 1130 | var rid = i % _l2; 1131 | if (!(rid in skip)) { 1132 | var result = joinPaths(rpath, paths[rid]); 1133 | if (result && result.length == 1) { 1134 | rpath = result; 1135 | skip[rid] = 1; 1136 | skipCnt++; 1137 | joinPass++; 1138 | } else { 1139 | freePass = rid; 1140 | } 1141 | } 1142 | } 1143 | if (!joinPass) { 1144 | if (freePass) { 1145 | rpaths.push(rpath[0]); 1146 | rpath = paths[freePass]; 1147 | skip[freePass] = 1; 1148 | skipCnt++; 1149 | } else { 1150 | break; 1151 | } 1152 | } 1153 | if (ccx++ > 1000) { 1154 | break; 1155 | } 1156 | } 1157 | 1158 | if (rpath) { 1159 | rpaths.push(rpath[0]); 1160 | } 1161 | 1162 | return (0, _geometryDecode.getFixedGeometry)(rpaths, regionsData); 1163 | } 1164 | 1165 | exports.default = recombineRegion; 1166 | },{"./geometryDecode":12,"./region":16}],16:[function(require,module,exports){ 1167 | "use strict"; 1168 | 1169 | Object.defineProperty(exports, "__esModule", { 1170 | value: true 1171 | }); 1172 | 1173 | 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; }; }(); 1174 | 1175 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1176 | 1177 | /** 1178 | * @name RegionObject 1179 | * @class 1180 | */ 1181 | var RegionObject = function () { 1182 | function RegionObject(rid, meta, prop, data) { 1183 | _classCallCheck(this, RegionObject); 1184 | 1185 | /** @member {Number} */ 1186 | this.osmId = rid; 1187 | /** @member {Number} */ 1188 | this.geoNamesId = prop.geoNamesId; 1189 | /** @member {String} */ 1190 | this.iso = prop.iso3166; 1191 | /** @member {Number} */ 1192 | this.level = meta.level; 1193 | /** @member {Object} */ 1194 | this.properties = prop; 1195 | 1196 | this._meta = meta; 1197 | this._data = data; 1198 | } 1199 | 1200 | _createClass(RegionObject, [{ 1201 | key: "getBorderWith", 1202 | value: function getBorderWith(id) { 1203 | var wset = {}, 1204 | i, 1205 | l1, 1206 | j, 1207 | l2, 1208 | path1 = this._data.paths[id], 1209 | path2 = this._data.paths[this.osmId]; 1210 | for (i = 0, l1 = path1.length; i < l1; ++i) { 1211 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 1212 | wset[Math.abs(path1[i][j])] = 1; 1213 | } 1214 | } 1215 | var result = []; 1216 | for (i = 0, l1 = path2.length; i < l1; ++i) { 1217 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 1218 | if (wset[Math.abs(path2[i][j])]) { 1219 | // path is full in 1220 | result.push(path2[i]); 1221 | } 1222 | } 1223 | } 1224 | return result; 1225 | } 1226 | }, { 1227 | key: "hasBorderWith", 1228 | value: function hasBorderWith(id) { 1229 | var wset = {}, 1230 | i, 1231 | l1, 1232 | j, 1233 | l2, 1234 | path1 = this._data.paths[this.osmId], 1235 | path2 = this._data.paths[id]; 1236 | if (!path1 || !path2) { 1237 | return false; 1238 | } 1239 | for (i = 0, l1 = path1.length; i < l1; ++i) { 1240 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 1241 | wset[Math.abs(path1[i][j])] = 1; 1242 | } 1243 | } 1244 | for (i = 0, l1 = path2.length; i < l1; ++i) { 1245 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 1246 | if (wset[Math.abs(path2[i][j])]) { 1247 | return true; 1248 | } 1249 | } 1250 | } 1251 | return false; 1252 | } 1253 | }, { 1254 | key: "hasParent", 1255 | value: function hasParent(id) { 1256 | var parents = this._meta.parents; 1257 | for (var i = 0, l = parents.length; i < l; ++i) { 1258 | if (parents[i].id == id) { 1259 | return true; 1260 | } 1261 | } 1262 | return false; 1263 | } 1264 | }]); 1265 | 1266 | return RegionObject; 1267 | }(); 1268 | 1269 | /** 1270 | * wraps region for filter functions 1271 | * @param rid 1272 | * @param data 1273 | * @returns {RegionObject} 1274 | */ 1275 | 1276 | 1277 | function wrapRegion(rid, data) { 1278 | var meta = data.regions[rid], 1279 | prop = meta.property || {}; 1280 | return new RegionObject(rid, meta, prop, data); 1281 | } 1282 | 1283 | exports.default = wrapRegion; 1284 | },{}],17:[function(require,module,exports){ 1285 | "use strict"; 1286 | 1287 | Object.defineProperty(exports, "__esModule", { 1288 | value: true 1289 | }); 1290 | 1291 | var _region = require("./region"); 1292 | 1293 | var _region2 = _interopRequireDefault(_region); 1294 | 1295 | var _recombine = require("./recombine"); 1296 | 1297 | var _recombine2 = _interopRequireDefault(_recombine); 1298 | 1299 | var _geometryDecode = require("./geometryDecode"); 1300 | 1301 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1302 | 1303 | /** 1304 | * main decode function 1305 | * @param regionsData 1306 | * @param options 1307 | * @returns {Array} 1308 | */ 1309 | function setupGeometry(regionsData, options) { 1310 | options = options || {}; 1311 | var regions = regionsData.regions, 1312 | dataset = [], 1313 | postFilter = options.postFilter || (regionsData.meta && regionsData.meta.postFilter ? new Function("region", regionsData.meta.postFilter) : 0), 1314 | scheme = options.scheme || regionsData.meta && regionsData.meta.scheme, 1315 | disputedBorders = regionsData.meta && regionsData.meta.disputedBorders || {}, 1316 | useSetup = options.recombine || options.lang || "en", 1317 | disputedBorder = typeof useSetup == "string" ? disputedBorders[useSetup] : useSetup, 1318 | geometry = 0; 1319 | 1320 | for (var _i in disputedBorders) { 1321 | var setup = disputedBorders[_i]; 1322 | for (var j in setup) { 1323 | var regionSet = setup[j]; 1324 | if (typeof regionSet == "string") { 1325 | setup[j] = new Function("region", regionSet); 1326 | } 1327 | } 1328 | } 1329 | 1330 | for (var _i2 in regions) { 1331 | if (regions.hasOwnProperty(_i2)) { 1332 | if (!postFilter || postFilter((0, _region2.default)(_i2, regionsData))) { 1333 | if (disputedBorder && disputedBorder[+_i2]) { 1334 | geometry = (0, _recombine2.default)(regionsData, { 1335 | filter: disputedBorder[+_i2] 1336 | }); 1337 | } else if (scheme && scheme[+_i2]) { 1338 | var sch = scheme[+_i2]; 1339 | geometry = (0, _recombine2.default)(regionsData, { 1340 | filter: typeof sch == "string" ? new Function("region", sch) : sch 1341 | }); 1342 | } else { 1343 | geometry = (0, _geometryDecode.getGeometry)(+_i2, regionsData); 1344 | } 1345 | 1346 | if (geometry) { 1347 | dataset[regions[_i2].index] = { 1348 | type: "Feature", 1349 | geometry: geometry, 1350 | properties: { 1351 | osmId: _i2, 1352 | level: regions[_i2].level, 1353 | properties: regions[_i2].property || {}, 1354 | parents: regions[_i2].parents, 1355 | hintContent: regions[_i2].name, 1356 | name: regions[_i2].name, 1357 | title: regions[_i2].name, 1358 | wikipedia: regions[_i2].wikipedia, 1359 | orderIndex: regions[_i2].index, 1360 | square: regions[_i2].square 1361 | } 1362 | }; 1363 | } 1364 | } 1365 | } 1366 | } 1367 | var result = []; 1368 | for (var i = 0, l = dataset.length; i < l; ++i) { 1369 | if (dataset[i]) { 1370 | result.push(dataset[i]); 1371 | } 1372 | } 1373 | return result; 1374 | } 1375 | 1376 | exports.default = setupGeometry; 1377 | },{"./geometryDecode":12,"./recombine":15,"./region":16}],18:[function(require,module,exports){ 1378 | "use strict"; 1379 | 1380 | Object.defineProperty(exports, "__esModule", { 1381 | value: true 1382 | }); 1383 | function getShortestPath(contour) { 1384 | var halfWorld = 180; 1385 | var result = [contour[0]], 1386 | point = contour[0]; 1387 | for (var i = 1, l = contour.length; i < l; ++i) { 1388 | var delta = point[0] - contour[i][0]; 1389 | if (Math.abs(delta) > halfWorld) { 1390 | delta = delta < 0 ? -360 : 360; 1391 | } else { 1392 | delta = 0; 1393 | } 1394 | 1395 | var nextPoint = [contour[i][0] + delta, contour[i][1]]; 1396 | result.push(nextPoint); 1397 | point = nextPoint; 1398 | } 1399 | return result; 1400 | } 1401 | 1402 | var getShortestContour = exports.getShortestContour = function getShortestContour(contour) { 1403 | return contour.map(function (path) { 1404 | return getShortestPath(path); 1405 | }); 1406 | }; 1407 | 1408 | exports.default = getShortestPath; 1409 | },{}]},{},[1]); 1410 | -------------------------------------------------------------------------------- /examples/APIs/d3-globe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | A D3 map 4 | 5 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples/APIs/d3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | A D3 map 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 37 | 38 | -------------------------------------------------------------------------------- /examples/APIs/google.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 8 | 9 | 10 | 11 | 21 | 22 | 23 | 24 | 25 | 26 | 42 | 43 | -------------------------------------------------------------------------------- /examples/APIs/leaflet.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22 | 23 | Good example for Leaflet - Russia. 24 | It it so big, that goes beyond 180 degrees. 25 | As result you cannot display Russia without .toLeaflet (or .toUnboundedCoordinates) command. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 47 | 48 | -------------------------------------------------------------------------------- /examples/APIs/yandex.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 44 | 45 | -------------------------------------------------------------------------------- /examples/disputed-borders.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 9 | 10 | 11 | 12 | 22 | Things to compare: Marocco, Taiwan, Crimea and so on. 23 | 24 | 25 | 26 | Dispute:EN 27 | 28 | 29 | 30 | Dispute:RU 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 62 | 63 | -------------------------------------------------------------------------------- /examples/example.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Визуализатор данных регионов 6 | 7 | 9 | 10 | 11 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 151 | 152 | -------------------------------------------------------------------------------- /examples/geocode-example.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Geocode example 6 | 7 | 9 | 10 | 11 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 150 | 151 | -------------------------------------------------------------------------------- /examples/maritime.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 48 | -------------------------------------------------------------------------------- /examples/recombination/barcelona.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Disputed borders 6 | 7 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 63 | -------------------------------------------------------------------------------- /examples/static-data.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Static data usage 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 24 | 25 | 26 | 27 | 28 | 29 | 45 | -------------------------------------------------------------------------------- /geocoder.md: -------------------------------------------------------------------------------- 1 | Osme has reverse geocode. 2 | 3 | GET url: http://data.esosedi.org/geocode/v1?[lng=(ru|en)]&point=x,y[&seq=?][&callback=?] 4 | Where point - target point, use callback for jsonp, and seq for tracking your requests. 5 | 6 | Answer includes 2 main sections: 7 | ``` 8 | "target": { 9 | "l2": 60189, // administrative level 2 ( Country ) 10 | "l3": 1029256, // 3 11 | "l4": 81995, 12 | "l5": 0, 13 | "l6": 1235817, 14 | "l7": 0, 15 | "l8": 1918618, // 8 (normaly - last) 16 | "ll": 1918618, // last level (up to 12) 17 | "iso": [ // iso3166-2 code 18 | "RU", 19 | "KLU" 20 | ] 21 | }, 22 | ``` 23 | 24 | And some of them (not all!) has link to names 25 | ``` 26 | "names": { 27 | "60189": { 28 | "name": "Россия", // name 29 | "level": 2, // admin_level 30 | "iso1": "RU", // iso3166-1 31 | "visibleName": "Россия", // esosedi name 32 | "references": { // external reference 33 | "osm": { 34 | "relationId": 60189 // to osm relation id 35 | }, 36 | "esosedi": 1000258596, // to esosedi object 37 | "wikipedia": "en:Russia", // to wikipedia 38 | "geonames": 2017370 // to geonames 39 | }, 40 | "boundingBox": [ // bounding box of region 41 | [ 42 | 41.1868, 43 | 19.4142 44 | ], 45 | [ 46 | 82.0577, 47 | 191.037 48 | ] 49 | ] 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "osme", 3 | "version": "1.3.0", 4 | "description": "Provides geometry for regions of the World", 5 | "main": "lib/index.js", 6 | "unpkg": "umd/index.js", 7 | "scripts": { 8 | "build": "npm run build:npm & npm run build:bundle & npm run build:umd", 9 | "build:npm": "babel src -d lib", 10 | "build:bundle": "browserify lib/browserBundle.js > bundle.js", 11 | "build:umd": "browserify lib/browserBundle.js --standalone osme -o umd/index.js", 12 | "prepublish": "npm run build", 13 | "lint": "eslint src tests", 14 | "lint:fix": "eslint src tests --fix", 15 | "test": "npm run test:pick -- 'tests/*.spec.js'", 16 | "test:pick": "BABEL_ENV=test mocha --compilers js:babel-core/register" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/esosedi/regions.git" 21 | }, 22 | "keywords": [ 23 | "maps", 24 | "osm", 25 | "regions", 26 | "google maps", 27 | "leaflet", 28 | "country shape" 29 | ], 30 | "author": "Anton Korzunov ", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/esosedi/regions/issues" 34 | }, 35 | "homepage": "https://github.com/esosedi/regions", 36 | "devDependencies": { 37 | "babel-cli": "^6.18.0", 38 | "babel-eslint": "^10.0.1", 39 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 40 | "babel-preset-env": "^1.7.0", 41 | "browserify": "^14.3.0", 42 | "chai": "^3.5.0", 43 | "eslint": "^5.12.1", 44 | "eslint-plugin-mocha": "^4.9.0", 45 | "mocha": "^3.3.0", 46 | "prettier": "^1.15.3", 47 | "size-limit": "^0.21.1" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/browserBundle.js: -------------------------------------------------------------------------------- 1 | import osmeRegions from "./regions.js"; 2 | 3 | module.exports = osmeRegions; 4 | -------------------------------------------------------------------------------- /src/collections/google.js: -------------------------------------------------------------------------------- 1 | import buildIdTable from "../utils/buildIdTable"; 2 | 3 | function styleToGoogle(style) { 4 | var ret = {}; 5 | if ("strokeWidth" in style) { 6 | ret.strokeWeight = style.strokeWidth; 7 | } 8 | if ("fillColor" in style) { 9 | ret.fillColor = style.fillColor; 10 | } 11 | if ("strokeColor" in style) { 12 | ret.strokeColor = style.strokeColor; 13 | } 14 | if ("strokeOpacity" in style) { 15 | ret.strokeOpacity = Math.max(0.001, style.strokeOpacity); 16 | } 17 | if ("fillOpacity" in style) { 18 | ret.fillOpacity = Math.max(0.001, style.fillOpacity); 19 | } 20 | return ret; 21 | } 22 | 23 | function toGoogle(geoJson, maps) { 24 | // use google.data 25 | var idTable = buildIdTable(geoJson), 26 | collection = new (maps || window.google.maps).Data(); 27 | collection.addGeoJson(geoJson); 28 | 29 | return { 30 | collection: collection, 31 | add: function(map) { 32 | collection.setMap(map); 33 | }, 34 | remove: function() { 35 | collection.setMap(null); 36 | }, 37 | setStyles: function(fn) { 38 | collection.setStyle(function(object) { 39 | return styleToGoogle(fn(idTable[object.getProperty("osmId")], object)); 40 | }); 41 | }, 42 | /** 43 | * @param {String} eventName 44 | * @param {Function} callback 45 | * @param {Object} [ctx] 46 | */ 47 | addEvent: function(eventName, callback, ctx) { 48 | collection.addListener(eventName, function(event) { 49 | var target = event.feature; 50 | callback.call( 51 | ctx, 52 | idTable[target.getProperty("osmId")], 53 | [eventName, "google"], 54 | target, 55 | event 56 | ); 57 | }); 58 | }, 59 | removeEvent: function(event) { 60 | collection.removeListener(event); 61 | } 62 | }; 63 | } 64 | 65 | export default toGoogle; 66 | -------------------------------------------------------------------------------- /src/collections/leaflet.js: -------------------------------------------------------------------------------- 1 | import buildIdTable from "../utils/buildIdTable"; 2 | import { getShortestContour } from "../utils/shortestPath"; 3 | 4 | function styleToLeaflet(style) { 5 | var ret = {}; 6 | if ("strokeWidth" in style) { 7 | ret.weight = style.strokeWidth; 8 | } 9 | if ("fillColor" in style) { 10 | ret.fillColor = style.fillColor; 11 | } 12 | if ("strokeColor" in style) { 13 | ret.color = style.strokeColor; 14 | } 15 | if ("strokeOpacity" in style) { 16 | ret.opacity = Math.max(0.001, style.strokeOpacity); 17 | } 18 | if ("fillOpacity" in style) { 19 | ret.fillOpacity = Math.max(0.001, style.fillOpacity); 20 | } 21 | return ret; 22 | } 23 | 24 | function toLeaflet(baseGeoJson, _L) { 25 | const Leaflet = _L || window.L; 26 | 27 | // implement unbounded coordinates 28 | const geoJson = { 29 | ...baseGeoJson, 30 | features: baseGeoJson.features.map(feature => ({ 31 | ...feature, 32 | geometry: { 33 | ...feature.geometry, 34 | coordinates: getShortestContour(feature.geometry.coordinates) 35 | } 36 | })) 37 | }; 38 | 39 | var idTable = buildIdTable(geoJson), 40 | features = [], 41 | collection = Leaflet.geoJSON(geoJson, { 42 | onEachFeature: feature => features.push(feature) 43 | }); 44 | 45 | return { 46 | collection: collection, 47 | add: function(map) { 48 | collection.addTo(map); 49 | }, 50 | remove: function() { 51 | collection.remove(); 52 | }, 53 | setStyles: function(fn) { 54 | features.forEach(feature => 55 | feature.setStyle( 56 | styleToLeaflet(fn(idTable[feature.properties.osmId], feature)) 57 | ) 58 | ); 59 | }, 60 | geoJSON: geoJson, 61 | /** 62 | * @param {String} eventName 63 | * @param {Function} callback 64 | * @param {Object} [ctx] 65 | */ 66 | addEvent: function(eventName, callback, ctx) { 67 | features.forEach(feature => { 68 | feature.addEventListener(eventName, function(event) { 69 | var target = feature; 70 | callback.call( 71 | ctx, 72 | idTable[target.properties.osmId], 73 | [eventName, "leaflet"], 74 | target, 75 | event 76 | ); 77 | }); 78 | }); 79 | }, 80 | removeEvent: function(event) { 81 | features.forEach(feature => { 82 | feature.removeEventListener(event); 83 | }); 84 | } 85 | }; 86 | } 87 | 88 | export default toLeaflet; 89 | -------------------------------------------------------------------------------- /src/collections/unbounded.js: -------------------------------------------------------------------------------- 1 | import {getShortestContour} from "../utils/shortestPath"; 2 | 3 | function toUnboundedGeoJSON(baseGeoJson) { 4 | return { 5 | ...baseGeoJson, 6 | features: baseGeoJson.features.map(feature => ({ 7 | ...feature, 8 | geometry: { 9 | ...feature.geometry, 10 | type: 'MultiPolygon', 11 | coordinates: getShortestContour(feature.geometry.coordinates) 12 | } 13 | })) 14 | }; 15 | } 16 | 17 | export default toUnboundedGeoJSON; 18 | -------------------------------------------------------------------------------- /src/collections/yandex.js: -------------------------------------------------------------------------------- 1 | import buildIdTable from "../utils/buildIdTable"; 2 | 3 | import settings from "../settings"; 4 | import convertCoordinate from "../utils/convertCoordinate"; 5 | 6 | function styleToYandex(style) { 7 | return style; 8 | } 9 | 10 | function toYandex(geoJson, ym21) { 11 | const ymaps = ym21 || window.ymaps; 12 | var collection = new ymaps.GeoObjectCollection(), 13 | dataset = geoJson.features, 14 | idTable = buildIdTable(geoJson); 15 | 16 | for (var i = 0, l = dataset.length; i < l; ++i) { 17 | var line = dataset[i]; 18 | if (line.geometry) { 19 | collection.add( 20 | new ymaps.GeoObject( 21 | settings.latLongOrder ? line : convertCoordinate(line), 22 | { 23 | simplificationFixedPoints: line.geometry.fixedPoints 24 | } 25 | ) 26 | ); 27 | } else { 28 | // window.console && console.error('osme line fail', line); // JFYI 29 | } 30 | } 31 | return { 32 | collection: collection, 33 | add: function(map) { 34 | map.geoObjects.add(collection); 35 | }, 36 | remove: function() { 37 | collection.setParent(null); 38 | }, 39 | setStyles: function(fn) { 40 | collection.each(function(object) { 41 | object.options.set( 42 | styleToYandex(fn(idTable[object.properties.get("osmId")], object)) 43 | ); 44 | }); 45 | }, 46 | /** 47 | * @param {String|Array.} eventName 48 | * @param {Function} callback 49 | * @param {Object} [ctx] 50 | */ 51 | addEvent: function(eventName, callback, ctx) { 52 | collection.events.add(eventName, function(event) { 53 | var target = event.get("target"); 54 | callback.call( 55 | ctx, 56 | idTable[target.properties.get("osmId")], 57 | [eventName, "yandex"], 58 | target, 59 | event 60 | ); 61 | }); 62 | }, 63 | removeEvent: function(event) { 64 | collection.events.remove(event); 65 | } 66 | }; 67 | } 68 | 69 | export default toYandex; 70 | -------------------------------------------------------------------------------- /src/connect/yandex.js: -------------------------------------------------------------------------------- 1 | import osmeRegions from "../index"; 2 | //Yandex.Maps API 3 | const ymaps = window.ymaps; 4 | 5 | if (typeof ymaps === "object" && ymaps.modules && ymaps.modules.define) { 6 | ymaps.modules.define("osmeRegions", ["vow", "system.project"], function( 7 | provide, 8 | vow, 9 | project 10 | ) { 11 | provide( 12 | (ymaps.osmeRegions = { 13 | /** 14 | * @name osmeRegions.load 15 | * @param {String} region RegionId 16 | * @param {Object} options 17 | * @returns {vow.Promise} 18 | */ 19 | load: function(region, options) { 20 | var deferred = vow.defer(); 21 | options = options || {}; 22 | osmeRegions.geoJSON( 23 | region, 24 | { 25 | lang: options.lang || project.data.lang.substr(0, 2), 26 | quality: "quality" in options ? options.quality : 0 27 | }, 28 | function(data) { 29 | deferred.resolve({ 30 | geoObjects: osmeRegions.toYandex(data).collection 31 | }); 32 | }, 33 | function() { 34 | deferred.reject(); 35 | } 36 | ); 37 | return deferred.promise(); 38 | }, 39 | 40 | /** 41 | * @name osmeRegions.geocode 42 | * @param {Number[]} point 43 | * @param {Object} options 44 | * @returns {vow.Promise} 45 | */ 46 | geocode: function(point, options) { 47 | var deferred = vow.defer(); 48 | options = options || {}; 49 | osmeRegions.geoJSON( 50 | point, 51 | { 52 | lang: options.lang || project.data.lang.substr(0, 2) 53 | }, 54 | function(data) { 55 | deferred.resolve(data); 56 | }, 57 | function() { 58 | deferred.reject(); 59 | } 60 | ); 61 | return deferred.promise(); 62 | } 63 | }) 64 | ); 65 | }); 66 | //force execute 67 | ymaps.modules.require("osmeRegions", function() {}); 68 | } 69 | -------------------------------------------------------------------------------- /src/geocode.js: -------------------------------------------------------------------------------- 1 | import settings from "./settings"; 2 | 3 | /** 4 | * Reverse geocode 5 | * @param {Numbrer[]} point - Point. 6 | * @param {Object} [options] 7 | * @param {Number} [options.seq] - Sequence number. 8 | * @param {String} [options.lang] - Language. 9 | * @param {Function} [callback] 10 | * @param {Function} [errorCallback] 11 | * @return {Promise} 12 | */ 13 | function geocode(point, options, _callback, _errorCallback) { 14 | let promise; 15 | let cb_resolve, cb_reject; 16 | 17 | var addr = settings.GEOCODEHOST; 18 | addr += "?point=" + +point[0] + "," + +point[1]; 19 | 20 | if (typeof options == "function") { 21 | _errorCallback = _callback; 22 | _callback = options; 23 | options = {}; 24 | } 25 | 26 | options = { 27 | lang: "en", 28 | seq: 0, 29 | ...(options || {}) 30 | }; 31 | 32 | if (options.seq) { 33 | addr += "&seq=" + +options.seq; 34 | } 35 | if (options.lang) { 36 | addr += "&lng=" + options.lang; 37 | } 38 | 39 | if (typeof Promise != "undefined") { 40 | promise = new Promise((resolve, reject) => { 41 | cb_resolve = resolve; 42 | cb_reject = reject; 43 | }); 44 | } else { 45 | cb_resolve = cb_reject = () => {}; 46 | } 47 | 48 | const callback = geojson => { 49 | cb_resolve(geojson); 50 | _callback && _callback(geojson); 51 | }; 52 | 53 | const errorCallback = geojson => { 54 | cb_reject(geojson); 55 | _errorCallback && _errorCallback(geojson); 56 | }; 57 | 58 | settings.load(addr, json => callback(json), err => errorCallback(err)); 59 | 60 | return promise; 61 | } 62 | 63 | export default geocode; 64 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import osmeRegions from "./regions.js"; 2 | import settings from "./settings"; 3 | 4 | if (typeof window === "undefined") { 5 | if (typeof __webpack_require__ === "undefined") { 6 | const r = eval("require"); 7 | const http = r("http"); 8 | // Overload load method 9 | settings.load = function(path, callback, errorCallback) { 10 | try { 11 | http 12 | .get(path, function(response) { 13 | let body = ""; 14 | response.on("data", function(chunk) { 15 | body += chunk; 16 | }); 17 | response.on("end", function() { 18 | try { 19 | const response = JSON.parse(body); 20 | callback(response); 21 | } catch (e) { 22 | errorCallback(e); 23 | } 24 | body = ""; 25 | }); 26 | }) 27 | .on("error", function(e) { 28 | errorCallback(e); 29 | }); 30 | } catch (e) { 31 | errorCallback(e); 32 | } 33 | }; 34 | } 35 | } else { 36 | window.osmeRegions = osmeRegions; 37 | } 38 | 39 | export default osmeRegions; 40 | -------------------------------------------------------------------------------- /src/regions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * OSMeRegions JavaScript Library 3 | * http://data.esosedi.org/regions/ 4 | * https://github.com/esosedi/regions 5 | * 6 | * @author Anton Korzunov 7 | * Released under the MIT license 8 | */ 9 | 10 | import settings from "./settings"; 11 | 12 | import nextTick from "./utils/nextTick"; 13 | 14 | import recombineRegion from "./utils/recombine"; 15 | import setupGeometry from "./utils/setupGeometry"; 16 | 17 | import geocode from "./geocode"; 18 | 19 | import toGoogleCollection from "./collections/google"; 20 | import toYandexCollection from "./collections/yandex"; 21 | import toLeafletCollection from "./collections/leaflet"; 22 | import toUnboundedGeoJSON from './collections/unbounded'; 23 | 24 | const assertData = (errorCallback, data) => { 25 | if (!data || data.error) { 26 | errorCallback("wrong data", data.error); 27 | } 28 | return data; 29 | }; 30 | 31 | /** 32 | * @name osmeRegions 33 | * @type Object 34 | */ 35 | var osmeRegions = /** @lends osmeRegions */ { 36 | /** 37 | * override data host 38 | * @param host 39 | */ 40 | setHost: function(host) { 41 | settings.HOST = host; 42 | }, 43 | 44 | /** 45 | * @param {Boolean} debug 46 | */ 47 | setDebug: function(debug) { 48 | settings.DEBUG = Boolean(debug); 49 | }, 50 | 51 | /** 52 | * allow recombination 53 | * @param regionsData 54 | * @param {Object} query 55 | * @param {Function} query.filter 56 | * @function 57 | */ 58 | recombine: recombineRegion, 59 | 60 | /** 61 | * Loads GeoJSON from default host 62 | * @param {String} region OSMRelationId,ISO3166-2 code or world's region name(Asia, Europe etc) or absolute URL. 63 | * @param {Object} options 64 | * @param {String} [options.lang='en'] Language (en,de,ru). 65 | * @param {Number} [options.quality=0] Quality. 0 for fullHD resolution. -1,0,+1,+2 for /4, x1, x4, x16 quality. 66 | * @param {String} [options.type=''] Type of data. Can be empty or 'coast' (unstable mode). 67 | * @param {Boolean} [options.nocache] Turns off internal cache. 68 | * @param {Function} [options.postFilter] filtering function. 69 | * @param {String|Object} [options.recombine] recombination function. 70 | * @param {Object} [options.scheme] another recombination function. 71 | * @param {Function} [callback] 72 | * @param {Function} [errorCallback] 73 | * @return {Promise} 74 | */ 75 | geoJSON: function(region, options, _callback, _errorCallback) { 76 | let promise; 77 | let cb_resolve, cb_reject; 78 | options = options || {}; 79 | 80 | if (typeof options === "function") { 81 | throw new Error("callback must be at third place"); 82 | } 83 | 84 | const lang = options.lang || "en"; 85 | let addr = typeof region === "string" ? lang + "_" + region : null; 86 | 87 | if (typeof Promise !== "undefined") { 88 | promise = new Promise((resolve, reject) => { 89 | cb_resolve = resolve; 90 | cb_reject = reject; 91 | }); 92 | } else { 93 | cb_resolve = cb_reject = () => {}; 94 | } 95 | const callback = (geojson, data) => { 96 | if (addr) { 97 | settings.cache[addr] = data; 98 | } 99 | cb_resolve(geojson, data); 100 | _callback && _callback(geojson, data); 101 | }; 102 | 103 | const errorCallback = geojson => { 104 | cb_reject(geojson); 105 | _errorCallback && _errorCallback(geojson); 106 | }; 107 | 108 | if (addr) { 109 | if ((region + "").indexOf("http") === 0) { 110 | addr = region; 111 | } else { 112 | addr = (options.host || settings.HOST) + "?lang=" + addr; 113 | if (options.quality) { 114 | addr += "&q=" + (options.quality + 1); 115 | } 116 | if (options.type) { 117 | addr += "&type=" + options.type; 118 | } 119 | } 120 | 121 | if (!settings.cache[addr] || options.nocache) { 122 | this.loadData( 123 | addr, 124 | data => { 125 | nextTick(callback, [ 126 | assertData(errorCallback, this.parseData(data, options)), 127 | data 128 | ]); 129 | }, 130 | errorCallback 131 | ); 132 | } else { 133 | const data = settings.cache[addr]; 134 | nextTick(callback, [ 135 | assertData(errorCallback, this.parseData(data, options)), 136 | data 137 | ]); 138 | } 139 | } else { 140 | nextTick(callback, [ 141 | assertData(errorCallback, this.parseData(region, options)), 142 | region 143 | ]); 144 | } 145 | 146 | return promise; 147 | }, 148 | 149 | /** 150 | * overloadable data transfer function 151 | */ 152 | loadData: function(path, callback, errorCallback) { 153 | return settings.load(path, callback, errorCallback); 154 | }, 155 | 156 | /** 157 | * parse default data format 158 | * @param {String} data 159 | * @returns {geoJSON} 160 | */ 161 | parseData: function(data, options) { 162 | if (!data.meta) { 163 | return { 164 | error: data.error 165 | }; 166 | } 167 | return { 168 | type: "FeatureCollection", 169 | features: setupGeometry(data, options), 170 | metaData: data.meta 171 | }; 172 | }, 173 | 174 | /** 175 | * drops internal cache 176 | */ 177 | dropCache: function() { 178 | settings.cache = {}; 179 | }, 180 | 181 | _setCoordOrder: function(order) { 182 | settings.latLongOrder = order == "latlong"; 183 | }, 184 | 185 | /** 186 | * convert geoJSON to YMAPS collection 187 | * @param geoJson 188 | * @param [ym21] - Maps API namespace 189 | * @returns {osmeMapCollection} 190 | */ 191 | toYandex: toYandexCollection, 192 | 193 | /** 194 | * converts GeoJSON to Google.data object 195 | * @param geoJson 196 | * @param maps 197 | * @returns {osmeMapCollection} 198 | */ 199 | toGoogle: toGoogleCollection, 200 | 201 | /** 202 | * converts GeoJSON to Leaflet object 203 | * @param geoJson 204 | * @param L 205 | * @returns {osmeMapCollection} 206 | */ 207 | toLeaflet: toLeafletCollection, 208 | 209 | /** 210 | * converts GeoJSON to GeoJSON with "unbounded" coordinates 211 | * @param geoJson 212 | * @returns {geoJson} 213 | */ 214 | toUnboundedGeoJSON: toUnboundedGeoJSON, 215 | 216 | /** 217 | * Reverse geocode 218 | * @param {Number[]} point - Point. 219 | * @param {Object} [options] 220 | * @param {Number} [options.seq] - Sequence number. 221 | * @param {String} [options.lang] - Language. 222 | * @param {Function} callback 223 | * @param {Function} [errorcallback] 224 | */ 225 | geocode: geocode 226 | }; 227 | 228 | export default osmeRegions; 229 | -------------------------------------------------------------------------------- /src/settings.js: -------------------------------------------------------------------------------- 1 | import load from "./utils/load_native"; 2 | 3 | const settings = { 4 | HOST: 5 | typeof window !== "undefined" && window.location.protocol === "https:" 6 | ? "https://osme.geolocated.org/regions/v1/" 7 | : "http://data.esosedi.org/regions/v1/", 8 | GEOCODEHOST: "http://data.esosedi.org/geocode/v1", 9 | DEBUG: false, 10 | cache: {}, 11 | 12 | latLongOrder: 0, 13 | 14 | load: load 15 | }; 16 | 17 | export default settings; 18 | -------------------------------------------------------------------------------- /src/utils/buildIdTable.js: -------------------------------------------------------------------------------- 1 | function buildIdTable(geoJson) { 2 | var ret = {}, 3 | features = geoJson.features; 4 | for (var i = 0, l = features.length; i < l; ++i) { 5 | var feature = features[i]; 6 | if (feature && feature.properties) { 7 | ret[feature.properties.osmId] = feature; 8 | } 9 | } 10 | 11 | return ret; 12 | } 13 | 14 | export default buildIdTable; 15 | -------------------------------------------------------------------------------- /src/utils/convertCoordinate.js: -------------------------------------------------------------------------------- 1 | function flipa(a) { 2 | var b = []; 3 | for (var i = 0, l = a.length; i < l; ++i) { 4 | b[i] = [a[i][1], a[i][0]]; 5 | } 6 | return b; 7 | } 8 | 9 | function flip(a) { 10 | var b = []; 11 | for (var i = 0, l = a.length; i < l; ++i) { 12 | b[i] = flipa(a[i]); 13 | } 14 | return b; 15 | } 16 | 17 | function convertCoordinate(feature) { 18 | return { 19 | type: "Feature", 20 | geometry: { 21 | type: "Polygon", 22 | fillRule: feature.geometry.coordinates.length > 1 ? "evenOdd" : "nonZero", 23 | coordinates: flip(feature.geometry.coordinates) 24 | }, 25 | properties: feature.properties 26 | }; 27 | } 28 | 29 | export default convertCoordinate; 30 | -------------------------------------------------------------------------------- /src/utils/decoder.js: -------------------------------------------------------------------------------- 1 | var codingCoefficient = 1 / 1000000, 2 | fraction = 2, 3 | dividor = 1 / 0xffff; // target resolution 65k, real 4k 4 | 5 | /** 6 | * coordinateDecode 7 | * partof Yandex.Maps.API 8 | */ 9 | function decodeByteVector(x, N) { 10 | var point = 0; 11 | for (var i = 0; i < N; ++i) { 12 | point |= x.charCodeAt(i) << (i * 8); 13 | } 14 | return point; 15 | } 16 | 17 | function clampx(x) { 18 | return Math.min(180, Math.max(-180, x)); 19 | } 20 | 21 | function clampy(y) { 22 | return Math.min(85, Math.max(-85, y)); 23 | } 24 | 25 | function fromBase64(input) { 26 | input = input.replace(/_/g, "/").replace(/-/g, "+"); 27 | if (typeof atob !== "undefined") { 28 | return atob(input); 29 | } else { 30 | // hide from webpack 31 | const B = eval("Buffer"); 32 | return new B(input, "base64").toString("binary"); 33 | } 34 | } 35 | 36 | function decodeLineBlock(encodedCoordinates) { 37 | var byteVector = fromBase64(encodedCoordinates), 38 | byteVectorLength = byteVector.length, 39 | bounds = [ 40 | [ 41 | decodeByteVector(byteVector.substr(0, 4), 4) * codingCoefficient, 42 | decodeByteVector(byteVector.substr(4, 4), 4) * codingCoefficient 43 | ], 44 | [ 45 | decodeByteVector(byteVector.substr(8, 4), 4) * codingCoefficient, 46 | decodeByteVector(byteVector.substr(12, 4), 4) * codingCoefficient 47 | ] 48 | ], 49 | dimension = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]], 50 | result = [], 51 | index = 16, 52 | fx = dimension[0] * dividor, 53 | fy = dimension[1] * dividor; 54 | 55 | function read() { 56 | var ret = decodeByteVector(byteVector.substr(index, fraction), fraction); 57 | index += fraction; 58 | return ret; 59 | } 60 | 61 | while (index < byteVectorLength) { 62 | var position = [ 63 | clampy(read() * fx + bounds[0][0]), 64 | clampx(read() * fy + bounds[0][1]) 65 | ]; 66 | result.push([position[1], position[0]]); 67 | } 68 | return result; 69 | } 70 | 71 | function decodeWay(lineBlock, wayId, osmeData) { 72 | if (osmeData.wayCache[wayId]) { 73 | return osmeData.wayCache[wayId]; 74 | } 75 | return (osmeData.wayCache[wayId] = decodeLineBlock(lineBlock)); 76 | } 77 | 78 | export default decodeWay; 79 | -------------------------------------------------------------------------------- /src/utils/geometryDecode.js: -------------------------------------------------------------------------------- 1 | import decodeWay from "./decoder"; 2 | 3 | function EQ(first, second, diff) { 4 | diff = diff || 1e-9; 5 | var dx = Math.abs(second[0] - first[0]), 6 | dy = Math.abs(second[1] - first[1]); 7 | return dx < diff && dy < diff; 8 | } 9 | 10 | function fixDegenerate(way, path) { 11 | var offset = 0, 12 | l = way.length, 13 | lp = path.length, 14 | limit = Math.min(l, lp), 15 | delta = 10 / 0xffff; //10 HOPS 16 | lp--; 17 | if (lp < 1) { 18 | return 0; 19 | } 20 | 21 | for (var i = 0; i < limit; ++i) { 22 | if (EQ(way[i], path[lp - i], delta)) { 23 | offset++; 24 | } else { 25 | break; 26 | } 27 | } 28 | 29 | return offset; 30 | } 31 | 32 | function getGeometry(regionId, osmeData, options) { 33 | var coordinates = [], 34 | fixedPoints = [], 35 | meta = [], 36 | paths = regionId.length ? regionId : osmeData.paths[regionId], 37 | //segments = [], 38 | osmeWays = osmeData.ways; 39 | 40 | options = options || {}; 41 | 42 | osmeData.wayCache = osmeData.wayCache || {}; 43 | 44 | if (!paths) { 45 | return false; 46 | } 47 | for ( 48 | var pathId = 0, pathLength = paths.length; 49 | pathId < pathLength; 50 | ++pathId 51 | ) { 52 | var path = paths[pathId]; 53 | var pathCoordinates = [], 54 | ways = [], 55 | segmentFixedPoints = [0]; 56 | if (typeof path == "number") { 57 | path = [path]; 58 | } 59 | for (var i = 0, l = path.length; i < l; ++i) { 60 | var wayId = Math.abs(path[i]); 61 | var way = decodeWay(osmeWays[wayId], wayId, osmeData); 62 | if (path[i] < 0) { 63 | way = way.slice(0); 64 | way.reverse(); 65 | } 66 | if (options.fixDegenerate) { 67 | var offset = fixDegenerate(way, pathCoordinates); 68 | if (offset) { 69 | way = way.slice(offset); 70 | } 71 | if (i == l - 1) { 72 | var tw = way.slice(0); 73 | tw.reverse(); 74 | offset = fixDegenerate(pathCoordinates, way); 75 | if (offset) { 76 | offset--; 77 | way.length = way.length - offset; 78 | pathCoordinates = pathCoordinates.slice(offset); 79 | } 80 | } 81 | } else { 82 | // edges have same coordinates 83 | if (pathCoordinates.length) { 84 | pathCoordinates.length = pathCoordinates.length - 1; 85 | } 86 | } 87 | 88 | pathCoordinates.push.apply(pathCoordinates, way); 89 | segmentFixedPoints.push(pathCoordinates.length - 1); 90 | ways.push(wayId); 91 | } 92 | pathCoordinates.push(pathCoordinates[0]); 93 | coordinates.push(pathCoordinates); 94 | fixedPoints.push(segmentFixedPoints); 95 | meta.push(ways); 96 | } 97 | 98 | return { 99 | type: "Polygon", 100 | fillRule: "nonZero", 101 | coordinates: coordinates, 102 | path: paths, 103 | fixedPoints: fixedPoints 104 | }; 105 | } 106 | 107 | function getFixedGeometry(regionId, osmeData) { 108 | return getGeometry(regionId, osmeData, { fixDegenerate: true }); 109 | } 110 | 111 | export { getGeometry, getFixedGeometry }; 112 | -------------------------------------------------------------------------------- /src/utils/load_native.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Vanilla Ajax data transfer 3 | * @param {String} path 4 | * @param {Function} callback 5 | * @param {Function} errorCallback 6 | */ 7 | function load(path, callback, errorCallback) { 8 | try { 9 | var xhr = new XMLHttpRequest(); 10 | xhr.open("GET", path, true); 11 | xhr.onreadystatechange = function() { 12 | if (xhr.readyState === 4) { 13 | if (xhr.status === 200 || xhr.status === 304) { 14 | try { 15 | var response = JSON.parse(xhr.responseText); 16 | callback(response); 17 | } catch (e) { 18 | errorCallback(e); 19 | } 20 | } else { 21 | errorCallback(xhr); 22 | } 23 | } 24 | }; 25 | xhr.setRequestHeader("Content-Type", "application/json"); 26 | xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 27 | xhr.send(); 28 | } catch (e) { 29 | errorCallback(e); 30 | } 31 | } 32 | 33 | export default load; 34 | -------------------------------------------------------------------------------- /src/utils/nextTick.js: -------------------------------------------------------------------------------- 1 | function nextTick(callback, args) { 2 | Promise.resolve().then(() => callback.apply(this, args)); 3 | } 4 | 5 | export default nextTick; 6 | -------------------------------------------------------------------------------- /src/utils/recombine.js: -------------------------------------------------------------------------------- 1 | import wrapRegion from "./region"; 2 | import { getFixedGeometry } from "./geometryDecode"; 3 | /** 4 | * recombination 5 | * @param regionsData 6 | * @param query 7 | * @returns {*} 8 | */ 9 | function recombineRegion(regionsData, query) { 10 | var regions = regionsData.regions, 11 | inpaths = regionsData.paths, 12 | passRegions = {}, 13 | paths = [], 14 | way; 15 | 16 | function filterPath(path) { 17 | var result = []; 18 | for (var i = 0, l = path.length; i < l; ++i) { 19 | if (1 || path[i].length > 1) { 20 | result.push([path[i]]); 21 | } 22 | } 23 | return result; 24 | } 25 | 26 | //fill regions and way counter 27 | for (var ri in regions) { 28 | if (regions.hasOwnProperty(ri)) { 29 | var tpaths = inpaths[ri]; 30 | var qf = query.filter(wrapRegion(ri, regionsData)); 31 | if (qf) { 32 | if (qf !== true) { 33 | if (qf.path) { 34 | tpaths = qf.path; 35 | } 36 | } 37 | if (tpaths && tpaths.length) { 38 | tpaths = filterPath(tpaths); 39 | if (tpaths.length) { 40 | passRegions[ri] = ri; 41 | paths.push.apply(paths, tpaths); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | function joinPaths(patha, pathb) { 49 | var usedWays = {}, 50 | wayDirection = {}, 51 | wayLookup = {}; 52 | 53 | var apaths = [patha, pathb]; 54 | for (let ri = 0; ri < 2; ++ri) { 55 | const tpaths = apaths[ri]; 56 | for ( 57 | let pathId = 0, pathLength = tpaths.length; 58 | pathId < pathLength; 59 | ++pathId 60 | ) { 61 | let path = tpaths[pathId]; 62 | if (typeof path == "number") { 63 | path = [path]; 64 | } 65 | for (var i = 0, l = path.length; i < l; ++i) { 66 | const wayId = Math.abs(path[i]); 67 | usedWays[wayId] = (usedWays[wayId] || 0) + 1; 68 | } 69 | } 70 | } 71 | 72 | var //pass = 0, 73 | lost = 0; 74 | for (let ri = 0; ri < 2; ++ri) { 75 | const tpaths = apaths[ri]; 76 | for ( 77 | let pathId = 0, pathLength = tpaths.length; 78 | pathId < pathLength; 79 | ++pathId 80 | ) { 81 | let path = tpaths[pathId]; 82 | if (typeof path == "number") { 83 | path = [path]; 84 | } 85 | 86 | for (let i = 0, l = path.length; i < l; ++i) { 87 | var wayId = Math.abs(path[i]); 88 | if (usedWays[wayId] === 1) { 89 | //pass++; 90 | var lw = +path[(i - 1 + l) % l], 91 | rw = +path[(i + 1 + l) % l]; 92 | wayLookup[lw] = wayLookup[lw] || []; 93 | wayLookup[lw].push(path[i]); 94 | wayDirection[path[i]] = [+lw, +path[i], +rw, ri, pathId]; 95 | } else { 96 | lost++; 97 | } 98 | } 99 | } 100 | } 101 | if (!lost) { 102 | return false; 103 | } 104 | 105 | function getWay() { 106 | for (var i in wayDirection) { 107 | if (testWay(i)) { 108 | return +i; 109 | } 110 | } 111 | return false; 112 | } 113 | 114 | function testWay(i) { 115 | return i && wayDirection.hasOwnProperty(i) && wayDirection[i][1]; 116 | } 117 | 118 | // function reverse () { 119 | // rpath.reverse(); 120 | // for (var i = 0, l = rpath.length; i < l; ++i) { 121 | // rpath[i] *= -1; 122 | // } 123 | // ord *= -1; 124 | // return rpath; 125 | // } 126 | 127 | var rpaths = [], 128 | rpath = [], 129 | ord = 1; 130 | 131 | function tryJoinWay(rpath, way) { 132 | if (!wayDirection[way]) { 133 | return false; 134 | } 135 | var lw = ord == -1 ? wayDirection[way][0] : 0, 136 | rw = ord == +1 ? wayDirection[way][2] : 0; 137 | if (testWay(rw)) { 138 | way = rw; 139 | rpath.push(+way * ord); 140 | } else if (testWay(lw)) { 141 | way = lw; 142 | rpath.push(+way); 143 | } else { 144 | // indirect 145 | var rwset = wayLookup[-wayDirection[way][2]]; 146 | way = 0; 147 | for (var j in rwset) { 148 | rw = rwset[j]; 149 | if (testWay(rw)) { 150 | way = rw; 151 | rpath.push(+way); 152 | break; 153 | } 154 | } 155 | if (!way) { 156 | return false; 157 | } 158 | } 159 | return way; 160 | } 161 | 162 | while (false !== (way = getWay())) { 163 | rpath = []; 164 | ord = 1; 165 | rpath.push(+way); 166 | while (way) { 167 | wayDirection[way][1] = 0; 168 | var newWay = tryJoinWay(rpath, way); 169 | if (!newWay) { 170 | break; 171 | } 172 | way = newWay; 173 | } 174 | rpaths.push(rpath); 175 | } 176 | return rpaths; 177 | } 178 | 179 | paths.sort(function(a, b) { 180 | return Math.abs(a[0][0]) < Math.abs(b[0][0]); 181 | }); 182 | 183 | var rpath = paths[0], 184 | skip = { 0: 1 }, 185 | skipCnt = 1, 186 | rpaths = [], 187 | l = paths.length, 188 | freePass = 0, 189 | joinPass = 0, 190 | ccx = 0; 191 | 192 | while (skipCnt < l) { 193 | joinPass = 0; 194 | for (let i = 1, l = paths.length; i < l; ++i) { 195 | var rid = i % l; 196 | if (!(rid in skip)) { 197 | var result = joinPaths(rpath, paths[rid]); 198 | if (result && result.length == 1) { 199 | rpath = result; 200 | skip[rid] = 1; 201 | skipCnt++; 202 | joinPass++; 203 | } else { 204 | freePass = rid; 205 | } 206 | } 207 | } 208 | if (!joinPass) { 209 | if (freePass) { 210 | rpaths.push(rpath[0]); 211 | rpath = paths[freePass]; 212 | skip[freePass] = 1; 213 | skipCnt++; 214 | } else { 215 | break; 216 | } 217 | } 218 | if (ccx++ > 1000) { 219 | break; 220 | } 221 | } 222 | 223 | if (rpath) { 224 | rpaths.push(rpath[0]); 225 | } 226 | 227 | return getFixedGeometry(rpaths, regionsData); 228 | } 229 | 230 | export default recombineRegion; 231 | -------------------------------------------------------------------------------- /src/utils/region.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name RegionObject 3 | * @class 4 | */ 5 | class RegionObject { 6 | constructor(rid, meta, prop, data) { 7 | /** @member {Number} */ 8 | this.osmId = rid; 9 | /** @member {Number} */ 10 | this.geoNamesId = prop.geoNamesId; 11 | /** @member {String} */ 12 | this.iso = prop.iso3166; 13 | /** @member {Number} */ 14 | this.level = meta.level; 15 | /** @member {Object} */ 16 | this.properties = prop; 17 | 18 | this._meta = meta; 19 | this._data = data; 20 | } 21 | 22 | getBorderWith(id) { 23 | var wset = {}, 24 | i, 25 | l1, 26 | j, 27 | l2, 28 | path1 = this._data.paths[id], 29 | path2 = this._data.paths[this.osmId]; 30 | for (i = 0, l1 = path1.length; i < l1; ++i) { 31 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 32 | wset[Math.abs(path1[i][j])] = 1; 33 | } 34 | } 35 | var result = []; 36 | for (i = 0, l1 = path2.length; i < l1; ++i) { 37 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 38 | if (wset[Math.abs(path2[i][j])]) { 39 | // path is full in 40 | result.push(path2[i]); 41 | } 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | hasBorderWith(id) { 48 | var wset = {}, 49 | i, 50 | l1, 51 | j, 52 | l2, 53 | path1 = this._data.paths[this.osmId], 54 | path2 = this._data.paths[id]; 55 | if (!path1 || !path2) { 56 | return false; 57 | } 58 | for (i = 0, l1 = path1.length; i < l1; ++i) { 59 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 60 | wset[Math.abs(path1[i][j])] = 1; 61 | } 62 | } 63 | for (i = 0, l1 = path2.length; i < l1; ++i) { 64 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 65 | if (wset[Math.abs(path2[i][j])]) { 66 | return true; 67 | } 68 | } 69 | } 70 | return false; 71 | } 72 | 73 | hasParent(id) { 74 | var parents = this._meta.parents; 75 | for (var i = 0, l = parents.length; i < l; ++i) { 76 | if (parents[i].id == id) { 77 | return true; 78 | } 79 | } 80 | return false; 81 | } 82 | } 83 | 84 | /** 85 | * wraps region for filter functions 86 | * @param rid 87 | * @param data 88 | * @returns {RegionObject} 89 | */ 90 | function wrapRegion(rid, data) { 91 | var meta = data.regions[rid], 92 | prop = meta.property || {}; 93 | return new RegionObject(rid, meta, prop, data); 94 | } 95 | 96 | export default wrapRegion; 97 | -------------------------------------------------------------------------------- /src/utils/setupGeometry.js: -------------------------------------------------------------------------------- 1 | import wrapRegion from "./region"; 2 | import recombineRegion from "./recombine"; 3 | import { getGeometry } from "./geometryDecode"; 4 | 5 | /** 6 | * main decode function 7 | * @param regionsData 8 | * @param options 9 | * @returns {Array} 10 | */ 11 | function setupGeometry(regionsData, options) { 12 | options = options || {}; 13 | var regions = regionsData.regions, 14 | dataset = [], 15 | postFilter = 16 | options.postFilter || 17 | (regionsData.meta && regionsData.meta.postFilter 18 | ? new Function("region", regionsData.meta.postFilter) 19 | : 0), 20 | scheme = options.scheme || (regionsData.meta && regionsData.meta.scheme), 21 | disputedBorders = 22 | (regionsData.meta && regionsData.meta.disputedBorders) || {}, 23 | useSetup = options.recombine || options.lang || "en", 24 | disputedBorder = 25 | typeof useSetup == "string" ? disputedBorders[useSetup] : useSetup, 26 | geometry = 0; 27 | 28 | for (const i in disputedBorders) { 29 | var setup = disputedBorders[i]; 30 | for (const j in setup) { 31 | var regionSet = setup[j]; 32 | if (typeof regionSet == "string") { 33 | setup[j] = new Function("region", regionSet); 34 | } 35 | } 36 | } 37 | 38 | for (const i in regions) { 39 | if (regions.hasOwnProperty(i)) { 40 | if (!postFilter || postFilter(wrapRegion(i, regionsData))) { 41 | if (disputedBorder && disputedBorder[+i]) { 42 | geometry = recombineRegion(regionsData, { 43 | filter: disputedBorder[+i] 44 | }); 45 | } else if (scheme && scheme[+i]) { 46 | var sch = scheme[+i]; 47 | geometry = recombineRegion(regionsData, { 48 | filter: typeof sch == "string" ? new Function("region", sch) : sch 49 | }); 50 | } else { 51 | geometry = getGeometry(+i, regionsData); 52 | } 53 | 54 | if (geometry) { 55 | dataset[regions[i].index] = { 56 | type: "Feature", 57 | geometry: geometry, 58 | properties: { 59 | osmId: i, 60 | level: regions[i].level, 61 | properties: regions[i].property || {}, 62 | parents: regions[i].parents, 63 | hintContent: regions[i].name, 64 | name: regions[i].name, 65 | title: regions[i].name, 66 | wikipedia: regions[i].wikipedia, 67 | orderIndex: regions[i].index, 68 | square: regions[i].square 69 | } 70 | }; 71 | } 72 | } 73 | } 74 | } 75 | var result = []; 76 | for (var i = 0, l = dataset.length; i < l; ++i) { 77 | if (dataset[i]) { 78 | result.push(dataset[i]); 79 | } 80 | } 81 | return result; 82 | } 83 | 84 | export default setupGeometry; 85 | -------------------------------------------------------------------------------- /src/utils/shortestPath.js: -------------------------------------------------------------------------------- 1 | function getShortestPath(contour) { 2 | var halfWorld = 180; 3 | var result = [contour[0]], 4 | point = contour[0]; 5 | for (var i = 1, l = contour.length; i < l; ++i) { 6 | var delta = point[0] - contour[i][0]; 7 | if (Math.abs(delta) > halfWorld) { 8 | delta = delta < 0 ? -360 : 360; 9 | } else { 10 | delta = 0; 11 | } 12 | 13 | var nextPoint = [contour[i][0] + delta, contour[i][1]]; 14 | result.push(nextPoint); 15 | point = nextPoint; 16 | } 17 | return result; 18 | } 19 | 20 | export const getShortestContour = contour => { 21 | return contour.map(path => getShortestPath(path)); 22 | }; 23 | 24 | export default getShortestPath; 25 | -------------------------------------------------------------------------------- /tests/geocode.spec.js: -------------------------------------------------------------------------------- 1 | import osme from '../src/index'; 2 | import {expect} from 'chai'; 3 | 4 | describe("geocode", () => { 5 | 6 | const BERLIN = [52.5076678, 13.2857205]; 7 | const MOSCOW = [55.7498582, 37.3516355]; 8 | const AUSTRALIA = [-24.9868075, 115.1814363]; 9 | 10 | it('should find Berlin', () => 11 | osme.geocode(BERLIN).then(data => { 12 | expect(data.target.iso[0]).to.be.equal('DE'); 13 | expect(data.names[data.target.l2].name).to.be.equal('Germany'); 14 | expect(data.names[data.target.l2].lng).to.be.equal('en'); 15 | }) 16 | ).timeout(5000); 17 | 18 | it('should find Moscow', () => 19 | osme.geocode(MOSCOW).then(data => { 20 | expect(data.target.iso).to.be.deep.equal(['RU', 'MOS']); 21 | expect(data.names[data.target.l4].name).to.be.equal('Moscow Oblast'); 22 | expect(data.names[data.target.l2].lng).to.be.equal('en'); 23 | }) 24 | ); 25 | 26 | it('should find Moscow in ru', () => 27 | osme.geocode(MOSCOW, { 28 | lang: 'ru' 29 | }).then(data => { 30 | expect(data.target.iso).to.be.deep.equal(['RU', 'MOS']); 31 | expect(data.names[data.target.l2].name).to.be.equal('Россия'); 32 | expect(data.names[data.target.l2].lng).to.be.equal('ru'); 33 | }) 34 | ); 35 | 36 | it('should find Australia', () => 37 | osme.geocode(AUSTRALIA).then(data => { 38 | expect(data.target.iso[0]).to.be.equal('AU'); 39 | expect(data.names[data.target.l2].name).to.be.equal('Australia'); 40 | expect(data.names[data.target.l2].lng).to.be.equal('en'); 41 | }) 42 | ); 43 | }); -------------------------------------------------------------------------------- /tests/regions.spec.js: -------------------------------------------------------------------------------- 1 | import osme from '../src/index'; 2 | import {expect} from 'chai'; 3 | 4 | describe("Regions", () => { 5 | describe("fetching", () => { 6 | it('should call load callback', (done) => { 7 | osme.geoJSON("AU-NT", {}, (data) => { 8 | expect(data.metaData.name).to.be.equal('AU-NT'); 9 | done(); 10 | }); 11 | }); 12 | 13 | it('should call load callback', (done) => { 14 | osme.geoJSON("AU-NT", {quality: -1}, (data) => { 15 | expect(data.metaData.name).to.be.equal('AU-NT'); 16 | done(); 17 | }); 18 | }); 19 | 20 | it('should return a promise', () => { 21 | return osme.geoJSON("AU-NT").then(data => { 22 | expect(data.metaData.name).to.be.equal('AU-NT'); 23 | return true; 24 | }).catch(() => { 25 | expect("must not be called").to.equal(true) 26 | }); 27 | }); 28 | }); 29 | 30 | describe("error fetch", () => { 31 | it('should call error callback', (done) => { 32 | osme.geoJSON("world", { 33 | host: "unexistsing-in-a-world-host.test" 34 | }, ()=> { 35 | expect("must not be called").to.equal(true); 36 | done(); 37 | }, ()=> { 38 | done(); 39 | }).catch(()=>{}); 40 | }); 41 | 42 | it('should return a promise', () => { 43 | return osme.geoJSON("undefined-keywork").then(() => { 44 | expect("must not be called").to.equal(true); 45 | }, () => { 46 | return true; 47 | }); 48 | }); 49 | }); 50 | }); -------------------------------------------------------------------------------- /umd/index.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.osme = f()}})(function(){var define,module,exports;return (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} eventName 259 | * @param {Function} callback 260 | * @param {Object} [ctx] 261 | */ 262 | addEvent: function addEvent(eventName, callback, ctx) { 263 | collection.events.add(eventName, function (event) { 264 | var target = event.get("target"); 265 | callback.call(ctx, idTable[target.properties.get("osmId")], [eventName, "yandex"], target, event); 266 | }); 267 | }, 268 | removeEvent: function removeEvent(event) { 269 | collection.events.remove(event); 270 | } 271 | }; 272 | } 273 | 274 | exports.default = toYandex; 275 | },{"../settings":8,"../utils/buildIdTable":9,"../utils/convertCoordinate":10}],6:[function(require,module,exports){ 276 | "use strict"; 277 | 278 | Object.defineProperty(exports, "__esModule", { 279 | value: true 280 | }); 281 | 282 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 283 | 284 | var _settings = require("./settings"); 285 | 286 | var _settings2 = _interopRequireDefault(_settings); 287 | 288 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 289 | 290 | /** 291 | * Reverse geocode 292 | * @param {Numbrer[]} point - Point. 293 | * @param {Object} [options] 294 | * @param {Number} [options.seq] - Sequence number. 295 | * @param {String} [options.lang] - Language. 296 | * @param {Function} [callback] 297 | * @param {Function} [errorCallback] 298 | * @return {Promise} 299 | */ 300 | function geocode(point, options, _callback, _errorCallback) { 301 | var promise = void 0; 302 | var cb_resolve = void 0, 303 | cb_reject = void 0; 304 | 305 | var addr = _settings2.default.GEOCODEHOST; 306 | addr += "?point=" + +point[0] + "," + +point[1]; 307 | 308 | if (typeof options == "function") { 309 | _errorCallback = _callback; 310 | _callback = options; 311 | options = {}; 312 | } 313 | 314 | options = _extends({ 315 | lang: "en", 316 | seq: 0 317 | }, options || {}); 318 | 319 | if (options.seq) { 320 | addr += "&seq=" + +options.seq; 321 | } 322 | if (options.lang) { 323 | addr += "&lng=" + options.lang; 324 | } 325 | 326 | if (typeof Promise != "undefined") { 327 | promise = new Promise(function (resolve, reject) { 328 | cb_resolve = resolve; 329 | cb_reject = reject; 330 | }); 331 | } else { 332 | cb_resolve = cb_reject = function cb_reject() {}; 333 | } 334 | 335 | var callback = function callback(geojson) { 336 | cb_resolve(geojson); 337 | _callback && _callback(geojson); 338 | }; 339 | 340 | var errorCallback = function errorCallback(geojson) { 341 | cb_reject(geojson); 342 | _errorCallback && _errorCallback(geojson); 343 | }; 344 | 345 | _settings2.default.load(addr, function (json) { 346 | return callback(json); 347 | }, function (err) { 348 | return errorCallback(err); 349 | }); 350 | 351 | return promise; 352 | } 353 | 354 | exports.default = geocode; 355 | },{"./settings":8}],7:[function(require,module,exports){ 356 | "use strict"; 357 | 358 | Object.defineProperty(exports, "__esModule", { 359 | value: true 360 | }); 361 | 362 | var _settings = require("./settings"); 363 | 364 | var _settings2 = _interopRequireDefault(_settings); 365 | 366 | var _nextTick = require("./utils/nextTick"); 367 | 368 | var _nextTick2 = _interopRequireDefault(_nextTick); 369 | 370 | var _recombine = require("./utils/recombine"); 371 | 372 | var _recombine2 = _interopRequireDefault(_recombine); 373 | 374 | var _setupGeometry = require("./utils/setupGeometry"); 375 | 376 | var _setupGeometry2 = _interopRequireDefault(_setupGeometry); 377 | 378 | var _geocode = require("./geocode"); 379 | 380 | var _geocode2 = _interopRequireDefault(_geocode); 381 | 382 | var _google = require("./collections/google"); 383 | 384 | var _google2 = _interopRequireDefault(_google); 385 | 386 | var _yandex = require("./collections/yandex"); 387 | 388 | var _yandex2 = _interopRequireDefault(_yandex); 389 | 390 | var _leaflet = require("./collections/leaflet"); 391 | 392 | var _leaflet2 = _interopRequireDefault(_leaflet); 393 | 394 | var _unbounded = require("./collections/unbounded"); 395 | 396 | var _unbounded2 = _interopRequireDefault(_unbounded); 397 | 398 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 399 | 400 | var assertData = function assertData(errorCallback, data) { 401 | if (!data || data.error) { 402 | errorCallback("wrong data", data.error); 403 | } 404 | return data; 405 | }; 406 | 407 | /** 408 | * @name osmeRegions 409 | * @type Object 410 | */ 411 | /*! 412 | * OSMeRegions JavaScript Library 413 | * http://data.esosedi.org/regions/ 414 | * https://github.com/esosedi/regions 415 | * 416 | * @author Anton Korzunov 417 | * Released under the MIT license 418 | */ 419 | 420 | var osmeRegions = /** @lends osmeRegions */{ 421 | /** 422 | * override data host 423 | * @param host 424 | */ 425 | setHost: function setHost(host) { 426 | _settings2.default.HOST = host; 427 | }, 428 | 429 | /** 430 | * @param {Boolean} debug 431 | */ 432 | setDebug: function setDebug(debug) { 433 | _settings2.default.DEBUG = Boolean(debug); 434 | }, 435 | 436 | /** 437 | * allow recombination 438 | * @param regionsData 439 | * @param {Object} query 440 | * @param {Function} query.filter 441 | * @function 442 | */ 443 | recombine: _recombine2.default, 444 | 445 | /** 446 | * Loads GeoJSON from default host 447 | * @param {String} region OSMRelationId,ISO3166-2 code or world's region name(Asia, Europe etc) or absolute URL. 448 | * @param {Object} options 449 | * @param {String} [options.lang='en'] Language (en,de,ru). 450 | * @param {Number} [options.quality=0] Quality. 0 for fullHD resolution. -1,0,+1,+2 for /4, x1, x4, x16 quality. 451 | * @param {String} [options.type=''] Type of data. Can be empty or 'coast' (unstable mode). 452 | * @param {Boolean} [options.nocache] Turns off internal cache. 453 | * @param {Function} [options.postFilter] filtering function. 454 | * @param {String|Object} [options.recombine] recombination function. 455 | * @param {Object} [options.scheme] another recombination function. 456 | * @param {Function} [callback] 457 | * @param {Function} [errorCallback] 458 | * @return {Promise} 459 | */ 460 | geoJSON: function geoJSON(region, options, _callback, _errorCallback) { 461 | var _this = this; 462 | 463 | var promise = void 0; 464 | var cb_resolve = void 0, 465 | cb_reject = void 0; 466 | options = options || {}; 467 | 468 | if (typeof options === "function") { 469 | throw new Error("callback must be at third place"); 470 | } 471 | 472 | var lang = options.lang || "en"; 473 | var addr = typeof region === "string" ? lang + "_" + region : null; 474 | 475 | if (typeof Promise !== "undefined") { 476 | promise = new Promise(function (resolve, reject) { 477 | cb_resolve = resolve; 478 | cb_reject = reject; 479 | }); 480 | } else { 481 | cb_resolve = cb_reject = function cb_reject() {}; 482 | } 483 | var callback = function callback(geojson, data) { 484 | if (addr) { 485 | _settings2.default.cache[addr] = data; 486 | } 487 | cb_resolve(geojson, data); 488 | _callback && _callback(geojson, data); 489 | }; 490 | 491 | var errorCallback = function errorCallback(geojson) { 492 | cb_reject(geojson); 493 | _errorCallback && _errorCallback(geojson); 494 | }; 495 | 496 | if (addr) { 497 | if ((region + "").indexOf("http") === 0) { 498 | addr = region; 499 | } else { 500 | addr = (options.host || _settings2.default.HOST) + "?lang=" + addr; 501 | if (options.quality) { 502 | addr += "&q=" + (options.quality + 1); 503 | } 504 | if (options.type) { 505 | addr += "&type=" + options.type; 506 | } 507 | } 508 | 509 | if (!_settings2.default.cache[addr] || options.nocache) { 510 | this.loadData(addr, function (data) { 511 | (0, _nextTick2.default)(callback, [assertData(errorCallback, _this.parseData(data, options)), data]); 512 | }, errorCallback); 513 | } else { 514 | var data = _settings2.default.cache[addr]; 515 | (0, _nextTick2.default)(callback, [assertData(errorCallback, this.parseData(data, options)), data]); 516 | } 517 | } else { 518 | (0, _nextTick2.default)(callback, [assertData(errorCallback, this.parseData(region, options)), region]); 519 | } 520 | 521 | return promise; 522 | }, 523 | 524 | /** 525 | * overloadable data transfer function 526 | */ 527 | loadData: function loadData(path, callback, errorCallback) { 528 | return _settings2.default.load(path, callback, errorCallback); 529 | }, 530 | 531 | /** 532 | * parse default data format 533 | * @param {String} data 534 | * @returns {geoJSON} 535 | */ 536 | parseData: function parseData(data, options) { 537 | if (!data.meta) { 538 | return { 539 | error: data.error 540 | }; 541 | } 542 | return { 543 | type: "FeatureCollection", 544 | features: (0, _setupGeometry2.default)(data, options), 545 | metaData: data.meta 546 | }; 547 | }, 548 | 549 | /** 550 | * drops internal cache 551 | */ 552 | dropCache: function dropCache() { 553 | _settings2.default.cache = {}; 554 | }, 555 | 556 | _setCoordOrder: function _setCoordOrder(order) { 557 | _settings2.default.latLongOrder = order == "latlong"; 558 | }, 559 | 560 | /** 561 | * convert geoJSON to YMAPS collection 562 | * @param geoJson 563 | * @param [ym21] - Maps API namespace 564 | * @returns {osmeMapCollection} 565 | */ 566 | toYandex: _yandex2.default, 567 | 568 | /** 569 | * converts GeoJSON to Google.data object 570 | * @param geoJson 571 | * @param maps 572 | * @returns {osmeMapCollection} 573 | */ 574 | toGoogle: _google2.default, 575 | 576 | /** 577 | * converts GeoJSON to Leaflet object 578 | * @param geoJson 579 | * @param L 580 | * @returns {osmeMapCollection} 581 | */ 582 | toLeaflet: _leaflet2.default, 583 | 584 | /** 585 | * converts GeoJSON to GeoJSON with "unbounded" coordinates 586 | * @param geoJson 587 | * @returns {geoJson} 588 | */ 589 | toUnboundedGeoJSON: _unbounded2.default, 590 | 591 | /** 592 | * Reverse geocode 593 | * @param {Number[]} point - Point. 594 | * @param {Object} [options] 595 | * @param {Number} [options.seq] - Sequence number. 596 | * @param {String} [options.lang] - Language. 597 | * @param {Function} callback 598 | * @param {Function} [errorcallback] 599 | */ 600 | geocode: _geocode2.default 601 | }; 602 | 603 | exports.default = osmeRegions; 604 | },{"./collections/google":2,"./collections/leaflet":3,"./collections/unbounded":4,"./collections/yandex":5,"./geocode":6,"./settings":8,"./utils/nextTick":14,"./utils/recombine":15,"./utils/setupGeometry":17}],8:[function(require,module,exports){ 605 | "use strict"; 606 | 607 | Object.defineProperty(exports, "__esModule", { 608 | value: true 609 | }); 610 | 611 | var _load_native = require("./utils/load_native"); 612 | 613 | var _load_native2 = _interopRequireDefault(_load_native); 614 | 615 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 616 | 617 | var settings = { 618 | HOST: typeof window !== "undefined" && window.location.protocol === "https:" ? "https://osme.geolocated.org/regions/v1/" : "http://data.esosedi.org/regions/v1/", 619 | GEOCODEHOST: "http://data.esosedi.org/geocode/v1", 620 | DEBUG: false, 621 | cache: {}, 622 | 623 | latLongOrder: 0, 624 | 625 | load: _load_native2.default 626 | }; 627 | 628 | exports.default = settings; 629 | },{"./utils/load_native":13}],9:[function(require,module,exports){ 630 | "use strict"; 631 | 632 | Object.defineProperty(exports, "__esModule", { 633 | value: true 634 | }); 635 | function buildIdTable(geoJson) { 636 | var ret = {}, 637 | features = geoJson.features; 638 | for (var i = 0, l = features.length; i < l; ++i) { 639 | var feature = features[i]; 640 | if (feature && feature.properties) { 641 | ret[feature.properties.osmId] = feature; 642 | } 643 | } 644 | 645 | return ret; 646 | } 647 | 648 | exports.default = buildIdTable; 649 | },{}],10:[function(require,module,exports){ 650 | "use strict"; 651 | 652 | Object.defineProperty(exports, "__esModule", { 653 | value: true 654 | }); 655 | function flipa(a) { 656 | var b = []; 657 | for (var i = 0, l = a.length; i < l; ++i) { 658 | b[i] = [a[i][1], a[i][0]]; 659 | } 660 | return b; 661 | } 662 | 663 | function flip(a) { 664 | var b = []; 665 | for (var i = 0, l = a.length; i < l; ++i) { 666 | b[i] = flipa(a[i]); 667 | } 668 | return b; 669 | } 670 | 671 | function convertCoordinate(feature) { 672 | return { 673 | type: "Feature", 674 | geometry: { 675 | type: "Polygon", 676 | fillRule: feature.geometry.coordinates.length > 1 ? "evenOdd" : "nonZero", 677 | coordinates: flip(feature.geometry.coordinates) 678 | }, 679 | properties: feature.properties 680 | }; 681 | } 682 | 683 | exports.default = convertCoordinate; 684 | },{}],11:[function(require,module,exports){ 685 | "use strict"; 686 | 687 | Object.defineProperty(exports, "__esModule", { 688 | value: true 689 | }); 690 | var codingCoefficient = 1 / 1000000, 691 | fraction = 2, 692 | dividor = 1 / 0xffff; // target resolution 65k, real 4k 693 | 694 | /** 695 | * coordinateDecode 696 | * partof Yandex.Maps.API 697 | */ 698 | function decodeByteVector(x, N) { 699 | var point = 0; 700 | for (var i = 0; i < N; ++i) { 701 | point |= x.charCodeAt(i) << i * 8; 702 | } 703 | return point; 704 | } 705 | 706 | function clampx(x) { 707 | return Math.min(180, Math.max(-180, x)); 708 | } 709 | 710 | function clampy(y) { 711 | return Math.min(85, Math.max(-85, y)); 712 | } 713 | 714 | function fromBase64(input) { 715 | input = input.replace(/_/g, "/").replace(/-/g, "+"); 716 | if (typeof atob !== "undefined") { 717 | return atob(input); 718 | } else { 719 | // hide from webpack 720 | var B = eval("Buffer"); 721 | return new B(input, "base64").toString("binary"); 722 | } 723 | } 724 | 725 | function decodeLineBlock(encodedCoordinates) { 726 | var byteVector = fromBase64(encodedCoordinates), 727 | byteVectorLength = byteVector.length, 728 | bounds = [[decodeByteVector(byteVector.substr(0, 4), 4) * codingCoefficient, decodeByteVector(byteVector.substr(4, 4), 4) * codingCoefficient], [decodeByteVector(byteVector.substr(8, 4), 4) * codingCoefficient, decodeByteVector(byteVector.substr(12, 4), 4) * codingCoefficient]], 729 | dimension = [bounds[1][0] - bounds[0][0], bounds[1][1] - bounds[0][1]], 730 | result = [], 731 | index = 16, 732 | fx = dimension[0] * dividor, 733 | fy = dimension[1] * dividor; 734 | 735 | function read() { 736 | var ret = decodeByteVector(byteVector.substr(index, fraction), fraction); 737 | index += fraction; 738 | return ret; 739 | } 740 | 741 | while (index < byteVectorLength) { 742 | var position = [clampy(read() * fx + bounds[0][0]), clampx(read() * fy + bounds[0][1])]; 743 | result.push([position[1], position[0]]); 744 | } 745 | return result; 746 | } 747 | 748 | function decodeWay(lineBlock, wayId, osmeData) { 749 | if (osmeData.wayCache[wayId]) { 750 | return osmeData.wayCache[wayId]; 751 | } 752 | return osmeData.wayCache[wayId] = decodeLineBlock(lineBlock); 753 | } 754 | 755 | exports.default = decodeWay; 756 | },{}],12:[function(require,module,exports){ 757 | "use strict"; 758 | 759 | Object.defineProperty(exports, "__esModule", { 760 | value: true 761 | }); 762 | exports.getFixedGeometry = exports.getGeometry = undefined; 763 | 764 | var _decoder = require("./decoder"); 765 | 766 | var _decoder2 = _interopRequireDefault(_decoder); 767 | 768 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 769 | 770 | function EQ(first, second, diff) { 771 | diff = diff || 1e-9; 772 | var dx = Math.abs(second[0] - first[0]), 773 | dy = Math.abs(second[1] - first[1]); 774 | return dx < diff && dy < diff; 775 | } 776 | 777 | function fixDegenerate(way, path) { 778 | var offset = 0, 779 | l = way.length, 780 | lp = path.length, 781 | limit = Math.min(l, lp), 782 | delta = 10 / 0xffff; //10 HOPS 783 | lp--; 784 | if (lp < 1) { 785 | return 0; 786 | } 787 | 788 | for (var i = 0; i < limit; ++i) { 789 | if (EQ(way[i], path[lp - i], delta)) { 790 | offset++; 791 | } else { 792 | break; 793 | } 794 | } 795 | 796 | return offset; 797 | } 798 | 799 | function getGeometry(regionId, osmeData, options) { 800 | var coordinates = [], 801 | fixedPoints = [], 802 | meta = [], 803 | paths = regionId.length ? regionId : osmeData.paths[regionId], 804 | 805 | //segments = [], 806 | osmeWays = osmeData.ways; 807 | 808 | options = options || {}; 809 | 810 | osmeData.wayCache = osmeData.wayCache || {}; 811 | 812 | if (!paths) { 813 | return false; 814 | } 815 | for (var pathId = 0, pathLength = paths.length; pathId < pathLength; ++pathId) { 816 | var path = paths[pathId]; 817 | var pathCoordinates = [], 818 | ways = [], 819 | segmentFixedPoints = [0]; 820 | if (typeof path == "number") { 821 | path = [path]; 822 | } 823 | for (var i = 0, l = path.length; i < l; ++i) { 824 | var wayId = Math.abs(path[i]); 825 | var way = (0, _decoder2.default)(osmeWays[wayId], wayId, osmeData); 826 | if (path[i] < 0) { 827 | way = way.slice(0); 828 | way.reverse(); 829 | } 830 | if (options.fixDegenerate) { 831 | var offset = fixDegenerate(way, pathCoordinates); 832 | if (offset) { 833 | way = way.slice(offset); 834 | } 835 | if (i == l - 1) { 836 | var tw = way.slice(0); 837 | tw.reverse(); 838 | offset = fixDegenerate(pathCoordinates, way); 839 | if (offset) { 840 | offset--; 841 | way.length = way.length - offset; 842 | pathCoordinates = pathCoordinates.slice(offset); 843 | } 844 | } 845 | } else { 846 | // edges have same coordinates 847 | if (pathCoordinates.length) { 848 | pathCoordinates.length = pathCoordinates.length - 1; 849 | } 850 | } 851 | 852 | pathCoordinates.push.apply(pathCoordinates, way); 853 | segmentFixedPoints.push(pathCoordinates.length - 1); 854 | ways.push(wayId); 855 | } 856 | pathCoordinates.push(pathCoordinates[0]); 857 | coordinates.push(pathCoordinates); 858 | fixedPoints.push(segmentFixedPoints); 859 | meta.push(ways); 860 | } 861 | 862 | return { 863 | type: "Polygon", 864 | fillRule: "nonZero", 865 | coordinates: coordinates, 866 | path: paths, 867 | fixedPoints: fixedPoints 868 | }; 869 | } 870 | 871 | function getFixedGeometry(regionId, osmeData) { 872 | return getGeometry(regionId, osmeData, { fixDegenerate: true }); 873 | } 874 | 875 | exports.getGeometry = getGeometry; 876 | exports.getFixedGeometry = getFixedGeometry; 877 | },{"./decoder":11}],13:[function(require,module,exports){ 878 | "use strict"; 879 | 880 | Object.defineProperty(exports, "__esModule", { 881 | value: true 882 | }); 883 | /** 884 | * Vanilla Ajax data transfer 885 | * @param {String} path 886 | * @param {Function} callback 887 | * @param {Function} errorCallback 888 | */ 889 | function load(path, callback, errorCallback) { 890 | try { 891 | var xhr = new XMLHttpRequest(); 892 | xhr.open("GET", path, true); 893 | xhr.onreadystatechange = function () { 894 | if (xhr.readyState === 4) { 895 | if (xhr.status === 200 || xhr.status === 304) { 896 | try { 897 | var response = JSON.parse(xhr.responseText); 898 | callback(response); 899 | } catch (e) { 900 | errorCallback(e); 901 | } 902 | } else { 903 | errorCallback(xhr); 904 | } 905 | } 906 | }; 907 | xhr.setRequestHeader("Content-Type", "application/json"); 908 | xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 909 | xhr.send(); 910 | } catch (e) { 911 | errorCallback(e); 912 | } 913 | } 914 | 915 | exports.default = load; 916 | },{}],14:[function(require,module,exports){ 917 | "use strict"; 918 | 919 | Object.defineProperty(exports, "__esModule", { 920 | value: true 921 | }); 922 | function nextTick(callback, args) { 923 | var _this = this; 924 | 925 | Promise.resolve().then(function () { 926 | return callback.apply(_this, args); 927 | }); 928 | } 929 | 930 | exports.default = nextTick; 931 | },{}],15:[function(require,module,exports){ 932 | "use strict"; 933 | 934 | Object.defineProperty(exports, "__esModule", { 935 | value: true 936 | }); 937 | 938 | var _region = require("./region"); 939 | 940 | var _region2 = _interopRequireDefault(_region); 941 | 942 | var _geometryDecode = require("./geometryDecode"); 943 | 944 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 945 | 946 | /** 947 | * recombination 948 | * @param regionsData 949 | * @param query 950 | * @returns {*} 951 | */ 952 | function recombineRegion(regionsData, query) { 953 | var regions = regionsData.regions, 954 | inpaths = regionsData.paths, 955 | passRegions = {}, 956 | paths = [], 957 | way; 958 | 959 | function filterPath(path) { 960 | var result = []; 961 | for (var i = 0, l = path.length; i < l; ++i) { 962 | if (1 || path[i].length > 1) { 963 | result.push([path[i]]); 964 | } 965 | } 966 | return result; 967 | } 968 | 969 | //fill regions and way counter 970 | for (var ri in regions) { 971 | if (regions.hasOwnProperty(ri)) { 972 | var tpaths = inpaths[ri]; 973 | var qf = query.filter((0, _region2.default)(ri, regionsData)); 974 | if (qf) { 975 | if (qf !== true) { 976 | if (qf.path) { 977 | tpaths = qf.path; 978 | } 979 | } 980 | if (tpaths && tpaths.length) { 981 | tpaths = filterPath(tpaths); 982 | if (tpaths.length) { 983 | passRegions[ri] = ri; 984 | paths.push.apply(paths, tpaths); 985 | } 986 | } 987 | } 988 | } 989 | } 990 | 991 | function joinPaths(patha, pathb) { 992 | var usedWays = {}, 993 | wayDirection = {}, 994 | wayLookup = {}; 995 | 996 | var apaths = [patha, pathb]; 997 | for (var _ri = 0; _ri < 2; ++_ri) { 998 | var _tpaths = apaths[_ri]; 999 | for (var pathId = 0, pathLength = _tpaths.length; pathId < pathLength; ++pathId) { 1000 | var path = _tpaths[pathId]; 1001 | if (typeof path == "number") { 1002 | path = [path]; 1003 | } 1004 | for (var i = 0, l = path.length; i < l; ++i) { 1005 | var _wayId = Math.abs(path[i]); 1006 | usedWays[_wayId] = (usedWays[_wayId] || 0) + 1; 1007 | } 1008 | } 1009 | } 1010 | 1011 | var //pass = 0, 1012 | lost = 0; 1013 | for (var _ri2 = 0; _ri2 < 2; ++_ri2) { 1014 | var _tpaths2 = apaths[_ri2]; 1015 | for (var _pathId = 0, _pathLength = _tpaths2.length; _pathId < _pathLength; ++_pathId) { 1016 | var _path = _tpaths2[_pathId]; 1017 | if (typeof _path == "number") { 1018 | _path = [_path]; 1019 | } 1020 | 1021 | for (var _i = 0, _l = _path.length; _i < _l; ++_i) { 1022 | var wayId = Math.abs(_path[_i]); 1023 | if (usedWays[wayId] === 1) { 1024 | //pass++; 1025 | var lw = +_path[(_i - 1 + _l) % _l], 1026 | rw = +_path[(_i + 1 + _l) % _l]; 1027 | wayLookup[lw] = wayLookup[lw] || []; 1028 | wayLookup[lw].push(_path[_i]); 1029 | wayDirection[_path[_i]] = [+lw, +_path[_i], +rw, _ri2, _pathId]; 1030 | } else { 1031 | lost++; 1032 | } 1033 | } 1034 | } 1035 | } 1036 | if (!lost) { 1037 | return false; 1038 | } 1039 | 1040 | function getWay() { 1041 | for (var i in wayDirection) { 1042 | if (testWay(i)) { 1043 | return +i; 1044 | } 1045 | } 1046 | return false; 1047 | } 1048 | 1049 | function testWay(i) { 1050 | return i && wayDirection.hasOwnProperty(i) && wayDirection[i][1]; 1051 | } 1052 | 1053 | // function reverse () { 1054 | // rpath.reverse(); 1055 | // for (var i = 0, l = rpath.length; i < l; ++i) { 1056 | // rpath[i] *= -1; 1057 | // } 1058 | // ord *= -1; 1059 | // return rpath; 1060 | // } 1061 | 1062 | var rpaths = [], 1063 | rpath = [], 1064 | ord = 1; 1065 | 1066 | function tryJoinWay(rpath, way) { 1067 | if (!wayDirection[way]) { 1068 | return false; 1069 | } 1070 | var lw = ord == -1 ? wayDirection[way][0] : 0, 1071 | rw = ord == +1 ? wayDirection[way][2] : 0; 1072 | if (testWay(rw)) { 1073 | way = rw; 1074 | rpath.push(+way * ord); 1075 | } else if (testWay(lw)) { 1076 | way = lw; 1077 | rpath.push(+way); 1078 | } else { 1079 | // indirect 1080 | var rwset = wayLookup[-wayDirection[way][2]]; 1081 | way = 0; 1082 | for (var j in rwset) { 1083 | rw = rwset[j]; 1084 | if (testWay(rw)) { 1085 | way = rw; 1086 | rpath.push(+way); 1087 | break; 1088 | } 1089 | } 1090 | if (!way) { 1091 | return false; 1092 | } 1093 | } 1094 | return way; 1095 | } 1096 | 1097 | while (false !== (way = getWay())) { 1098 | rpath = []; 1099 | ord = 1; 1100 | rpath.push(+way); 1101 | while (way) { 1102 | wayDirection[way][1] = 0; 1103 | var newWay = tryJoinWay(rpath, way); 1104 | if (!newWay) { 1105 | break; 1106 | } 1107 | way = newWay; 1108 | } 1109 | rpaths.push(rpath); 1110 | } 1111 | return rpaths; 1112 | } 1113 | 1114 | paths.sort(function (a, b) { 1115 | return Math.abs(a[0][0]) < Math.abs(b[0][0]); 1116 | }); 1117 | 1118 | var rpath = paths[0], 1119 | skip = { 0: 1 }, 1120 | skipCnt = 1, 1121 | rpaths = [], 1122 | l = paths.length, 1123 | freePass = 0, 1124 | joinPass = 0, 1125 | ccx = 0; 1126 | 1127 | while (skipCnt < l) { 1128 | joinPass = 0; 1129 | for (var i = 1, _l2 = paths.length; i < _l2; ++i) { 1130 | var rid = i % _l2; 1131 | if (!(rid in skip)) { 1132 | var result = joinPaths(rpath, paths[rid]); 1133 | if (result && result.length == 1) { 1134 | rpath = result; 1135 | skip[rid] = 1; 1136 | skipCnt++; 1137 | joinPass++; 1138 | } else { 1139 | freePass = rid; 1140 | } 1141 | } 1142 | } 1143 | if (!joinPass) { 1144 | if (freePass) { 1145 | rpaths.push(rpath[0]); 1146 | rpath = paths[freePass]; 1147 | skip[freePass] = 1; 1148 | skipCnt++; 1149 | } else { 1150 | break; 1151 | } 1152 | } 1153 | if (ccx++ > 1000) { 1154 | break; 1155 | } 1156 | } 1157 | 1158 | if (rpath) { 1159 | rpaths.push(rpath[0]); 1160 | } 1161 | 1162 | return (0, _geometryDecode.getFixedGeometry)(rpaths, regionsData); 1163 | } 1164 | 1165 | exports.default = recombineRegion; 1166 | },{"./geometryDecode":12,"./region":16}],16:[function(require,module,exports){ 1167 | "use strict"; 1168 | 1169 | Object.defineProperty(exports, "__esModule", { 1170 | value: true 1171 | }); 1172 | 1173 | 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; }; }(); 1174 | 1175 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1176 | 1177 | /** 1178 | * @name RegionObject 1179 | * @class 1180 | */ 1181 | var RegionObject = function () { 1182 | function RegionObject(rid, meta, prop, data) { 1183 | _classCallCheck(this, RegionObject); 1184 | 1185 | /** @member {Number} */ 1186 | this.osmId = rid; 1187 | /** @member {Number} */ 1188 | this.geoNamesId = prop.geoNamesId; 1189 | /** @member {String} */ 1190 | this.iso = prop.iso3166; 1191 | /** @member {Number} */ 1192 | this.level = meta.level; 1193 | /** @member {Object} */ 1194 | this.properties = prop; 1195 | 1196 | this._meta = meta; 1197 | this._data = data; 1198 | } 1199 | 1200 | _createClass(RegionObject, [{ 1201 | key: "getBorderWith", 1202 | value: function getBorderWith(id) { 1203 | var wset = {}, 1204 | i, 1205 | l1, 1206 | j, 1207 | l2, 1208 | path1 = this._data.paths[id], 1209 | path2 = this._data.paths[this.osmId]; 1210 | for (i = 0, l1 = path1.length; i < l1; ++i) { 1211 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 1212 | wset[Math.abs(path1[i][j])] = 1; 1213 | } 1214 | } 1215 | var result = []; 1216 | for (i = 0, l1 = path2.length; i < l1; ++i) { 1217 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 1218 | if (wset[Math.abs(path2[i][j])]) { 1219 | // path is full in 1220 | result.push(path2[i]); 1221 | } 1222 | } 1223 | } 1224 | return result; 1225 | } 1226 | }, { 1227 | key: "hasBorderWith", 1228 | value: function hasBorderWith(id) { 1229 | var wset = {}, 1230 | i, 1231 | l1, 1232 | j, 1233 | l2, 1234 | path1 = this._data.paths[this.osmId], 1235 | path2 = this._data.paths[id]; 1236 | if (!path1 || !path2) { 1237 | return false; 1238 | } 1239 | for (i = 0, l1 = path1.length; i < l1; ++i) { 1240 | for (j = 0, l2 = path1[i].length; j < l2; ++j) { 1241 | wset[Math.abs(path1[i][j])] = 1; 1242 | } 1243 | } 1244 | for (i = 0, l1 = path2.length; i < l1; ++i) { 1245 | for (j = 0, l2 = path2[i].length; j < l2; ++j) { 1246 | if (wset[Math.abs(path2[i][j])]) { 1247 | return true; 1248 | } 1249 | } 1250 | } 1251 | return false; 1252 | } 1253 | }, { 1254 | key: "hasParent", 1255 | value: function hasParent(id) { 1256 | var parents = this._meta.parents; 1257 | for (var i = 0, l = parents.length; i < l; ++i) { 1258 | if (parents[i].id == id) { 1259 | return true; 1260 | } 1261 | } 1262 | return false; 1263 | } 1264 | }]); 1265 | 1266 | return RegionObject; 1267 | }(); 1268 | 1269 | /** 1270 | * wraps region for filter functions 1271 | * @param rid 1272 | * @param data 1273 | * @returns {RegionObject} 1274 | */ 1275 | 1276 | 1277 | function wrapRegion(rid, data) { 1278 | var meta = data.regions[rid], 1279 | prop = meta.property || {}; 1280 | return new RegionObject(rid, meta, prop, data); 1281 | } 1282 | 1283 | exports.default = wrapRegion; 1284 | },{}],17:[function(require,module,exports){ 1285 | "use strict"; 1286 | 1287 | Object.defineProperty(exports, "__esModule", { 1288 | value: true 1289 | }); 1290 | 1291 | var _region = require("./region"); 1292 | 1293 | var _region2 = _interopRequireDefault(_region); 1294 | 1295 | var _recombine = require("./recombine"); 1296 | 1297 | var _recombine2 = _interopRequireDefault(_recombine); 1298 | 1299 | var _geometryDecode = require("./geometryDecode"); 1300 | 1301 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1302 | 1303 | /** 1304 | * main decode function 1305 | * @param regionsData 1306 | * @param options 1307 | * @returns {Array} 1308 | */ 1309 | function setupGeometry(regionsData, options) { 1310 | options = options || {}; 1311 | var regions = regionsData.regions, 1312 | dataset = [], 1313 | postFilter = options.postFilter || (regionsData.meta && regionsData.meta.postFilter ? new Function("region", regionsData.meta.postFilter) : 0), 1314 | scheme = options.scheme || regionsData.meta && regionsData.meta.scheme, 1315 | disputedBorders = regionsData.meta && regionsData.meta.disputedBorders || {}, 1316 | useSetup = options.recombine || options.lang || "en", 1317 | disputedBorder = typeof useSetup == "string" ? disputedBorders[useSetup] : useSetup, 1318 | geometry = 0; 1319 | 1320 | for (var _i in disputedBorders) { 1321 | var setup = disputedBorders[_i]; 1322 | for (var j in setup) { 1323 | var regionSet = setup[j]; 1324 | if (typeof regionSet == "string") { 1325 | setup[j] = new Function("region", regionSet); 1326 | } 1327 | } 1328 | } 1329 | 1330 | for (var _i2 in regions) { 1331 | if (regions.hasOwnProperty(_i2)) { 1332 | if (!postFilter || postFilter((0, _region2.default)(_i2, regionsData))) { 1333 | if (disputedBorder && disputedBorder[+_i2]) { 1334 | geometry = (0, _recombine2.default)(regionsData, { 1335 | filter: disputedBorder[+_i2] 1336 | }); 1337 | } else if (scheme && scheme[+_i2]) { 1338 | var sch = scheme[+_i2]; 1339 | geometry = (0, _recombine2.default)(regionsData, { 1340 | filter: typeof sch == "string" ? new Function("region", sch) : sch 1341 | }); 1342 | } else { 1343 | geometry = (0, _geometryDecode.getGeometry)(+_i2, regionsData); 1344 | } 1345 | 1346 | if (geometry) { 1347 | dataset[regions[_i2].index] = { 1348 | type: "Feature", 1349 | geometry: geometry, 1350 | properties: { 1351 | osmId: _i2, 1352 | level: regions[_i2].level, 1353 | properties: regions[_i2].property || {}, 1354 | parents: regions[_i2].parents, 1355 | hintContent: regions[_i2].name, 1356 | name: regions[_i2].name, 1357 | title: regions[_i2].name, 1358 | wikipedia: regions[_i2].wikipedia, 1359 | orderIndex: regions[_i2].index, 1360 | square: regions[_i2].square 1361 | } 1362 | }; 1363 | } 1364 | } 1365 | } 1366 | } 1367 | var result = []; 1368 | for (var i = 0, l = dataset.length; i < l; ++i) { 1369 | if (dataset[i]) { 1370 | result.push(dataset[i]); 1371 | } 1372 | } 1373 | return result; 1374 | } 1375 | 1376 | exports.default = setupGeometry; 1377 | },{"./geometryDecode":12,"./recombine":15,"./region":16}],18:[function(require,module,exports){ 1378 | "use strict"; 1379 | 1380 | Object.defineProperty(exports, "__esModule", { 1381 | value: true 1382 | }); 1383 | function getShortestPath(contour) { 1384 | var halfWorld = 180; 1385 | var result = [contour[0]], 1386 | point = contour[0]; 1387 | for (var i = 1, l = contour.length; i < l; ++i) { 1388 | var delta = point[0] - contour[i][0]; 1389 | if (Math.abs(delta) > halfWorld) { 1390 | delta = delta < 0 ? -360 : 360; 1391 | } else { 1392 | delta = 0; 1393 | } 1394 | 1395 | var nextPoint = [contour[i][0] + delta, contour[i][1]]; 1396 | result.push(nextPoint); 1397 | point = nextPoint; 1398 | } 1399 | return result; 1400 | } 1401 | 1402 | var getShortestContour = exports.getShortestContour = function getShortestContour(contour) { 1403 | return contour.map(function (path) { 1404 | return getShortestPath(path); 1405 | }); 1406 | }; 1407 | 1408 | exports.default = getShortestPath; 1409 | },{}]},{},[1])(1) 1410 | }); --------------------------------------------------------------------------------