├── .gitignore ├── .travis.yml ├── .zuul.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── component.json ├── index.js ├── package.json └── test ├── a.csv ├── a.geojson ├── a.gpx ├── a.kml ├── a.polyline ├── a.topojson ├── a.wkt ├── demo.html ├── options.csv ├── server.js └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | leaflet-omnivore.js 2 | leaflet-omnivore.min.js 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | script: 5 | - npm install 6 | - npm run test-headless 7 | # - npm run test-remote 8 | env: 9 | global: 10 | - secure: VX3HisGiObjV+0HynREXxKn4qqMM7pMVKphMjSWCucAxSyV//xeFTaFvuDOqoX9nYAcsisfBweDSOaofiSBCgVprxF0rK4URoPFRdlF1vJHfjP3JXID5kZssSsXPtmSyzuRHjYUnsqu1csM4FQDx0GTI5iwQqsTjSzvByzwiQGc= 11 | - secure: OcMhDEfS3LzSSHuLyJElBkg80XXaJE6+IzP8kmvelYENG0pQ9bpdoEAOux7vKYWp8T/OylHgaoipl/Y0kzqTTAaksLORSeuwgo5RffQveIy0V5nHh0X+USlWz3XKjg9BeWYiW3gDsaOLA/C2OLyH+DKe8FV1YffNzD1LqVmFhgc= 12 | -------------------------------------------------------------------------------- /.zuul.yml: -------------------------------------------------------------------------------- 1 | ui: tape 2 | server: test/server.js 3 | browsers: 4 | - name: chrome 5 | version: latest 6 | - name: safari 7 | version: latest 8 | - name: ie 9 | version: 9..latest 10 | - name: firefox 11 | version: latest 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.4 2 | 3 | * From now on, the repository doesn't contain leaflet-omnivore.js or leaflet-omnivore.min.js. Those 4 | files will be in the npm package and you can use unpkg.com to get them. 5 | 6 | ## 0.3.3 7 | 8 | * Call either `setGeoJSON` or `addData` on GeoJSON layers, not both. 9 | 10 | ## 0.3.2 11 | 12 | * Move `brfs` and `hintify` to dependencies. 13 | 14 | ## 0.3.1 15 | 16 | * Updates [wellknown](https://github.com/mapbox/wellknown) to 0.3.0 with exponent coordinate support 17 | * Updates [togeojson](https://github.com/mapbox/togeojson) to 0.10.1 with timestamp, ie9 feature id, gx:Track, gx:MultiTrack support 18 | 19 | ## 0.3.0 20 | 21 | * Includes [encoded polyline](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) support. 22 | 23 | ## 0.2.0 24 | 25 | * Only includes the necessary parts of [TopoJSON](https://github.com/mbostock/topojson): less bytes, 26 | and **IE9** and **IE10** are now supported. 27 | * Tests now use Sauce Labs and run on real browsers for every commit. 28 | * Builds now use an `npm` script rather than a Makefile. 29 | 30 | ## 0.1.0 31 | 32 | * loader functions now support a `customLayer` option for providing options to 33 | `L.geoJson` or using a different layer type. 34 | 35 | ## 0.0.1 36 | 37 | * `gpx.parse` and `kml.parse` support parsing from either strings or DOM objects 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Mapbox 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | ----------------------------------------------------------------------------- 30 | 31 | TopoJSON 32 | 33 | Copyright (c) 2012, Michael Bostock 34 | All rights reserved. 35 | 36 | Redistribution and use in source and binary forms, with or without 37 | modification, are permitted provided that the following conditions are met: 38 | 39 | * Redistributions of source code must retain the above copyright notice, this 40 | list of conditions and the following disclaimer. 41 | 42 | * Redistributions in binary form must reproduce the above copyright notice, 43 | this list of conditions and the following disclaimer in the documentation 44 | and/or other materials provided with the distribution. 45 | 46 | * The name Michael Bostock may not be used to endorse or promote products 47 | derived from this software without specific prior written permission. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 53 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 54 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 56 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 57 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 58 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # leaflet-omnivore 2 | 3 | ![](https://farm8.staticflickr.com/7373/12376158164_e335b4e61d_b.jpg) 4 | 5 | [Leaflet](http://leafletjs.com/) supports the [GeoJSON](http://geojson.org/) format 6 | by default. What if you have something else? That's where omnivore comes in. 7 | 8 | It currently supports: 9 | 10 | * [CSV](http://en.wikipedia.org/wiki/Comma-separated_values) (via [csv2geojson](https://github.com/mapbox/csv2geojson)) 11 | * GPX (via [toGeoJSON](https://github.com/mapbox/togeojson)) 12 | * [KML](http://developers.google.com/kml/documentation/) (via [toGeoJSON](https://github.com/mapbox/togeojson)) 13 | * [WKT](http://en.wikipedia.org/wiki/Well-known_text) (via [wellknown](https://github.com/mapbox/wellknown)) 14 | * [TopoJSON](https://github.com/mbostock/topojson) 15 | * [Encoded Polylines](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) via [polyline](https://github.com/mapbox/polyline) 16 | 17 | Omnivore also includes an AJAX library, [corslite](https://github.com/mapbox/corslite), 18 | so you can specify what you want to add to the map with just a URL. 19 | 20 | ## Installation 21 | 22 | use it easily with the [Mapbox Plugins CDN](http://mapbox.com/mapbox.js/plugins/#leaflet-omnivore): 23 | 24 | ```html 25 | 26 | ``` 27 | 28 | 29 | Or download `leaflet-omnivore.min.js` from this repository. 30 | 31 | ## example 32 | 33 | Live examples: 34 | 35 | * [WKT](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-wkt/) 36 | * [TopoJSON](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-topojson/) 37 | * [Tooltips](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-kml-tooltip/) 38 | * [KML](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-kml/) 39 | * [GPX](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-gpx/) 40 | * [Icons](https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-from-csv-custom-style/) 41 | * [CSV](https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-from-csv/) 42 | 43 | ```js 44 | var map = L.mapbox.map('map', 'mapbox.streets') 45 | .setView([38, -102.0], 5); 46 | 47 | omnivore.csv('a.csv').addTo(map); 48 | omnivore.gpx('a.gpx').addTo(map); 49 | omnivore.kml('a.kml').addTo(map); 50 | omnivore.wkt('a.wkt').addTo(map); 51 | omnivore.topojson('a.topojson').addTo(map); 52 | omnivore.geojson('a.geojson').addTo(map); 53 | omnivore.polyline('a.txt').addTo(map); 54 | ``` 55 | 56 | ## API 57 | 58 | Arguments with `?` are optional. **parser_options** consists of options 59 | sent to the parser library, _not_ to the layer: if you want to provide options 60 | to the layer, see the example in the Custom Layers section. 61 | 62 | By default, the library will construct a `L.geoJson()` layer internally and 63 | call `.addData(geojson)` on it in order to load it full of GeoJSON. If you want 64 | to use a different kind of layer, like a `L.mapbox.featureLayer()`, you can, 65 | by passing it as `customLayer`, as long as it supports events and `addData()`. 66 | You can also use this API to pass custom options to a `L.geoJson()` instance.: 67 | 68 | 69 | * `.csv(url, parser_options?, customLayer?)`: Load & parse CSV, and return layer. Options are the same as [csv2geojson](https://github.com/mapbox/csv2geojson#api): `latfield, lonfield, delimiter` 70 | * `.csv.parse(csvString, parser_options?)`: Parse CSV, and return layer. 71 | * `.kml(url)`: Load & parse KML, and return layer. 72 | * `.kml.parse(kmlString | gpxDom)`: Parse KML from a string of XML or XML DOM, and return layer. 73 | * `.gpx(url, parser_options?, customLayer?)`: Load & parse GPX, and return layer. 74 | * `.gpx.parse(gpxString | gpxDom)`: Parse GPX from a string of XML or XML DOM, and return layer. 75 | * `.geojson(url, parser_options?, customLayer?)`: Load GeoJSON file at URL, parse GeoJSON, and return layer. 76 | * `.wkt(url, parser_options?, customLayer?)`: Load & parse WKT, and return layer. 77 | * `.wkt.parse(wktString)`: Parse WKT, and return layer. 78 | * `.topojson(url, parser_options?, customLayer?)`: Load & parse TopoJSON, and return layer. 79 | * `.topojson.parse(topojson)`: Parse TopoJSON (given as a string or object), and return layer. 80 | * `.polyline(url, parser_options?, customLayer?)`: Load & parse polyline, and return layer. 81 | * `.polyline.parse(txt, options, layer)`: Parse polyline (given as a string or object), and return layer. 82 | 83 | Valid options: 84 | 85 | #### polyline 86 | 87 | * `precision` will change how the polyline is interpreted. By default, the value 88 | is 5. This is the [factor in the algorithm](https://developers.google.com/maps/documentation/utilities/polylinealgorithm), 89 | by default 1e5, which is adjustable. 90 | 91 | ### Custom Layers 92 | 93 | Passing custom options: 94 | 95 | ```js 96 | var customLayer = L.geoJson(null, { 97 | filter: function() { 98 | // my custom filter function 99 | return true; 100 | } 101 | }); 102 | 103 | var myLayer = omnivore.csv('foo', null, customLayer); 104 | ``` 105 | 106 | Adding custom styles to a GeoJSON layer: 107 | 108 | ```js 109 | var customLayer = L.geoJson(null, { 110 | // http://leafletjs.com/reference.html#geojson-style 111 | style: function(feature) { 112 | return { color: '#f00' }; 113 | } 114 | }); 115 | // this can be any kind of omnivore layer 116 | var runLayer = omnivore.kml('line.kml', null, customLayer) 117 | ``` 118 | 119 | Using a `L.mapbox.featureLayer`: 120 | 121 | ```js 122 | var layer = omnivore.gpx('a.gpx', null, L.mapbox.featureLayer()); 123 | ``` 124 | 125 | ### Async & Events 126 | 127 | Each function returns an `L.geoJson` object. Functions that load from URLs 128 | are **asynchronous**, so they will **not** immediately expose accurate `.setGeoJSON()` functions. 129 | 130 | For this reason, we fire events: 131 | 132 | * `ready`: fired when all data is loaded into the layer 133 | * `error`: fired if data can't be loaded or parsed 134 | 135 | ```js 136 | var layer = omnivore.gpx('a.gpx') 137 | .on('ready', function() { 138 | // when this is fired, the layer 139 | // is done being initialized 140 | }) 141 | .on('error', function() { 142 | // fired if the layer can't be loaded over AJAX 143 | // or can't be parsed 144 | }) 145 | .addTo(map); 146 | ``` 147 | 148 | `ready` does **not** fire if you don't use an asynchronous form of the function 149 | like `.topojson.parse()`: because you don't need an event. Just run your code 150 | after the call. 151 | 152 | ## Development 153 | 154 | This is a [browserify](http://browserify.org/) project: 155 | 156 | ```sh 157 | git clone git@github.com:mapbox/leaflet-omnivore.git 158 | 159 | cd leaflet-omnivore 160 | 161 | # to run tests 162 | npm install 163 | 164 | # to build leaflet-omnivore.js 165 | npm run prepublish 166 | ``` 167 | 168 | `leaflet-omnivore.js` and `leaflet-omnivore.min.js` are **built files** generated 169 | from `index.js` by `browserify`. If you find an issue, it either needs to be 170 | fixed in `index.js`, or in one of the libraries leaflet-omnivore uses 171 | to parse formats. 172 | 173 | ## FAQ 174 | 175 | * **What if I just want one format?** Lucky for you, each format is specified 176 | in a different module, so you can just use [TopoJSON](https://github.com/mbostock/topojson), 177 | [csv2geojson](https://github.com/mapbox/csv2geojson), [wellknown](https://github.com/mapbox/wellknown), or 178 | [toGeoJSON](https://github.com/mapbox/togeojson) 179 | individually. 180 | * **My AJAX request is failing for a cross-domain request**. Read up on the [Same Origin Restriction](http://en.wikipedia.org/wiki/Same-origin_policy). 181 | By default, we use corslite, so cross-domain requests will try to use [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) 182 | if your server and browser supports it, but if one of them doesn't, there's no 183 | way on the internet to support your request. 184 | * **Why isn't JSONP supported?** [Here's why](https://gist.github.com/tmcw/6244497). 185 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaflet-omnivore", 3 | "version": "0.2.0", 4 | "description": "a geospatial format parser for Leaflet", 5 | "scripts": [ 6 | "leaflet-omnivore.js" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var xhr = require('corslite'), 2 | csv2geojson = require('csv2geojson'), 3 | wellknown = require('wellknown'), 4 | polyline = require('polyline'), 5 | topojson = require('topojson'), 6 | toGeoJSON = require('togeojson'); 7 | 8 | module.exports.polyline = polylineLoad; 9 | module.exports.polyline.parse = polylineParse; 10 | 11 | module.exports.geojson = geojsonLoad; 12 | 13 | module.exports.topojson = topojsonLoad; 14 | module.exports.topojson.parse = topojsonParse; 15 | 16 | module.exports.csv = csvLoad; 17 | module.exports.csv.parse = csvParse; 18 | 19 | module.exports.gpx = gpxLoad; 20 | module.exports.gpx.parse = gpxParse; 21 | 22 | module.exports.kml = kmlLoad; 23 | module.exports.kml.parse = kmlParse; 24 | 25 | module.exports.wkt = wktLoad; 26 | module.exports.wkt.parse = wktParse; 27 | 28 | function addData(l, d) { 29 | if ('setGeoJSON' in l) { 30 | l.setGeoJSON(d); 31 | } else if ('addData' in l) { 32 | l.addData(d); 33 | } 34 | } 35 | 36 | /** 37 | * Load a [GeoJSON](http://geojson.org/) document into a layer and return the layer. 38 | * 39 | * @param {string} url 40 | * @param {object} options 41 | * @param {object} customLayer 42 | * @returns {object} 43 | */ 44 | function geojsonLoad(url, options, customLayer) { 45 | var layer = customLayer || L.geoJson(); 46 | xhr(url, function(err, response) { 47 | if (err) return layer.fire('error', { error: err }); 48 | addData(layer, JSON.parse(response.responseText)); 49 | layer.fire('ready'); 50 | }); 51 | return layer; 52 | } 53 | 54 | /** 55 | * Load a [TopoJSON](https://github.com/mbostock/topojson) document into a layer and return the layer. 56 | * 57 | * @param {string} url 58 | * @param {object} options 59 | * @param {object} customLayer 60 | * @returns {object} 61 | */ 62 | function topojsonLoad(url, options, customLayer) { 63 | var layer = customLayer || L.geoJson(); 64 | xhr(url, onload); 65 | function onload(err, response) { 66 | if (err) return layer.fire('error', { error: err }); 67 | topojsonParse(response.responseText, options, layer); 68 | layer.fire('ready'); 69 | } 70 | return layer; 71 | } 72 | 73 | /** 74 | * Load a CSV document into a layer and return the layer. 75 | * 76 | * @param {string} url 77 | * @param {object} options 78 | * @param {object} customLayer 79 | * @returns {object} 80 | */ 81 | function csvLoad(url, options, customLayer) { 82 | var layer = customLayer || L.geoJson(); 83 | xhr(url, onload); 84 | function onload(err, response) { 85 | var error; 86 | if (err) return layer.fire('error', { error: err }); 87 | function avoidReady() { 88 | error = true; 89 | } 90 | layer.on('error', avoidReady); 91 | csvParse(response.responseText, options, layer); 92 | layer.off('error', avoidReady); 93 | if (!error) layer.fire('ready'); 94 | } 95 | return layer; 96 | } 97 | 98 | /** 99 | * Load a GPX document into a layer and return the layer. 100 | * 101 | * @param {string} url 102 | * @param {object} options 103 | * @param {object} customLayer 104 | * @returns {object} 105 | */ 106 | function gpxLoad(url, options, customLayer) { 107 | var layer = customLayer || L.geoJson(); 108 | xhr(url, onload); 109 | function onload(err, response) { 110 | var error; 111 | if (err) return layer.fire('error', { error: err }); 112 | function avoidReady() { 113 | error = true; 114 | } 115 | layer.on('error', avoidReady); 116 | gpxParse(response.responseXML || response.responseText, options, layer); 117 | layer.off('error', avoidReady); 118 | if (!error) layer.fire('ready'); 119 | } 120 | return layer; 121 | } 122 | 123 | /** 124 | * Load a [KML](https://developers.google.com/kml/documentation/) document into a layer and return the layer. 125 | * 126 | * @param {string} url 127 | * @param {object} options 128 | * @param {object} customLayer 129 | * @returns {object} 130 | */ 131 | function kmlLoad(url, options, customLayer) { 132 | var layer = customLayer || L.geoJson(); 133 | xhr(url, onload); 134 | function onload(err, response) { 135 | var error; 136 | if (err) return layer.fire('error', { error: err }); 137 | function avoidReady() { 138 | error = true; 139 | } 140 | layer.on('error', avoidReady); 141 | kmlParse(response.responseXML || response.responseText, options, layer); 142 | layer.off('error', avoidReady); 143 | if (!error) layer.fire('ready'); 144 | } 145 | return layer; 146 | } 147 | 148 | /** 149 | * Load a WKT (Well Known Text) string into a layer and return the layer 150 | * 151 | * @param {string} url 152 | * @param {object} options 153 | * @param {object} customLayer 154 | * @returns {object} 155 | */ 156 | function wktLoad(url, options, customLayer) { 157 | var layer = customLayer || L.geoJson(); 158 | xhr(url, onload); 159 | function onload(err, response) { 160 | if (err) return layer.fire('error', { error: err }); 161 | wktParse(response.responseText, options, layer); 162 | layer.fire('ready'); 163 | } 164 | return layer; 165 | } 166 | 167 | /** 168 | * Load a polyline string into a layer and return the layer 169 | * 170 | * @param {string} url 171 | * @param {object} options 172 | * @param {object} customLayer 173 | * @returns {object} 174 | */ 175 | function polylineLoad(url, options, customLayer) { 176 | var layer = customLayer || L.geoJson(); 177 | xhr(url, onload); 178 | function onload(err, response) { 179 | if (err) return layer.fire('error', { error: err }); 180 | polylineParse(response.responseText, options, layer); 181 | layer.fire('ready'); 182 | } 183 | return layer; 184 | } 185 | 186 | function topojsonParse(data, options, layer) { 187 | var o = typeof data === 'string' ? 188 | JSON.parse(data) : data; 189 | layer = layer || L.geoJson(); 190 | for (var i in o.objects) { 191 | var ft = topojson.feature(o, o.objects[i]); 192 | if (ft.features) addData(layer, ft.features); 193 | else addData(layer, ft); 194 | } 195 | return layer; 196 | } 197 | 198 | function csvParse(csv, options, layer) { 199 | layer = layer || L.geoJson(); 200 | options = options || {}; 201 | csv2geojson.csv2geojson(csv, options, onparse); 202 | function onparse(err, geojson) { 203 | if (err) return layer.fire('error', { error: err }); 204 | addData(layer, geojson); 205 | } 206 | return layer; 207 | } 208 | 209 | function gpxParse(gpx, options, layer) { 210 | var xml = parseXML(gpx); 211 | if (!xml) return layer.fire('error', { 212 | error: 'Could not parse GPX' 213 | }); 214 | layer = layer || L.geoJson(); 215 | var geojson = toGeoJSON.gpx(xml); 216 | addData(layer, geojson); 217 | return layer; 218 | } 219 | 220 | 221 | function kmlParse(gpx, options, layer) { 222 | var xml = parseXML(gpx); 223 | if (!xml) return layer.fire('error', { 224 | error: 'Could not parse KML' 225 | }); 226 | layer = layer || L.geoJson(); 227 | var geojson = toGeoJSON.kml(xml); 228 | addData(layer, geojson); 229 | return layer; 230 | } 231 | 232 | function polylineParse(txt, options, layer) { 233 | layer = layer || L.geoJson(); 234 | options = options || {}; 235 | var coords = polyline.decode(txt, options.precision); 236 | var geojson = { type: 'LineString', coordinates: [] }; 237 | for (var i = 0; i < coords.length; i++) { 238 | // polyline returns coords in lat, lng order, so flip for geojson 239 | geojson.coordinates[i] = [coords[i][1], coords[i][0]]; 240 | } 241 | addData(layer, geojson); 242 | return layer; 243 | } 244 | 245 | function wktParse(wkt, options, layer) { 246 | layer = layer || L.geoJson(); 247 | var geojson = wellknown(wkt); 248 | addData(layer, geojson); 249 | return layer; 250 | } 251 | 252 | function parseXML(str) { 253 | if (typeof str === 'string') { 254 | return (new DOMParser()).parseFromString(str, 'text/xml'); 255 | } else { 256 | return str; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mapbox/leaflet-omnivore", 3 | "version": "0.3.4", 4 | "description": "a geospatial format parser for Leaflet", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "zuul --local -- test/test.js", 8 | "test-remote": "zuul -- test/test.js", 9 | "test-headless": "zuul --phantom -- test/test.js", 10 | "prepublish": "browserify -s omnivore index.js > leaflet-omnivore.js && uglifyjs leaflet-omnivore.js -c -m > leaflet-omnivore.min.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git@github.com:mapbox/leaflet-omnivore.git" 15 | }, 16 | "files": [ 17 | "index.js", 18 | "leaflet-omnivore.js", 19 | "leaflet-omnivore.min.js" 20 | ], 21 | "browserify": { 22 | "transform": [ 23 | "brfs" 24 | ] 25 | }, 26 | "keywords": [ 27 | "leaflet", 28 | "formats", 29 | "kml", 30 | "csv", 31 | "gpx", 32 | "geojson", 33 | "kml", 34 | "leaflet", 35 | "maps", 36 | "gpx", 37 | "wkt", 38 | "osm", 39 | "polyline", 40 | "topojson", 41 | "format", 42 | "converter" 43 | ], 44 | "author": "Tom MacWright", 45 | "license": "BSD-3-Clause", 46 | "bugs": { 47 | "url": "https://github.com/mapbox/leaflet-omnivore/issues" 48 | }, 49 | "homepage": "https://github.com/mapbox/leaflet-omnivore", 50 | "dependencies": { 51 | "csv2geojson": "~5.0.0", 52 | "togeojson": "0.13.0", 53 | "corslite": "0.0.7", 54 | "wellknown": "0.4.2", 55 | "brfs": "1.4.3", 56 | "topojson": "1.6.26", 57 | "polyline": "0.2.0" 58 | }, 59 | "devDependencies": { 60 | "browserify": "13.0.1", 61 | "tape": "4.5.1", 62 | "uglify-js": "^2.6.2", 63 | "jshint": "2.9.2", 64 | "mocha": "~2.5.3", 65 | "zuul": "~3.10.1", 66 | "st": "1.1.0", 67 | "mapbox.js": "2.4.0", 68 | "phantomjs-prebuilt": "2.1.7" 69 | } 70 | } -------------------------------------------------------------------------------- /test/a.csv: -------------------------------------------------------------------------------- 1 | lat,lon,name 2 | 0,0,"Hello World" 3 | -------------------------------------------------------------------------------- /test/a.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "geometry": { 7 | "type": "GeometryCollection", 8 | "geometries": [ 9 | { 10 | "type": "LineString", 11 | "coordinates": [ 12 | [ 13 | -122.4425587930444, 14 | 37.80666418607323, 15 | 0 16 | ], 17 | [ 18 | -122.4428379594768, 19 | 37.80663578323093, 20 | 0 21 | ] 22 | ] 23 | }, 24 | { 25 | "type": "LineString", 26 | "coordinates": [ 27 | [ 28 | -122.4425509770566, 29 | 37.80662588061205, 30 | 0 31 | ], 32 | [ 33 | -122.4428340530617, 34 | 37.8065999493009, 35 | 0 36 | ] 37 | ] 38 | } 39 | ] 40 | }, 41 | "properties": { 42 | "name": "SF Marina Harbor Master" 43 | } 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /test/a.gpx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1298.0 6 | 7 | 1301.0 8 | 9 | 1304.0 10 | 11 | 1306.0 12 | 13 | 1308.0 14 | 15 | 1311.0 16 | 17 | 1316.0 18 | 19 | 1320.0 20 | 21 | 1323.0 22 | 23 | 1325.0 24 | 25 | 1328.0 26 | 27 | 1333.0 28 | 29 | 1342.0 30 | 31 | 1349.0 32 | 33 | 1363.0 34 | 35 | 1379.0 36 | 37 | 1381.0 38 | 39 | 1387.0 40 | 41 | 1405.0 42 | 43 | 1410.0 44 | 45 | 1420.0 46 | 47 | 1425.0 48 | 49 | 1430.0 50 | 51 | 1433.0 52 | 53 | 1437.0 54 | 55 | 1444.0 56 | 57 | 1452.0 58 | 59 | 1461.0 60 | 61 | 1464.0 62 | 63 | 1467.0 64 | 65 | 1468.0 66 | 67 | 1471.0 68 | 69 | 1474.0 70 | 71 | 1477.0 72 | 73 | 1481.0 74 | 75 | 1487.0 76 | 77 | 1494.0 78 | 79 | 1501.0 80 | 81 | 1502.0 82 | 83 | 1503.0 84 | 85 | 1512.0 86 | 87 | 1521.0 88 | 89 | 1527.0 90 | 91 | 1541.0 92 | 93 | 1542.0 94 | 95 | 1544.0 96 | 97 | 1548.0 98 | 99 | 1544.0 100 | 101 | 1561.0 102 | 103 | 1566.0 104 | 105 | 1566.0 106 | 107 | 1581.0 108 | 109 | 1604.0 110 | 111 | 1590.0 112 | 113 | 1607.0 114 | 115 | 1612.0 116 | 117 | 1630.0 118 | 119 | 1647.0 120 | 121 | 1662.0 122 | 123 | 1662.0 124 | 125 | 1664.0 126 | 127 | 1711.0 128 | 129 | 1723.0 130 | 131 | 1760.0 132 | 133 | 1747.0 134 | 135 | 1767.0 136 | 137 | 1780.0 138 | 139 | 1794.0 140 | 141 | 1813.0 142 | 143 | 1813.0 144 | 145 | 1847.0 146 | 147 | 1868.0 148 | 149 | 1870.0 150 | 151 | 1869.0 152 | 153 | 1887.0 154 | 155 | 1886.0 156 | 157 | 1900.0 158 | 159 | 1916.0 160 | 161 | 1916.0 162 | 163 | 1916.0 164 | 165 | 1948.0 166 | 167 | 1947.0 168 | 169 | 1946.0 170 | 171 | 1976.0 172 | 173 | 1975.0 174 | 175 | 2002.0 176 | 177 | 2012.0 178 | 179 | 2036.0 180 | 181 | 2049.0 182 | 183 | 2045.0 184 | 185 | 2041.0 186 | 187 | 2052.0 188 | 189 | 2058.0 190 | 191 | 2062.0 192 | 193 | 2069.0 194 | 195 | 2066.0 196 | 197 | 2097.0 198 | 199 | 2091.0 200 | 201 | 2125.0 202 | 203 | 2131.0 204 | 205 | 2159.0 206 | 207 | 2161.0 208 | 209 | 2175.0 210 | 211 | 2174.0 212 | 213 | 2170.0 214 | 215 | 2207.0 216 | 217 | 2236.0 218 | 219 | 2234.0 220 | 221 | 2241.0 222 | 223 | 2234.0 224 | 225 | 2240.0 226 | 227 | 2253.0 228 | 229 | 2277.0 230 | 231 | 2286.0 232 | 233 | 2275.0 234 | 235 | 2279.0 236 | 237 | 2283.0 238 | 239 | 2295.0 240 | 241 | 2291.0 242 | 243 | 2285.0 244 | -------------------------------------------------------------------------------- /test/a.kml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Simple placemark 5 | Attached to the ground. Intelligently places itself 6 | at the height of the underlying terrain. 7 | 8 | -122.0822035425683,37.42228990140251,0 9 | 10 | 11 | 12 | Simple placemark two 13 | Attached to the ground. Intelligently places itself 14 | at the height of the underlying terrain. 15 | 16 | -120.0822035425683,37.42228990140251,0 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/a.polyline: -------------------------------------------------------------------------------- 1 | _p~iF~ps|U_ulLnnqC_mqNvxq`@ 2 | -------------------------------------------------------------------------------- /test/a.topojson: -------------------------------------------------------------------------------- 1 | {"type":"Topology","objects":{"collection":{"type":"GeometryCollection","geometries":[{"type":"LineString","arcs":[0]}]}},"arcs":[[[0,2202],[3273,6332],[655,-8534],[1726,7176],[4345,2823]]],"bbox":[3.1640625,41.77131167976407,62.22656249999999,54.57206165565852],"transform":{"scale":[0.005906840684068406,0.0012802030178912344],"translate":[3.1640625,41.77131167976407]}} -------------------------------------------------------------------------------- /test/a.wkt: -------------------------------------------------------------------------------- 1 | MultiPoint(20 20, 10 10, 30 30) 2 | -------------------------------------------------------------------------------- /test/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Loading CSV into Markers 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 |
17 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/options.csv: -------------------------------------------------------------------------------- 1 | a,b,name 2 | 20,10,"Hello World" 3 | -------------------------------------------------------------------------------- /test/server.js: -------------------------------------------------------------------------------- 1 | var st = require('st'); 2 | var http = require('http'); 3 | 4 | console.log('serving on ', process.env.ZUUL_PORT, ' in ', __dirname); 5 | http.createServer(st(__dirname)).listen(process.env.ZUUL_PORT); 6 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | require('mapbox.js'); 2 | 3 | var test = require('tape'), 4 | fs = require('fs'), 5 | omnivore = require('../'); 6 | 7 | test('gpx-featureLayer', function (t) { 8 | function customFilter() { return true; } 9 | var l = L.mapbox.featureLayer(); 10 | var layer = omnivore.gpx('a.gpx', null, l); 11 | 12 | t.ok('setFilter' in layer, 'uses a featureLayer'); 13 | layer.on('ready', function() { 14 | t.pass('fires ready event'); 15 | t.ok('setFilter' in layer, 'uses a featureLayer'); 16 | t.end(); 17 | }); 18 | layer.on('error', function() { 19 | t.fail('does not fire error event'); 20 | t.end(); 21 | }); 22 | }); 23 | 24 | test('gpx-customLayer', function (t) { 25 | function customFilter() { return true; } 26 | var l = L.geoJson(null, { 27 | filter: customFilter 28 | }); 29 | var layer = omnivore.gpx('a.gpx', null, l); 30 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 31 | layer.on('ready', function() { 32 | t.pass('fires ready event'); 33 | t.equal(layer.options.filter, customFilter, 'uses a customLayer'); 34 | t.end(); 35 | }); 36 | layer.on('error', function() { 37 | t.fail('does not fire error event'); 38 | t.end(); 39 | }); 40 | }); 41 | 42 | test('gpx', function (t) { 43 | t.plan(2); 44 | var layer = omnivore.gpx('a.gpx'); 45 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 46 | layer.on('ready', function() { 47 | t.pass('fires ready event'); 48 | }); 49 | layer.on('error', function() { 50 | t.fail('does not fire error event'); 51 | }); 52 | }); 53 | 54 | test('polyline.parse', function (t) { 55 | t.plan(2); 56 | var layer = omnivore.polyline.parse(fs.readFileSync('./test/a.polyline', 'utf8')); 57 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 58 | t.equal(layer.toGeoJSON().features.length, 1); 59 | }); 60 | 61 | test('gpx.parse', function (t) { 62 | t.plan(2); 63 | var layer = omnivore.gpx.parse(fs.readFileSync('./test/a.gpx', 'utf8')); 64 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 65 | t.equal(layer.toGeoJSON().features.length, 1); 66 | }); 67 | 68 | test('csv fail', function (t) { 69 | t.plan(4); 70 | var layer = omnivore.csv('a.gpx'); 71 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 72 | layer.on('ready', function() { 73 | t.fail('fires ready event'); 74 | }); 75 | layer.on('error', function(e) { 76 | t.equal(e.error.message, 'Latitude and longitude fields not present'); 77 | t.equal(e.error.type, 'Error'); 78 | t.pass('fires error event'); 79 | }); 80 | }); 81 | 82 | test('csv options', function (t) { 83 | t.plan(2); 84 | var layer = omnivore.csv('options.csv', { 85 | latfield: 'a', 86 | lonfield: 'b' 87 | }); 88 | layer.on('ready', function() { 89 | t.pass('fires ready event'); 90 | t.deepEqual( 91 | layer.toGeoJSON().features[0].geometry.coordinates, 92 | [10, 20], 'parses coordinates'); 93 | }); 94 | layer.on('error', function() { 95 | t.fail('fires error event'); 96 | }); 97 | }); 98 | 99 | test('kml', function (t) { 100 | t.plan(2); 101 | var layer = omnivore.kml('a.kml'); 102 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 103 | layer.on('ready', function() { 104 | t.pass('fires ready event'); 105 | }); 106 | layer.on('error', function() { 107 | t.fail('does not fire error event'); 108 | }); 109 | }); 110 | 111 | test('kml.parse', function (t) { 112 | t.plan(2); 113 | var layer = omnivore.kml.parse(fs.readFileSync('./test/a.kml', 'utf8')); 114 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 115 | t.equal(layer.toGeoJSON().features.length, 2); 116 | }); 117 | 118 | test('csv', function (t) { 119 | t.plan(2); 120 | var layer = omnivore.csv('a.csv'); 121 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 122 | layer.on('ready', function() { 123 | t.pass('fires ready event'); 124 | }); 125 | layer.on('error', function() { 126 | t.fail('does not fire error event'); 127 | }); 128 | }); 129 | 130 | test('polyline', function (t) { 131 | t.plan(2); 132 | var layer = omnivore.polyline('a.polyline'); 133 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 134 | layer.on('ready', function() { 135 | t.pass('fires ready event'); 136 | }); 137 | layer.on('error', function() { 138 | t.fail('does not fire error event'); 139 | }); 140 | }); 141 | 142 | test('csv.parse', function (t) { 143 | t.plan(1); 144 | var lyr = omnivore.csv.parse('lat,lon,title\n0,0,"Hello"'); 145 | t.ok(lyr instanceof L.GeoJSON, 'produces layer'); 146 | }); 147 | 148 | test('wkt.parse', function (t) { 149 | t.plan(1); 150 | var lyr = omnivore.wkt.parse('MultiPoint(20 20, 10 10, 30 30)'); 151 | t.ok(lyr instanceof L.GeoJSON, 'produces layer'); 152 | }); 153 | 154 | test('wkt', function (t) { 155 | t.plan(2); 156 | var layer = omnivore.wkt('a.wkt'); 157 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 158 | layer.on('ready', function() { 159 | t.pass('fires ready event'); 160 | }); 161 | layer.on('error', function() { 162 | t.fail('does not fire error event'); 163 | }); 164 | }); 165 | 166 | test('topojson', function (t) { 167 | t.plan(2); 168 | var layer = omnivore.topojson('a.topojson'); 169 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 170 | layer.on('ready', function() { 171 | t.pass('fires ready event'); 172 | }); 173 | layer.on('error', function() { 174 | t.fail('does not fire error event'); 175 | }); 176 | }); 177 | 178 | test('topojson.parse', function (t) { 179 | t.plan(1); 180 | var lyr = omnivore.topojson.parse(fs.readFileSync('./test/a.topojson', 'utf8')); 181 | t.ok(lyr instanceof L.GeoJSON, 'produces geojson layer'); 182 | }); 183 | 184 | test('geojson', function (t) { 185 | t.plan(2); 186 | var layer = omnivore.geojson('a.geojson'); 187 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 188 | layer.on('ready', function() { 189 | t.pass('fires ready event'); 190 | }); 191 | layer.on('error', function() { 192 | t.fail('does not fire error event'); 193 | }); 194 | }); 195 | 196 | test('geojson: fail', function (t) { 197 | t.plan(2); 198 | var layer = omnivore.geojson('404 does not exist'); 199 | t.ok(layer instanceof L.GeoJSON, 'produces geojson layer'); 200 | layer.on('ready', function() { 201 | t.fail('fires ready event'); 202 | }); 203 | layer.on('error', function(e) { 204 | t.pass('fires error event'); 205 | }); 206 | }); 207 | --------------------------------------------------------------------------------