├── .eslintrc.js ├── .gitignore ├── .jsbeautifyrc ├── LICENSE ├── README.md ├── docs ├── class-breaks-symbology │ └── index.html ├── comparison │ ├── css │ │ ├── normalize.css │ │ └── skeleton.css │ └── index.html ├── csv-data │ ├── Flowmap_Cities.csv │ ├── Flowmap_Cities_many_to_one.csv │ ├── Flowmap_Cities_one_to_many.csv │ └── Flowmap_Cities_one_to_one.csv └── main │ └── index.html ├── img └── img_01.png └── src └── CanvasFlowmapLayer.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true 4 | }, 5 | "globals": { 6 | "define": false, 7 | "require": false, 8 | "module": false, 9 | "L": false, 10 | "TWEEN": false, 11 | "Papa": false 12 | }, 13 | "rules": { 14 | "no-debugger": "error", 15 | "no-bitwise": "error", 16 | "curly": "error", 17 | "eqeqeq": "error", 18 | "guard-for-in": "error", 19 | "block-scoped-var": "off", 20 | "no-use-before-define": "warn", 21 | "max-params": "off", 22 | "no-caller": "error", 23 | "no-new": "error", 24 | "no-shadow": "error", 25 | "strict": "off", 26 | "no-undef": "error", 27 | "no-unused-vars": "error", 28 | "no-eval": "off", 29 | "indent": ["error", 2, { 30 | "SwitchCase": 1 31 | }], 32 | "quotes": ["error", "single"] 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwasilgeo/Leaflet.Canvas-Flowmap-Layer/7ae3238d3bbe11512eeda5ce47b5593c172b23e6/.gitignore -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "indent_size": 2, 3 | "indent_char": " ", 4 | "other": "", 5 | "indent_level": 0, 6 | "indent_with_tabs": false, 7 | "preserve_newlines": true, 8 | "max_preserve_newlines": 2, 9 | "indent_handlebars": true 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jacob Wasilkowski 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leaflet.Canvas-Flowmap-Layer 2 | 3 | The `Leaflet.Canvas-Flowmap-Layer` is a custom layer plugin for [LeafletJS](http://leafletjs.com/) to map the flow of objects from an origin point to a destination point by using a Bezier curve. GeoJSON point feature coordinates are translated to pixel space so that rendering for the points and curves are mapped to an [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement). 4 | 5 | **Demos:** 6 | 7 | - [Simple](https://jwasilgeo.github.io/Leaflet.Canvas-Flowmap-Layer/docs/main) 8 | - [Feature comparison](https://jwasilgeo.github.io/Leaflet.Canvas-Flowmap-Layer/docs/comparison) (aka: kitchen sink, sandbox) 9 | - [Advanced symbology: class breaks of flowlines](https://jwasilgeo.github.io/Leaflet.Canvas-Flowmap-Layer/docs/class-breaks-symbology) 10 | 11 | **Important!** 12 | 13 | This is a LeafletJS port of [sarahbellum/Canvas-Flowmap-Layer](https://www.github.com/sarahbellum/Canvas-Flowmap-Layer), which was originally written for the ArcGIS API for JavaScript. Go there to learn more! 14 | 15 | View our [**presentation at NACIS 2017**](https://www.youtube.com/watch?v=cRPx-BfBtv0). 16 | 17 | **Table of Contents:** 18 | 19 | - [Purpose and Background](#purpose-and-background) 20 | - [Options and More Information for Developers](#options-and-more-information-for-developers) 21 | - [Data Relationships](#data-relationships) 22 | - [Animation](#animation) 23 | - [Interaction](#interaction) 24 | - [Symbology](#symbology) 25 | - [API](#api) 26 | - [Constructor Summary](#constructor-summary) 27 | - [Options and Property Summary](#options-and-property-summary) 28 | - [Method Summary](#method-summary) 29 | - [Event Summary](#event-summary) 30 | - [Licensing](#licensing) 31 | 32 | [![screenshot](https://raw.githubusercontent.com/jwasilgeo/Leaflet.Canvas-Flowmap-Layer/master/img/img_01.png)](https://jwasilgeo.github.io/Leaflet.Canvas-Flowmap-Layer/docs/main) 33 | 34 | ## Purpose and Background 35 | 36 | Please see [sarahbellum/Canvas-Flowmap-Layer#purpose](https://github.com/sarahbellum/Canvas-Flowmap-Layer#purpose) for more detailed information. 37 | 38 | ## Options and More Information for Developers 39 | 40 | ### Data Relationships 41 | 42 | "One-to-many", "many-to-one" and "one-to-one" origin-to-destination relationships are supported by this custom layer. 43 | 44 | **Important:** The developer must format and provide a GeoJSON point feature collection in a specific format. This layer expects that _both_ origin and destination attributes and spatial coordinates are available in each GeoJSON point feature's properties. 45 | 46 | Example of a single GeoJSON point feature within a feature collection that includes _both_ origin and destination info: 47 | 48 | ```json 49 | { 50 | "type": "Feature", 51 | "geometry": { 52 | "type": "Point", 53 | "coordinates":[109.6091129, 23.09653465] 54 | }, 55 | "properties": { 56 | "origin_id": 238, 57 | "origin_city": "Hechi", 58 | "origin_country": "China", 59 | "origin_lon": 109.6091129, 60 | "origin_lat": 23.09653465, 61 | "destination_id": 1, 62 | "destination_city": "Sarh", 63 | "destination_country": "Chad", 64 | "destination_lon": 18.39002966, 65 | "destination_lat": 9.149969909 66 | } 67 | } 68 | ``` 69 | 70 | Please see [sarahbellum/Canvas-Flowmap-Layer#data-relationships](https://github.com/sarahbellum/Canvas-Flowmap-Layer#data-relationships) for more details. 71 | 72 | ### Animation 73 | 74 | The animations rely on the [tween.js library](https://github.com/tweenjs/tween.js) to assist with changing the underlying line property values as well as providing many different easing functions and durations. See the `setAnimationDuration()` and `setAnimationEasing()` method descriptions below for more information. 75 | 76 | **Important:** If animations are going to be used, then the developer must first load the tween.js library. 77 | 78 | ```html 79 | 80 | 81 | 82 | 83 | 84 | ``` 85 | 86 | ### Interaction 87 | 88 | You can change how users interact with the `Leaflet.CanvasFlowmapLayer` by controlling which Bezier curves appear and disappear at any time. The demos we provide show how to do this in several ways with LeafletJS `click` and `mouseover` events, coupled with using this layer's `selectFeaturesForPathDisplay()` method. 89 | 90 | For example, you could listen for a `click` event on an origin point feature—which is displayed on the map as an `L.CircleMarker`—and then choose to either **add** to your selection of displayed Bezier curves, **subtract** from your selection, or establish a brand **new** selection. 91 | 92 | Alternatively, you could set the `pathDisplayMode` option to `'all'` when constructing the layer to display every Bezier curve at once. 93 | 94 | ### Symbology 95 | 96 | The `Leaflet.Canvas-Flowmap-Layer` has default symbol styles established for origin and destination point `L.CircleMarker`s, canvas Bezier curves, and animated canvas Bezier curves. 97 | 98 | The default symbol styles for **origin and destination point** `L.CircleMarker`s can be changed by using the layer constructor option `style()` method, since this layer extends from `L.GeoJSON`. 99 | 100 | The default symbol styles for **canvas Bezier paths and animations** can be changed by overriding the layer constructor options for `canvasBezierStyle` and `animatedCanvasBezierStyle`, specifically using HTMLCanvasElement stroke and line style property names (instead of LeafletJS marker style properties). 101 | 102 | The caveat here is that this Leaflet version of the Canvas-Flowmap-Layer **and** the [Esri-compatible Canvas-Flowmap-Layer](https://github.com/sarahbellum/Canvas-Flowmap-Layer) both rely on symbol configurations that are defined using property objects inspired by the ArcGIS REST API renderer objects specification. Simple, unique value, and class breaks are all supported but instead use canvas stroke and line style property names. Specifically for this, read about the [ArcGIS REST API renderer objects specification](http://resources.arcgis.com/en/help/arcgis-rest-api/#/Renderer_objects/02r30000019t000000/). 103 | 104 | See the developer API section below and also [sarahbellum/Canvas-Flowmap-Layer#symbology](https://github.com/sarahbellum/Canvas-Flowmap-Layer#symbology) for more details. We have provided a demo page of how to set class breaks symbology for Bezier curves. 105 | 106 | ## API 107 | 108 | This extends the LeafletJS v1 [`L.GeoJSON` layer](http://leafletjs.com/reference-1.3.0.html#geojson). All properties, methods, and events provided by the `L.GeoJSON` layer are available in the `Leaflet.CanvasFlowmapLayer`, with additional custom features described below. 109 | 110 | ### Constructor Summary 111 | 112 | ```javascript 113 | var geoJsonFeatureCollection = { 114 | // collection of GeoJSON point features 115 | // with origin and destination attribute properties 116 | 117 | // see discussion above, demos, and CSV example data sources 118 | }; 119 | 120 | var exampleFlowmapLayer = L.canvasFlowmapLayer(geoJsonFeatureCollection, { 121 | // required property for this custom layer, 122 | // which relies on the property names of your own data 123 | originAndDestinationFieldIds: { 124 | // all kinds of important stuff here...see docs below 125 | 126 | // however, this isn't required if your own data 127 | // is in the same format as the layer source code 128 | }, 129 | 130 | // some custom options 131 | pathDisplayMode: 'selection', 132 | animationStarted: true, 133 | animationEasingFamily: 'Cubic', 134 | animationEasingType: 'In', 135 | animationDuration: 2000 136 | }).addTo(map); 137 | ``` 138 | 139 | ### Options and Property Summary 140 | 141 | | Property | Description | 142 | | --- | --- | 143 | | `originAndDestinationFieldIds` | **Required if your data does not have the same property field names as the layer source code.** `Object`. This object informs the layer of your unique origin and destination attributes (fields). Both origins and destinations need to have their own unique ID attribute and geometry definition. [See example below](#originanddestinationfieldids-example) which includes minimum required object properties. | 144 | | `style` | _Optional_. `Function`. This function defines the symbol style properties of the origin and destination `L.CircleMarker`. [See example below](#style-example). | 145 | | `canvasBezierStyle` | _Optional_. `Object`. This object defines the symbol properties of the non-animated Bezier curve that is drawn on the canvas connecting an origin point to a destination point. [See Symbology discussion above](#symbology). | 146 | | `animatedCanvasBezierStyle` | _Optional_. `Object`. This defines the symbol properties of the animated Bezier curve that is drawn on the canvas directly on top of the non-animated Bezier curve. [See Symbology discussion above](#symbology). | 147 | | `pathDisplayMode` | _Optional_. `String`. Valid values: `'selection'` or `'all'`. Defaults to `'all'`. | 148 | | `wrapAroundCanvas` | _Optional_. `Boolean`. Defaults to `true`. Ensures that canvas features will be drawn beyond +/-180 longitude. | 149 | | `animationStarted` | _Optional_. `Boolean`. Defaults to `false`. This can be set during construction, but you should use the `playAnimation()` and `stopAnimation()` methods to control animations after layer construction. | 150 | | `animationDuration` | See `setAnimationDuration()` method description below. | 151 | | `animationEasingFamily` | See `setAnimationEasing()` method description below. | 152 | | `animationEasingType` | See `setAnimationEasing()` method description below. | 153 | 154 | **`originAndDestinationFieldIds` example:** 155 | 156 | (This is also the default in the layer source code.) 157 | 158 | ```javascript 159 | // this is only a default option example, 160 | // developers will most likely need to provide this 161 | // options object with values unique to their data 162 | originAndDestinationFieldIds: { 163 | originUniqueIdField: 'origin_id', 164 | originGeometry: { 165 | x: 'origin_lon', 166 | y: 'origin_lat' 167 | }, 168 | destinationUniqueIdField: 'destination_id', 169 | destinationGeometry: { 170 | x: 'destination_lon', 171 | y: 'destination_lat' 172 | } 173 | } 174 | ``` 175 | 176 | **`style` example:** 177 | 178 | (This is also the default in the layer source code.) 179 | 180 | ```javascript 181 | style: function(geoJsonFeature) { 182 | // use leaflet's path styling options 183 | 184 | // since the GeoJSON feature properties are modified by the layer, 185 | // developers can rely on the "isOrigin" property to set different 186 | // symbols for origin vs destination CircleMarker stylings 187 | 188 | if (geoJsonFeature.properties.isOrigin) { 189 | return { 190 | renderer: canvasRenderer, // recommended to use your own L.canvas() 191 | radius: 5, 192 | weight: 1, 193 | color: 'rgb(195, 255, 62)', 194 | fillColor: 'rgba(195, 255, 62, 0.6)', 195 | fillOpacity: 0.6 196 | }; 197 | } else { 198 | return { 199 | renderer: canvasRenderer, 200 | radius: 2.5, 201 | weight: 0.25, 202 | color: 'rgb(17, 142, 170)', 203 | fillColor: 'rgb(17, 142, 170)', 204 | fillOpacity: 0.7 205 | }; 206 | } 207 | } 208 | ``` 209 | 210 | ### Method Summary 211 | 212 | | Method | Arguments | Description | 213 | | --- | --- | --- | 214 | | `selectFeaturesForPathDisplay( selectionFeatures, selectionMode )` | `selectionFeatures`: `Array` of origin or destination features already managed and displayed by the layer.

`selectionMode`: `String`. Valid values: `'SELECTION_NEW'`, `'SELECTION_ADD'`, or `'SELECTION_SUBTRACT'`. | This informs the layer which Bezier curves should be drawn on the map.

For example, you can most easily use this in conjunction with a `click` or `mouseover` event listener. | 215 | | `selectFeaturesForPathDisplayById( uniqueOriginOrDestinationIdField, idValue, originBoolean, selectionMode )` | | This is a convenience method if the unique origin or destination ID value is already known and you do not wish to rely on a `click` or `mouseover` event listener. | 216 | | `selectAllFeaturesForPathDisplay()` | | This informs the layer to select (and thus show) all Bezier curves. | 217 | | `clearAllPathSelections()` | | This informs the layer to unselect (and thus hide) all Bezier curves. | 218 | | `playAnimation()` | | This starts and shows Bezier curve animations. | 219 | | `stopAnimation()` | | This stops and hides any Bezier curve animations. | 220 | | `setAnimationDuration( duration )` | `duration`: _Optional_. `Number` in milliseconds. | This changes the animation duration. | 221 | | `setAnimationEasing( easingFamily, easingType )` | `easingFamily`: `String`.

`easingType`: `String`.

See `getAnimationEasingOptions()` method for info on valid values. | This changes the animation easing function with the help of the [tween.js library](https://github.com/tweenjs/tween.js). | 222 | | `getAnimationEasingOptions()` | | Returns information on valid `easingFamily` and `easingType` values based on the [tween.js library](https://github.com/tweenjs/tween.js). | 223 | 224 | ### Event Summary 225 | 226 | | Event | Description | 227 | | --- | --- | 228 | | `click` | Extends [layer `click`](http://leafletjs.com/reference-1.3.0.html#interactive-layer-click) and adds the following properties to the event object:

`isOriginFeature`: `true` if an origin point has been clicked, but `false` if a destination point has been clicked.

`sharedOriginFeatures`: `Array` of features that share the same origin.

`sharedDestinationFeatures`: `Array` of features that share the same destination. | 229 | | `mouseover` | Extends [layer `mouseover`](http://leafletjs.com/reference-1.3.0.html#interactive-layer-mouseover) and adds the following properties to the event object:

`isOriginFeature`: `true` when the mouse first entered an origin point, but `false` when the mouse first entered a destination point.

`sharedOriginFeatures`: `Array` of features that share the same origin.

`sharedDestinationFeatures`: `Array` of features that share the same destination. | 230 | 231 | ## Licensing 232 | 233 | A copy of the license is available in the repository's [LICENSE](./LICENSE) file. 234 | -------------------------------------------------------------------------------- /docs/class-breaks-symbology/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Canvas Flowmap Layer with LeafletJS 10 | 11 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /docs/comparison/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } -------------------------------------------------------------------------------- /docs/comparison/css/skeleton.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Skeleton V2.0.4 3 | * Copyright 2014, Dave Gamache 4 | * www.getskeleton.com 5 | * Free to use under the MIT license. 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * 12/29/2014 8 | */ 9 | 10 | 11 | /* Table of contents 12 | –––––––––––––––––––––––––––––––––––––––––––––––––– 13 | - Grid 14 | - Base Styles 15 | - Typography 16 | - Links 17 | - Buttons 18 | - Forms 19 | - Lists 20 | - Code 21 | - Tables 22 | - Spacing 23 | - Utilities 24 | - Clearing 25 | - Media Queries 26 | */ 27 | 28 | 29 | /* Grid 30 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 31 | .container { 32 | position: relative; 33 | width: 100%; 34 | max-width: 960px; 35 | margin: 0 auto; 36 | padding: 0 20px; 37 | box-sizing: border-box; } 38 | .column, 39 | .columns { 40 | width: 100%; 41 | float: left; 42 | box-sizing: border-box; } 43 | 44 | /* For devices larger than 400px */ 45 | @media (min-width: 400px) { 46 | .container { 47 | width: 85%; 48 | padding: 0; } 49 | } 50 | 51 | /* For devices larger than 550px */ 52 | @media (min-width: 550px) { 53 | .container { 54 | width: 80%; } 55 | .column, 56 | .columns { 57 | margin-left: 4%; } 58 | .column:first-child, 59 | .columns:first-child { 60 | margin-left: 0; } 61 | 62 | .one.column, 63 | .one.columns { width: 4.66666666667%; } 64 | .two.columns { width: 13.3333333333%; } 65 | .three.columns { width: 22%; } 66 | .four.columns { width: 30.6666666667%; } 67 | .five.columns { width: 39.3333333333%; } 68 | .six.columns { width: 48%; } 69 | .seven.columns { width: 56.6666666667%; } 70 | .eight.columns { width: 65.3333333333%; } 71 | .nine.columns { width: 74.0%; } 72 | .ten.columns { width: 82.6666666667%; } 73 | .eleven.columns { width: 91.3333333333%; } 74 | .twelve.columns { width: 100%; margin-left: 0; } 75 | 76 | .one-third.column { width: 30.6666666667%; } 77 | .two-thirds.column { width: 65.3333333333%; } 78 | 79 | .one-half.column { width: 48%; } 80 | 81 | /* Offsets */ 82 | .offset-by-one.column, 83 | .offset-by-one.columns { margin-left: 8.66666666667%; } 84 | .offset-by-two.column, 85 | .offset-by-two.columns { margin-left: 17.3333333333%; } 86 | .offset-by-three.column, 87 | .offset-by-three.columns { margin-left: 26%; } 88 | .offset-by-four.column, 89 | .offset-by-four.columns { margin-left: 34.6666666667%; } 90 | .offset-by-five.column, 91 | .offset-by-five.columns { margin-left: 43.3333333333%; } 92 | .offset-by-six.column, 93 | .offset-by-six.columns { margin-left: 52%; } 94 | .offset-by-seven.column, 95 | .offset-by-seven.columns { margin-left: 60.6666666667%; } 96 | .offset-by-eight.column, 97 | .offset-by-eight.columns { margin-left: 69.3333333333%; } 98 | .offset-by-nine.column, 99 | .offset-by-nine.columns { margin-left: 78.0%; } 100 | .offset-by-ten.column, 101 | .offset-by-ten.columns { margin-left: 86.6666666667%; } 102 | .offset-by-eleven.column, 103 | .offset-by-eleven.columns { margin-left: 95.3333333333%; } 104 | 105 | .offset-by-one-third.column, 106 | .offset-by-one-third.columns { margin-left: 34.6666666667%; } 107 | .offset-by-two-thirds.column, 108 | .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } 109 | 110 | .offset-by-one-half.column, 111 | .offset-by-one-half.columns { margin-left: 52%; } 112 | 113 | } 114 | 115 | 116 | /* Base Styles 117 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 118 | /* NOTE 119 | html is set to 62.5% so that all the REM measurements throughout Skeleton 120 | are based on 10px sizing. So basically 1.5rem = 15px :) */ 121 | html { 122 | font-size: 62.5%; } 123 | body { 124 | font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ 125 | line-height: 1.6; 126 | font-weight: 400; 127 | font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; 128 | color: #222; } 129 | 130 | 131 | /* Typography 132 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 133 | h1, h2, h3, h4, h5, h6 { 134 | margin-top: 0; 135 | margin-bottom: 2rem; 136 | font-weight: 300; } 137 | h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} 138 | h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } 139 | h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } 140 | h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } 141 | h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } 142 | h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } 143 | 144 | /* Larger than phablet */ 145 | @media (min-width: 550px) { 146 | h1 { font-size: 5.0rem; } 147 | h2 { font-size: 4.2rem; } 148 | h3 { font-size: 3.6rem; } 149 | h4 { font-size: 3.0rem; } 150 | h5 { font-size: 2.4rem; } 151 | h6 { font-size: 1.5rem; } 152 | } 153 | 154 | p { 155 | margin-top: 0; } 156 | 157 | 158 | /* Links 159 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 160 | a { 161 | color: #1EAEDB; } 162 | a:hover { 163 | color: #0FA0CE; } 164 | 165 | 166 | /* Buttons 167 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 168 | .button, 169 | button, 170 | input[type="submit"], 171 | input[type="reset"], 172 | input[type="button"] { 173 | display: inline-block; 174 | height: 38px; 175 | padding: 0 30px; 176 | color: #555; 177 | text-align: center; 178 | font-size: 11px; 179 | font-weight: 600; 180 | line-height: 38px; 181 | letter-spacing: .1rem; 182 | text-transform: uppercase; 183 | text-decoration: none; 184 | white-space: nowrap; 185 | background-color: transparent; 186 | border-radius: 4px; 187 | border: 1px solid #bbb; 188 | cursor: pointer; 189 | box-sizing: border-box; } 190 | .button:hover, 191 | button:hover, 192 | input[type="submit"]:hover, 193 | input[type="reset"]:hover, 194 | input[type="button"]:hover, 195 | .button:focus, 196 | button:focus, 197 | input[type="submit"]:focus, 198 | input[type="reset"]:focus, 199 | input[type="button"]:focus { 200 | color: #333; 201 | border-color: #888; 202 | outline: 0; } 203 | .button.button-primary, 204 | button.button-primary, 205 | input[type="submit"].button-primary, 206 | input[type="reset"].button-primary, 207 | input[type="button"].button-primary { 208 | color: #FFF; 209 | background-color: #33C3F0; 210 | border-color: #33C3F0; } 211 | .button.button-primary:hover, 212 | button.button-primary:hover, 213 | input[type="submit"].button-primary:hover, 214 | input[type="reset"].button-primary:hover, 215 | input[type="button"].button-primary:hover, 216 | .button.button-primary:focus, 217 | button.button-primary:focus, 218 | input[type="submit"].button-primary:focus, 219 | input[type="reset"].button-primary:focus, 220 | input[type="button"].button-primary:focus { 221 | color: #FFF; 222 | background-color: #1EAEDB; 223 | border-color: #1EAEDB; } 224 | 225 | 226 | /* Forms 227 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 228 | input[type="email"], 229 | input[type="number"], 230 | input[type="search"], 231 | input[type="text"], 232 | input[type="tel"], 233 | input[type="url"], 234 | input[type="password"], 235 | textarea, 236 | select { 237 | height: 38px; 238 | padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ 239 | background-color: #fff; 240 | border: 1px solid #D1D1D1; 241 | border-radius: 4px; 242 | box-shadow: none; 243 | box-sizing: border-box; } 244 | /* Removes awkward default styles on some inputs for iOS */ 245 | input[type="email"], 246 | input[type="number"], 247 | input[type="search"], 248 | input[type="text"], 249 | input[type="tel"], 250 | input[type="url"], 251 | input[type="password"], 252 | textarea { 253 | -webkit-appearance: none; 254 | -moz-appearance: none; 255 | appearance: none; } 256 | textarea { 257 | min-height: 65px; 258 | padding-top: 6px; 259 | padding-bottom: 6px; } 260 | input[type="email"]:focus, 261 | input[type="number"]:focus, 262 | input[type="search"]:focus, 263 | input[type="text"]:focus, 264 | input[type="tel"]:focus, 265 | input[type="url"]:focus, 266 | input[type="password"]:focus, 267 | textarea:focus, 268 | select:focus { 269 | border: 1px solid #33C3F0; 270 | outline: 0; } 271 | label, 272 | legend { 273 | display: block; 274 | margin-bottom: .5rem; 275 | font-weight: 600; } 276 | fieldset { 277 | padding: 0; 278 | border-width: 0; } 279 | input[type="checkbox"], 280 | input[type="radio"] { 281 | display: inline; } 282 | label > .label-body { 283 | display: inline-block; 284 | margin-left: .5rem; 285 | font-weight: normal; } 286 | 287 | 288 | /* Lists 289 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 290 | ul { 291 | list-style: circle inside; } 292 | ol { 293 | list-style: decimal inside; } 294 | ol, ul { 295 | padding-left: 0; 296 | margin-top: 0; } 297 | ul ul, 298 | ul ol, 299 | ol ol, 300 | ol ul { 301 | margin: 1.5rem 0 1.5rem 3rem; 302 | font-size: 90%; } 303 | li { 304 | margin-bottom: 1rem; } 305 | 306 | 307 | /* Code 308 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 309 | code { 310 | padding: .2rem .5rem; 311 | margin: 0 .2rem; 312 | font-size: 90%; 313 | white-space: nowrap; 314 | background: #F1F1F1; 315 | border: 1px solid #E1E1E1; 316 | border-radius: 4px; } 317 | pre > code { 318 | display: block; 319 | padding: 1rem 1.5rem; 320 | white-space: pre; } 321 | 322 | 323 | /* Tables 324 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 325 | th, 326 | td { 327 | padding: 12px 15px; 328 | text-align: left; 329 | border-bottom: 1px solid #E1E1E1; } 330 | th:first-child, 331 | td:first-child { 332 | padding-left: 0; } 333 | th:last-child, 334 | td:last-child { 335 | padding-right: 0; } 336 | 337 | 338 | /* Spacing 339 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 340 | button, 341 | .button { 342 | margin-bottom: 1rem; } 343 | input, 344 | textarea, 345 | select, 346 | fieldset { 347 | margin-bottom: 1.5rem; } 348 | pre, 349 | blockquote, 350 | dl, 351 | figure, 352 | table, 353 | p, 354 | ul, 355 | ol, 356 | form { 357 | margin-bottom: 2.5rem; } 358 | 359 | 360 | /* Utilities 361 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 362 | .u-full-width { 363 | width: 100%; 364 | box-sizing: border-box; } 365 | .u-max-full-width { 366 | max-width: 100%; 367 | box-sizing: border-box; } 368 | .u-pull-right { 369 | float: right; } 370 | .u-pull-left { 371 | float: left; } 372 | 373 | 374 | /* Misc 375 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 376 | hr { 377 | margin-top: 3rem; 378 | margin-bottom: 3.5rem; 379 | border-width: 0; 380 | border-top: 1px solid #E1E1E1; } 381 | 382 | 383 | /* Clearing 384 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 385 | 386 | /* Self Clearing Goodness */ 387 | .container:after, 388 | .row:after, 389 | .u-cf { 390 | content: ""; 391 | display: table; 392 | clear: both; } 393 | 394 | 395 | /* Media Queries 396 | –––––––––––––––––––––––––––––––––––––––––––––––––– */ 397 | /* 398 | Note: The best way to structure the use of media queries is to create the queries 399 | near the relevant code. For example, if you wanted to change the styles for buttons 400 | on small devices, paste the mobile query code up in the buttons section and style it 401 | there. 402 | */ 403 | 404 | 405 | /* Larger than mobile */ 406 | @media (min-width: 400px) {} 407 | 408 | /* Larger than phablet (also point when grid becomes active) */ 409 | @media (min-width: 550px) {} 410 | 411 | /* Larger than tablet */ 412 | @media (min-width: 750px) {} 413 | 414 | /* Larger than desktop */ 415 | @media (min-width: 1000px) {} 416 | 417 | /* Larger than Desktop HD */ 418 | @media (min-width: 1200px) {} 419 | -------------------------------------------------------------------------------- /docs/comparison/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Canvas Flowmap Layer with LeafletJS 10 | 11 | 12 | 13 | 14 | 15 | 16 | 87 | 88 | 89 | 90 | 91 | 92 |
93 | 94 |
95 | 96 |
97 | 98 |

Canvas Flowmap Layer

99 | 100 |

101 | Explore origin-to-destination layers with different relationships: 102 |

103 | 104 | 105 | 106 | 107 |

108 | Change animation properties: 109 |

110 |
111 |
112 | 113 |
114 |
115 | 116 |
117 |
118 | 119 | 123 | 124 |

125 | Change user interaction and path selection properties: 126 |

127 |
128 |
129 | 133 |
134 |
135 | 140 |
141 |
142 | 143 |
144 |
145 | 146 |
147 |
148 | 149 |
150 |
151 |
152 | 153 |
154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 372 | 373 | 374 | 375 | -------------------------------------------------------------------------------- /docs/csv-data/Flowmap_Cities_one_to_many.csv: -------------------------------------------------------------------------------- 1 | s_city_id,s_city,s_lat,s_lon,s_pop,s_country,s_Volume,e_city_id,e_City,e_lat,e_lon,e_pop,e_country,e_vol 2 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,1,Sarh,9.149969909,18.39002966,135862,Chad,1 3 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,2,Tandil,-37.32001015,-59.15004358,84799.5,Argentina,1 4 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,3,Victorville,34.5365082,-117.2903191,83496,United States of America,1 5 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,4,Cranbourne,-38.09960081,145.2833695,249955,Australia,1 6 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,5,Curico,-34.97999795,-71.24002914,108074.5,Chile,1 7 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,6,Dahuk,36.86670013,43.00000263,620500,Iraq,1 8 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,7,Olympia,47.03804486,-122.899434,100950,United States of America,1 9 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,8,Oostanay,53.22089744,63.62830196,223450.5,Kazakhstan,1 10 | 238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,9,Oran,35.71000246,-0.61997278,721992,Algeria,1 11 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,10,Asheville,35.60119773,-82.55414474,105775,United States of America,1 12 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,11,Asti,44.92998232,8.209979206,63410.5,Italy,1 13 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,12,Athens,33.96129783,-83.3780221,78017.5,United States of America,1 14 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,13,Atlanta,33.83001385,-84.39994938,2464454,United States of America,1 15 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,14,Atyrau,47.11269147,51.92002437,170583,Kazakhstan,1 16 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,15,Aurora,41.76539512,-88.29999557,273949.5,United States of America,1 17 | 623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,16,Babruysk,53.12656211,29.19278113,212821.5,Belarus,1 18 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,17,Ballarat,-37.55958209,143.8400468,73404,Australia,1 19 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,18,Barnaul,53.35499778,83.74500688,569711,Russia,1 20 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,19,Lanzhou,36.05602785,103.7920003,2282609,China,1 21 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,20,L'Aquila,42.35039817,13.39002478,62201.5,Italy,1 22 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,21,Larache,35.20042116,-6.160022218,114688,Morocco,1 23 | 222,Haifa,32.8204114,34.98002478,639150,Israel,400017,22,Le Mans,48.00041506,0.099983275,143392.5,France,1 24 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,23,Elkhart,41.68294537,-85.96879419,100295,United States of America,1 25 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,24,Encarnacion,-27.34718482,-55.87391878,251813.5,Paraguay,1 26 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,25,Erechim,-27.63000731,-52.26999841,85365.5,Brazil,1 27 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,26,Everett,47.9604175,-122.1999677,291948,United States of America,1 28 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,27,Exeter,50.70040529,-3.529950197,108242,United Kingdom,1 29 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,28,Faisalabad,31.40998069,73.10999711,2561797.5,Pakistan,1 30 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,29,Fargo,46.8772278,-96.7894257,127472.5,United States of America,1 31 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,30,Fayetteville,36.06297833,-94.15720911,108267.5,United States of America,1 32 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,31,Florianopolis,-27.57998452,-48.52002059,568783,Brazil,1 33 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,32,Fort Pierce,27.44678591,-80.3258053,132984,United States of America,1 34 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,33,Fort Wayne,41.08039817,-85.12998234,264793,United States of America,1 35 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,34,Fresno,36.7477169,-119.7729841,540768,United States of America,1 36 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,35,Ft. Myers,26.64029767,-81.86049199,120810.5,United States of America,1 37 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,36,Fukui,36.07041974,136.2200468,241288.5,Japan,1 38 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,37,Furth,49.47001528,10.99998979,174934.5,Germany,1 39 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,38,Gävle,60.66698041,17.1666418,68235.5,Sweden,1 40 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,39,Galway,53.272393,-9.048812298,73140,Ireland,1 41 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,40,Ganca,40.68499595,46.35002844,301699.5,Azerbaijan,1 42 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,41,Ganzhou,25.91997988,114.9500272,1216134.5,China,1 43 | 657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,42,Garissa,-0.439625632,39.67002274,65948,Kenya,1 44 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,43,Chengdu,30.67000002,104.0700195,4036718.5,China,1 45 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,44,Chester,53.20002016,-2.919987428,83285.5,United Kingdom,1 46 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,45,Chihuahua,28.64498151,-106.0849823,750633.5,Mexico,1 47 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,46,Chita,52.05502545,113.4650016,293153.5,Russia,1 48 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,47,Chlef,36.17041363,1.319960489,449167,Algeria,1 49 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,48,Daytona Beach,29.21055422,-81.0230754,140775.5,United States of America,1 50 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,49,Denton,33.21576194,-97.12883651,138952.5,United States of America,1 51 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,50,Detroit,42.32996014,-83.08005579,2526135,United States of America,1 52 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,51,Divinopolis,-20.14953367,-44.89998316,181457,Brazil,1 53 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,52,Dondo,-19.61959186,34.7300142,75217.5,Mozambique,1 54 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,53,Dongguan,23.0488889,113.7447222,4528000,China,1 55 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,54,Dresden,51.04997052,13.75000281,552184.5,Germany,1 56 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,55,Drohobych,49.34436403,23.49938188,101837.5,Ukraine,1 57 | 262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,56,Dublin,53.33306114,-6.248905682,1013988,Ireland,1 58 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,57,Beirut,33.87197512,35.50970821,1779062.5,Lebanon,1 59 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,58,Linhares,-19.38999347,-40.05002079,86413,Brazil,1 60 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,59,Linköping,58.41001223,15.62993974,94111.5,Sweden,1 61 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,60,Linyi,35.07998924,118.329976,1176334.5,China,1 62 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,61,Liverpool,53.41600181,-2.917997886,639972.5,United Kingdom,1 63 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,62,Lobito,-12.37000853,13.54123002,170733,Angola,1 64 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,63,Logrono,42.47036501,-2.429991497,123918.5,Spain,1 65 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,64,Londonderry,55.00037539,-7.333283937,82635,United Kingdom,1 66 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,65,Lorient,47.75040448,-3.366575156,71532,France,1 67 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,66,Los Angeles,-37.46000161,-72.35998661,135334.5,Chile,1 68 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,67,Louangphrabang,19.88453432,102.1416101,77260,Laos,1 69 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,68,Lujan,-34.57960895,-59.10999435,69744.5,Argentina,1 70 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,69,Santiago del Estero,-27.78333128,-64.26665633,317549.5,Argentina,1 71 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,70,Junin,-34.58456989,-60.95887374,66141.5,Argentina,1 72 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,71,Kagoshima,31.58596478,130.561064,536092.5,Japan,1 73 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,72,Kakamega,0.290407327,34.7300142,63426,Kenya,1 74 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,73,Kalamata,37.03891359,22.11419511,61465.5,Greece,1 75 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,74,Kalamazoo,42.29215883,-85.58718958,128759.5,United States of America,1 76 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,75,Kamensk Uralskiy,56.42046958,61.9350203,176598.5,Russia,1 77 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,76,Kampong Cham,12.00044191,105.4500386,72491.5,Cambodia,1 78 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,77,Kamyanets-Podilskyy,48.68430096,26.58089921,107329,Ukraine,1 79 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,78,Kamyshin,50.08039146,45.40000891,82613,Russia,1 80 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,79,Kanazawa,36.56000226,136.6400211,505093,Japan,1 81 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,80,Kanoya,31.38331565,130.8500386,68513.5,Japan,1 82 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,81,Rostock,54.07038047,12.14999711,200686.5,Germany,1 83 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,82,Skopje,42.00000612,21.43346147,484488,Macedonia,1 84 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,83,Townsville,-19.24995034,146.7699971,129212,Australia,1 85 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,84,Szekesfehervar,47.19467613,18.40806474,122959.5,Hungary,1 86 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,85,Van,38.49543968,43.39997595,326262,Turkey,1 87 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,86,Mainz,49.98247246,8.273219156,184997,Germany,1 88 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,87,Maizuru,35.4504059,135.3333309,62531.5,Japan,1 89 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,88,Makkah,21.43002138,39.82003943,1354312,Saudi Arabia,1 90 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,89,Malacca,2.206414407,102.2464615,645916.5,Malaysia,1 91 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,90,Maladzyechna,54.31878908,26.86532629,96055,Belarus,1 92 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,91,Malanje,-9.540000388,16.34002559,106451,Angola,1 93 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,92,Male,4.16670819,73.49994747,108310,Maldives,1 94 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,93,Santo Domingo,18.47007285,-69.90008508,1078436.5,Dominican Republic,1 95 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,94,Takamatsu,34.34473696,134.044779,329861.5,Japan,1 96 | 183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,95,Velikiy Novgorod,58.4999809,31.33001501,218717,Russia,1 97 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,96,Mar del Plata,-38.00002033,-57.57998438,554916,Argentina,1 98 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,97,Marbella,36.51661989,-4.88333012,153069.5,Spain,1 99 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,98,Marietta,33.95561342,-84.54324813,61360,United States of America,1 100 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,99,Maseru,-29.31667438,27.48327307,239839.5,Lesotho,1 101 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,100,Masvingo,-20.05961668,30.8200203,76300.5,Zimbabwe,1 102 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,101,Mataro,41.53995668,2.45002071,149826,Spain,1 103 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,102,Matsue,35.46699404,133.0666475,150527,Japan,1 104 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,103,Matsumoto,36.2404352,137.9700175,217796.5,Japan,1 105 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,104,Matsuyama,33.84554262,132.765839,525089,Japan,1 106 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,105,Medenine,33.399999,10.41669956,61705,Tunisia,1 107 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,106,Medina,24.49998903,39.5800024,1010000,Saudi Arabia,1 108 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,107,Melbourne,28.08331036,-80.60832035,170870,United States of America,1 109 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,108,Melbourne,-37.82003131,144.9750162,2131812.5,Australia,1 110 | 579,Rome,41.89595563,12.48325842,1687226,Italy,800446,109,Metairie,29.98386619,-90.15277653,270171,United States of America,1 111 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,110,Tacoma,47.21131594,-122.5150131,460273,United States of America,1 112 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,111,Vancouver,49.27341658,-123.1216442,1458415,Canada,1 113 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,112,Columbia,38.95207847,-92.33390955,244754,United States of America,1 114 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,113,Adapazari,40.79997601,30.4150321,260109,Turkey,1 115 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,114,Adelaide,-34.93498777,138.6000048,990677,Australia,1 116 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,115,Aguascalientes,21.87945992,-102.2904135,763589.5,Mexico,1 117 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,116,Akron,41.07039878,-81.51999597,451155,United States of America,1 118 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,117,Al Ahmadi,29.0769448,48.08377274,68763,Kuwait,1 119 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,118,Al Jahra,29.33747154,47.6580623,194193,Kuwait,1 120 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,119,Albacete,39.00034426,-1.869999839,127597,Spain,1 121 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,120,Albany,42.67001691,-73.81994918,484286,United States of America,1 122 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,1,Alexandria,38.82043276,-77.09998153,127273,United States of America,1 123 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,122,Algeciras,36.12671215,-5.466530363,106687.5,Spain,1 124 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,123,Algiers,36.7630648,3.05055253,2665831.5,Algeria,1 125 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,124,Allentown,40.59998822,-75.50002751,300980.5,United States of America,1 126 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,125,Gisenyi,-1.684665915,29.26290605,83623,Rwanda,1 127 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,126,Gitarama,-2.069603659,29.75998165,87613,Rwanda,1 128 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,127,Gliwice,50.3303762,18.67001257,353252.5,Poland,1 129 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,128,Gold Coast,-28.08150429,153.4482458,429954.5,Australia,1 130 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,129,Goya,-29.13999266,-59.26998458,71274.5,Argentina,1 131 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,130,Graz,47.0777582,15.41000484,242780,Austria,1 132 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,131,Great Falls,47.50029055,-111.299987,61316.5,United States of America,1 133 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,132,Greeley,40.41919822,-104.739974,106142.5,United States of America,1 134 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,133,Greensboro,36.07000633,-79.80002344,310328,United States of America,1 135 | 103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,134,Greenville,35.61287661,-77.3666836,81661,United States of America,1 136 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,135,San Pedro de Macoris,18.4503583,-69.29996668,211019.5,Dominican Republic,1 137 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,136,Stockton,37.95813397,-121.289739,488506.5,United States of America,1 138 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,137,Usti Nad Labem,50.66299816,14.08100455,94105,Czech Republic,1 139 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,138,Mexicali,32.64998252,-115.4800161,736138.5,Mexico,1 140 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,139,Middlesbrough,54.58037518,-1.230013063,279374.5,United Kingdom,1 141 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,140,Midland,32.030718,-102.0974996,98141.5,United States of America,1 142 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,141,Mito,36.37042727,140.4800451,300215,Japan,1 143 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,142,Moca,19.39699814,-70.52300059,61834,Dominican Republic,1 144 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,143,Modesto,37.65541343,-120.9899899,269697,United States of America,1 145 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,144,Mombasa,-4.040026022,39.68991817,840834,Kenya,1 146 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,145,Rio Largo,-9.48000405,-35.83996769,110966,Brazil,1 147 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,146,Shenzhen,22.55237051,114.1221231,4291796,China,1 148 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,147,Toowoomba,-27.56453327,151.9555204,86711,Australia,1 149 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,148,Santa Fe,35.68692893,-105.9372394,80943,United States of America,1 150 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,149,Svobodnyy,51.40617617,128.1311865,62318.5,Russia,1 151 | 373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,150,Utsunomiya,36.54997703,139.8700048,558808.5,Japan,1 152 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,151,Salerno,40.68039675,14.76994055,546922,Italy,1 153 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,152,St. Cloud,45.56120994,-94.16222172,85974,United States of America,1 154 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,153,Tuzla,44.5504706,18.6800378,143410,Bosnia and Herzegovina,1 155 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,154,Kitami,43.8503583,143.8999914,103971.5,Japan,1 156 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,155,Kitchener,43.44999514,-80.50000655,413056.5,Canada,1 157 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,156,Klagenfurt,46.62034426,14.3100203,88588,Austria,1 158 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,157,Klerksdorp,-26.88002724,26.62001827,163362.5,South Africa,1 159 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,158,Koblenz,50.35047833,7.599990599,209976,Germany,1 160 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,159,Kofu,35.6503937,138.5833134,193770,Japan,1 161 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,160,Kokshetau,53.29998822,69.41998979,126658.5,Kazakhstan,1 162 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,161,Kolpino,59.73000917,30.65000484,180938.5,Russia,1 163 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,162,Kolwezi,-10.71672443,25.47243974,418000,Congo (Kinshasa),1 164 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,163,Kompong Chhnang,12.25047833,104.6666239,65817,Cambodia,1 165 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,164,Konotop,51.24238771,33.20902177,97672.5,Ukraine,1 166 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,165,Koriyama,37.40997622,140.3799996,302581,Japan,1 167 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,166,Koudougou,12.25047833,-2.369995159,85339,Burkina Faso,1 168 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,167,Kraków,50.05997927,19.96001135,755525,Poland,1 169 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,168,Kroonstad,-27.66003131,27.2100081,88413.5,South Africa,1 170 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,169,Ksar El Kebir,35.02038047,-5.909985801,207676.5,Morocco,1 171 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,170,Kuala Lumpur,3.166665872,101.6999833,1448000,Malaysia,1 172 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,171,Kuopio,62.89428632,27.69493974,90502,Finland,1 173 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,172,Ceuta,35.88898378,-5.30699935,78674,Spain,1 174 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,173,Chalkida,38.46399457,23.61239823,63200,Greece,1 175 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,174,Changde,29.02999676,111.6800459,993390,China,1 176 | 237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,175,Charlottesville,38.02918907,-78.47692591,61314,United States of America,1 177 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,176,Helsingborg,56.05049217,12.70004106,91164.5,Sweden,1 178 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,177,Higuey,18.61599603,-68.70799749,123787,Dominican Republic,1 179 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,178,Hinthada,17.64826255,95.46785722,157837.5,Myanmar,1 180 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,179,Hirosaki,40.56999005,140.4700199,171700.5,Japan,1 181 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,180,Honiara,-9.437994295,159.9497657,66313,Solomon Islands,1 182 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,181,Hradec Kralove,50.20599617,15.81200153,95195,Czech Republic,1 183 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,182,Huanuco,-9.920028871,-76.24000818,153052,Peru,1 184 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,183,Huaraz,-9.530026836,-77.53000696,74986.5,Peru,1 185 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,184,Huelva,37.25037355,-6.929949383,119732,Spain,1 186 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,185,Ioanina,39.66790041,20.85086137,75158,Greece,1 187 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,186,Iowa City,41.66108624,-91.52997929,81343,United States of America,1 188 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,187,Ipatinga,-19.4796004,-42.51999923,318320,Brazil,1 189 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,188,Rock Island,41.49339622,-90.53461369,102055.5,United States of America,1 190 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,189,Sivas,39.74541506,37.03498979,245801.5,Turkey,1 191 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,190,Toulon,43.13418645,5.918821566,263197,France,1 192 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,191,Borisoglebsk,51.36871075,42.08873816,64995,Russia,1 193 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,192,Boston,42.32996014,-71.07001367,2528070.5,United States of America,1 194 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,193,Boulder,40.03844627,-105.246093,106897.5,United States of America,1 195 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,194,Butare,-2.589623597,29.73000932,77000,Rwanda,1 196 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,195,Bydgoszcz,53.12041262,18.01000118,366222,Poland,1 197 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,196,Bytom,50.35003908,18.90999792,425716.5,Poland,1 198 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,197,Caxias do Sul,-29.17999022,-51.17003972,377580.5,Brazil,1 199 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,198,Cerro de Pasco,-10.69000771,-76.26998051,108071,Peru,1 200 | 276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,199,Ceske Budejovice,48.98001935,14.46003699,97452,Czech Republic,1 201 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,200,Hyderabad,25.379987,68.37498897,1422665,Pakistan,1 202 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,201,Iligan,8.171244119,124.2153531,464599,Philippines,1 203 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,202,Iloilo,10.70504295,122.5450158,387681,Philippines,1 204 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,203,Kupang,-10.17866941,123.5829886,270798,Indonesia,1 205 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,204,Kure,34.25097007,132.5655928,196807.5,Japan,1 206 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,205,Kushiro,42.97495953,144.3746911,191089,Japan,1 207 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,206,Kuwait,29.36971763,47.97830115,1061532,Kuwait,1 208 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,207,Kuznetsk,53.12041262,46.59998734,93027,Russia,1 209 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,208,Kwekwe,-18.92960814,29.79997921,80788,Zimbabwe,1 210 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,209,La Plata,-34.90961465,-57.95996118,440388.5,Argentina,1 211 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,210,La Rioja,-29.40995034,-66.84996118,147130,Argentina,1 212 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,211,Riyadh,24.64083315,46.77274166,4335480.5,Saudi Arabia,1 213 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,212,Rzeszow,50.07046958,22.00004187,202034,Poland,1 214 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,213,Siauliai,55.93863853,23.32502559,132057.5,Lithuania,1 215 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,214,Sonsonate,13.7199752,-89.7299858,139724,El Salvador,1 216 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,215,Toronto,43.69997988,-79.42002079,4573710.5,Canada,1 217 | 562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,216,Tripoli,32.89250002,13.18001176,1209199,Libya,1 218 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,217,Chimoio,-19.12003579,33.47003943,242538.5,Mozambique,1 219 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,218,Clarksville,36.5300816,-87.35943282,122115,United States of America,1 220 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,219,Duluth,46.78333173,-92.10637822,82026.5,United States of America,1 221 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,220,Ipswich,52.07034751,1.169995482,139012,United Kingdom,1 222 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,221,Iquique,-20.24999266,-70.12996769,223012,Chile,1 223 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,222,Irkutsk,52.31997052,104.2450476,572325,Russia,1 224 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,223,Luxembourg,49.61166038,6.130002806,91972,Luxembourg,1 225 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,224,Lysychansk,48.92041058,38.42735958,118010.5,Ukraine,1 226 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,225,Macau,22.20299746,113.5450484,568700,Macau S.A.R,1 227 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,226,Machakos,-1.509534486,37.25998897,88448,Kenya,1 228 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,227,Macon,32.85038373,-83.63004806,104932.5,United States of America,1 229 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,228,Maebashi,36.39269981,139.0726892,313791,Japan,1 230 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,229,Magnitogorsk,53.42269391,58.98000688,308724.5,Russia,1 231 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,230,Nürnberg,49.44999066,11.0799849,618270.5,Germany,1 232 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,231,Naga,13.61915448,123.1813594,458283,Philippines,1 233 | 389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,232,Nagaoka,37.45041302,138.8600406,187560,Japan,1 234 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,233,Rio Branco,-9.966589336,-67.80000655,257642,Brazil,1 235 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,234,Shenyeng,41.80497927,123.4499735,4149596,China,1 236 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,235,Tomakomai,42.6504057,141.5500057,161355.5,Japan,1 237 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,236,Santa Cruz,36.97194629,-122.0263904,101530.5,United States of America,1 238 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,237,Sucre,-19.04097085,-65.25951563,223287,Bolivia,1 239 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,238,Utica,43.10117922,-75.23306706,81870,United States of America,1 240 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,239,Nakuru,-0.279997132,36.06998409,312315,Kenya,1 241 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,240,Namur,50.47039349,4.870028034,97155.5,Belgium,1 242 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,241,Nanjing,32.05001914,118.7799743,3383005,China,1 243 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,242,National City,32.67194501,-117.0980052,104291,United States of America,1 244 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,243,Nazareth,32.70398439,35.2955094,108129.5,Israel,1 245 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,244,New Albany,38.3108773,-85.82128382,78381.5,United States of America,1 246 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,245,New London,41.3555235,-72.10002832,61236,United States of America,1 247 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,246,New Orleans,29.99500246,-90.03996688,527428.5,United States of America,1 248 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,247,Niagara Falls,43.09482302,-79.0369434,117567,United States of America,1 249 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,248,Niigata,37.91999676,139.0400297,537534.5,Japan,1 250 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,249,Nizhnekamsk,55.64043968,51.82003048,210363,Russia,1 251 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,250,Nizhyn,51.0540788,31.89029089,95893.5,Ukraine,1 252 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,251,Noginsk,64.48331077,91.23333533,229731,Russia,1 253 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,252,Noginsk,55.87042564,38.48001786,172855,Russia,1 254 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,253,Norman,35.22791302,-97.34414636,113525,United States of America,1 255 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,254,Norrköping,58.59542727,16.17869177,85771,Sweden,1 256 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,255,Norwich,52.63036501,1.300013386,184196,United Kingdom,1 257 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,256,Nova Lima,-19.98003497,-43.8500214,60413.5,Brazil,1 258 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,257,Novo Hamburgo,-29.70962197,-51.13998987,557017,Brazil,1 259 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,258,Santa Cruz do Sul,-29.71003538,-52.44003972,109869,Brazil,1 260 | 489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,259,Sunderland,54.92001853,-1.380029746,315449.5,United Kingdom,1 261 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,260,Monrovia,6.31055666,-10.80475163,913331,Liberia,1 262 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,261,Monterey,36.6002582,-121.8935781,77297.5,United States of America,1 263 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,262,Montevideo,-34.85804157,-56.17105229,759162,Uruguay,1 264 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,263,Montréal,45.49999921,-73.58329696,3017278,Canada,1 265 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,264,Monywa,22.1049931,95.14999548,204116.5,Myanmar,1 266 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,265,Morioka,39.72001609,141.1300313,294782.5,Japan,1 267 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,266,Mtwara,-10.26961994,40.18999101,91674,Tanzania,1 268 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,267,Mudangiang,44.57501691,129.5900122,954957.5,China,1 269 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,268,Multan,30.19997703,71.45500769,1479615,Pakistan,1 270 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,269,Murfreesboro,35.84596315,-86.39026717,100237,United States of America,1 271 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,270,Curepipe,-20.31619017,57.51663367,192087.5,Mauritius,1 272 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,271,Brest,48.39044293,-4.49500757,142914,France,1 273 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,272,Sakarya,40.76666114,30.40000251,286787,Turkey,1 274 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,273,Spartanburg,34.94942873,-81.93227055,81059,United States of America,1 275 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,274,Tucumán,-26.81600014,-65.21662419,678803.5,Argentina,1 276 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,275,Salavat,53.37034568,55.92996049,111648,Russia,1 277 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,276,Springfield,39.82000999,-89.65001652,125345,United States of America,1 278 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,277,Tuscaloosa,33.22511538,-87.54417607,100594.5,United States of America,1 279 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,278,Capenda-Camulemba,-9.4195943,18.43002722,79842.5,Angola,1 280 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,279,Rochester,43.17042564,-77.61994979,483177,United States of America,1 281 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,280,Sittwe,20.13999676,92.88000484,178387.5,Myanmar,1 282 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,281,Tottori,35.50037701,134.2332946,142635.5,Japan,1 283 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,282,Cotonou,6.400008564,2.519990599,726292,Benin,1 284 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,283,Council Bluffs,41.26227338,-95.86080021,80284.5,United States of America,1 285 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,284,Coventry,52.42040367,-1.499996583,348292,United Kingdom,1 286 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,285,Geelong,-38.16749505,144.3956335,149336,Australia,1 287 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,286,Gent,51.02999758,3.700021931,337914.5,Belgium,1 288 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,287,George,-33.95003497,22.45004024,143915,South Africa,1 289 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,288,Kara Balta,42.83062726,73.88566036,68464.5,Kyrgyzstan,1 290 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,289,Karakol,42.49204327,78.38182003,63411.5,Kyrgyzstan,1 291 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,290,Karlstad,59.36713727,13.49994055,66703.5,Sweden,1 292 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,291,Kasama,-10.19959837,31.17994665,156500,Zambia,1 293 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,292,Katowice,50.26038047,19.02001705,1527362,Poland,1 294 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,293,Kaunas,54.95040428,23.88003048,363844.5,Lithuania,1 295 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,294,Kayes,14.44998232,-11.44001001,77207,Mali,1 296 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,295,Kayseri,38.73495994,35.49001949,562215.5,Turkey,1 297 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,296,Kecskemet,46.90004295,19.70002722,111871,Hungary,1 298 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,297,Kelang,3.020369892,101.5500183,917933.5,Malaysia,1 299 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,298,Kelowna,49.89998903,-119.4833118,110207.5,Canada,1 300 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,299,Kendu Bay,-0.359578838,34.63999385,91248,Kenya,1 301 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,300,Kericho,-0.359578838,35.28000647,67300,Kenya,1 302 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,301,Kharkiv,49.99998293,36.25002478,1338063.5,Ukraine,1 303 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,302,Khaskovo,41.94378216,25.5632869,72805,Bulgaria,1 304 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,303,Kiev,50.43336733,30.51662797,2185754,Ukraine,1 305 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,304,Otaru,43.18871909,140.9783093,139260.5,Japan,1 306 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,305,Pasay City,14.5504413,120.9999939,403064,Philippines,1 307 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,306,Corrientes,-27.48996417,-58.80998682,339945,Argentina,1 308 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,307,Corumba,-19.01601113,-57.65000594,70035.5,Brazil,1 309 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,308,Eindhoven,51.42997316,5.50001542,303836.5,Netherlands,1 310 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,309,El Jadida,33.2603587,-8.509982138,164009.5,Morocco,1 311 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,310,Santa Maria,-29.68331867,-53.80000838,239211.5,Brazil,1 312 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,311,Syzran,53.16999615,48.47997595,171589,Russia,1 313 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,312,Valdivia,-39.7950012,-73.24502303,146509,Chile,1 314 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,313,San Francisco,37.74000775,-122.4599777,2091036,United States of America,1 315 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,314,Stavanger,58.97000389,5.680004434,136999,Norway,1 316 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,315,Upington,-28.46003416,21.23001135,62086,South Africa,1 317 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,316,Rybinsk,58.05034426,38.81999711,203874.5,Russia,1 318 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,317,Songea,-10.68003416,35.65000972,120923,Tanzania,1 319 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,318,Trablous,34.42000368,35.8699963,361286,Lebanon,1 320 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,319,Coquimbo,-29.95291461,-71.34361454,159082.5,Chile,1 321 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,320,Santiago de Compostela,42.88289797,-8.541091351,87721,Spain,1 322 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,321,Szczecin,53.42039431,14.53000688,390241.5,Poland,1 323 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,322,Vallejo,38.11194887,-122.258052,133367.5,United States of America,1 324 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,323,Edinburg,26.30318646,-98.1599622,114573.5,United States of America,1 325 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,324,Muroran,42.34995892,140.9800146,125936.5,Japan,1 326 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,325,Mutare,-18.97001911,32.6500378,216785,Zimbabwe,1 327 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,326,Myeik,12.45408347,98.61148962,220009,Myanmar,1 328 | 35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,327,Santo Angelo,-28.30004393,-54.28003076,65013,Brazil,1 329 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,328,Otsu,35.006402,135.8674068,437802.5,Japan,1 330 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,329,Ouagadougou,12.37031598,-1.524723756,992228.5,Burkina Faso,1 331 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,330,Oulu,64.99999758,25.47001094,132685,Finland,1 332 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,331,Ovalle,-30.59003335,-71.20005742,72984,Chile,1 333 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,332,Pakxe,15.12206016,105.8183365,95553.5,Laos,1 334 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,333,Palmerston North,-40.35269326,175.6072033,66551.5,New Zealand,1 335 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,334,Passos,-20.71001626,-46.60998214,85136.5,Brazil,1 336 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,335,Paulo Afonso,-9.330659161,-38.26565943,85350,Brazil,1 337 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,336,Pec,42.66032757,20.3107393,93481.5,Kosovo,1 338 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,337,Penza,53.18002138,44.99998165,491943,Russia,1 339 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,338,Pereira,4.81038983,-75.67999068,504434,Colombia,1 340 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,339,Peterborough,52.58041974,-0.249995363,140141,United Kingdom,1 341 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,340,Scarborough,54.28039349,-0.429984376,70571,United Kingdom,1 342 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,341,Temirtau,50.06501772,72.96499304,167193.5,Kazakhstan,1 343 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,342,Vitória,-20.32399331,-40.36599634,1008328,Brazil,1 344 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,343,Cartagena,10.39973859,-75.51439356,887000,Colombia,1 345 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,344,Schenectady,42.81458173,-73.93996769,104767.5,United States of America,1 346 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,345,Temuco,-38.73000161,-72.57999903,252015,Chile,1 347 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,346,Volsk,52.03471661,47.37430701,62027,Russia,1 348 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,347,Badajoz,38.8804291,-6.96997278,115638.5,Spain,1 349 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,348,Richmond,37.55001935,-77.449986,551443,United States of America,1 350 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,349,Savannakhet,16.53758099,104.772974,75725.5,Laos,1 351 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,350,Shangqiu,34.45041526,115.6500362,967109,China,1 352 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,351,Taza,34.22037762,-4.019971966,170761.5,Morocco,1 353 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,352,Tokushima,34.06738955,134.5525,355552.5,Japan,1 354 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,353,Visalia,36.32502952,-119.3160094,114699.5,United States of America,1 355 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,354,Daqing,46.57995913,125.0000081,948244,China,1 356 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,355,Darwin,-12.42535398,130.8500386,82973,Australia,1 357 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,356,Dayton,39.750376,-84.19998743,466067,United States of America,1 358 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,357,Ordu,41.00042889,37.8699259,135952.5,Turkey,1 359 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,358,Orsk,51.21001243,58.62731523,159353,Russia,1 360 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,359,Osh,40.54040529,72.79001664,295638.5,Kyrgyzstan,1 361 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,360,Oskemen,49.99003522,82.61494665,284350.5,Kazakhstan,1 362 | 1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,361,Osnabrück,52.28043805,8.049988972,198865,Germany,1 363 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,362,Groningen,53.22040651,6.580001179,198941,Netherlands,1 364 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,363,Groznyy,43.31868532,45.69869869,221237.5,Russia,1 365 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,364,Grudziadz,53.48039064,18.75000769,100964.5,Poland,1 366 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,365,Guangzhou,23.1449813,113.3250101,5990912.5,China,1 367 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,366,Gujranwala,32.16042584,74.18502193,1448735.5,Pakistan,1 368 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,367,Gweru,-19.45004148,29.82002966,164715.5,Zimbabwe,1 369 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,368,Gyor,47.70035585,17.63002437,132173,Hungary,1 370 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,369,Sarqan,45.42033999,79.91490474,61329,Kazakhstan,1 371 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,370,Tarragona,41.12036989,1.249990599,107957.5,Spain,1 372 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,371,Vientiane,17.96669273,102.59998,662174,Laos,1 373 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,372,Besancon,47.22999697,6.03000891,124193,France,1 374 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,373,Bethlehem,-28.21958372,28.29996741,66373,South Africa,1 375 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,374,Beziers,43.35049217,3.209974323,77759.5,France,1 376 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,375,Bialystok,53.15035911,23.1699963,288722.5,Poland,1 377 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,376,Biarritz,43.47327537,-1.561594891,89268,France,1 378 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,377,Billings,45.78830202,-108.5400004,102151.5,United States of America,1 379 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,378,Bishkek,42.87307945,74.58520422,820606,Kyrgyzstan,1 380 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,379,Bitola,41.03905703,21.33951371,75551,Macedonia,1 381 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,380,Biysk,52.53406598,85.18000972,209796.5,Russia,1 382 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,381,Bloemfontein,-29.11999388,26.22991288,459866.5,South Africa,1 383 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,382,Bloomington,40.48459475,-88.99359664,99842.5,United States of America,1 384 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,383,Blumenau,-26.9200248,-49.0899858,286326,Brazil,1 385 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,384,Bobo Dioulasso,11.1799752,-4.289981325,346035,Burkina Faso,1 386 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,385,Bonao,18.94200314,-70.40899757,73269,Dominican Republic,1 387 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,386,Borås,57.7304413,12.91997595,64115.5,Sweden,1 388 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,387,Bowling Green,36.99069948,-86.44364893,61349,United States of America,1 389 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,388,Bremerhaven,53.55043805,8.579982461,127598.5,Germany,1 390 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,389,Bridgeport,41.17997866,-73.19996118,578545,United States of America,1 391 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,390,Brighton,50.83034568,-0.169974407,321004.5,United Kingdom,1 392 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,391,Brikama,13.28036379,-16.65994979,136418,The Gambia,1 393 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,392,Brisbane,-27.45503091,153.0350927,1393176.5,Australia,1 394 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,393,Bristol,51.44999778,-2.583315472,492120.5,United Kingdom,1 395 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,394,Brownsville,25.91997988,-97.50000248,174707,United States of America,1 396 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,395,Brugge,51.22037355,3.230024779,131589,Belgium,1 397 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,396,Brusque,-27.12998615,-48.9300214,81163.5,Brazil,1 398 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,397,Bryan,30.67418581,-96.36968388,108156.5,United States of America,1 399 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,398,Bryansk,53.25999066,34.42998083,426510,Russia,1 400 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,399,Bucharest,44.4333718,26.09994665,1842097,Romania,1 401 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,400,Bulawayo,-20.16999754,28.58000199,697096,Zimbabwe,1 402 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,401,Burgos,42.35039817,-3.67996688,150251,Spain,1 403 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,402,Byumba,-1.579556052,30.06001501,70593,Rwanda,1 404 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,403,Cachoeira do Sul,-30.02996417,-52.90998519,61871,Brazil,1 405 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,404,Cachoeiro de Itapemirim,-20.85000771,-41.12998071,174808.5,Brazil,1 406 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,405,Cadiz,36.53499086,-6.225005332,153932.5,Spain,1 407 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,406,Calgary,51.08299176,-114.0799982,1012661,Canada,1 408 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,407,Cambridge,52.20039125,0.116623086,128488,United Kingdom,1 409 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,408,Campana,-34.15999632,-58.95997766,77149.5,Argentina,1 410 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,409,Campo Grande,-20.45003213,-54.61662521,687723,Brazil,1 411 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,410,Canoas,-29.91999673,-51.17998743,466661,Brazil,1 412 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,411,Cape Coral,26.60290977,-81.97968368,117387.5,United States of America,1 413 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,412,Cape Town,-33.92001097,18.43498816,2823929,South Africa,1 414 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,413,Cartagena,37.60042971,-0.980028322,166276.5,Spain,1 415 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,414,Castello,39.97041424,-0.05000757,176360,Spain,1 416 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,415,Catamarca,-28.47000771,-65.78000065,162586,Argentina,1 417 | 128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,416,Catania,37.49997072,15.07999914,482908,Italy,1 418 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,417,Reno,39.52997601,-119.8200096,265363.5,United States of America,1 419 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,418,Scranton,41.40929283,-75.66267908,114701,United States of America,1 420 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,419,Shakhty,47.72038047,40.2700378,206203.5,Russia,1 421 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,420,The Hague,52.08003684,4.269961302,953862.5,Netherlands,1 422 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,421,Tokmak,42.82987795,75.28459306,87953.5,Kyrgyzstan,1 423 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,422,Vryheid,-27.76002521,30.7899963,108364.5,South Africa,1 424 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,423,Waterbury,41.55000775,-73.05002202,174236,United States of America,1 425 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,424,Weifang,36.7204059,119.1001098,973866,China,1 426 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,425,Welkom,-27.96998655,26.72998572,279011.5,South Africa,1 427 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,426,Wiesbaden,50.08039146,8.250028441,444779,Germany,1 428 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,427,Wilmington,34.22551943,-77.94502039,126992,United States of America,1 429 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,428,Winnipeg,49.88298749,-97.16599186,603688,Canada,1 430 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,429,Wollongong,-34.41538125,150.890004,201319.5,Australia,1 431 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,430,Xapeco,-27.10001382,-52.64002751,154794,Brazil,1 432 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,431,Xian,34.27502545,108.8949963,3617406,China,1 433 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,432,Xinyi,34.38000612,118.3500264,962656,China,1 434 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,433,Yakutsk,62.03495892,129.7350162,220813,Russia,1 435 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,434,Yevpatoriya,45.19689109,33.36306921,90588,Ukraine,1 436 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,435,Yichun,27.8333333,114.4,982000,China,1 437 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,436,York,53.97038658,-1.080022218,151574.5,United Kingdom,1 438 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,437,Youngstown,41.09969932,-80.64973902,194765,United States of America,1 439 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,438,Yuzhno Sakhalinsk,46.96497438,142.7400105,174685,Russia,1 440 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,439,Zarate,-34.08956134,-59.04002446,86192,Argentina,1 441 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,440,Zheleznogorsk,52.3547746,35.40439164,94212,Russia,1 442 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,441,Zhezqazghan,47.77998924,67.77001298,104357,Kazakhstan,1 443 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,442,Zhytomyr,50.24557517,28.66216752,278581,Ukraine,1 444 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,443,Zlatoust,55.17499005,59.64999182,176285,Russia,1 445 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,444,Zlin,49.2304175,17.65002315,101893.5,Czech Republic,1 446 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,445,Balqash,46.8532241,74.95024654,80586,Kazakhstan,1 447 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,446,Banja Luka,44.78040489,17.17997432,221422,Bosnia and Herzegovina,1 448 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,447,Barahona,18.20037355,-71.099986,83644,Dominican Republic,1 449 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,448,Barranquilla,10.95998863,-74.79996688,1521245.5,Colombia,1 450 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,449,Barretos,-20.55002602,-48.58001693,97562,Brazil,1 451 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,450,Bata,1.870000833,9.769987344,135943.5,Equatorial Guinea,1 452 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,451,Bath,51.3837486,-2.350022218,92679,United Kingdom,1 453 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,452,Batman,37.89041201,41.14001054,276337.5,Turkey,1 454 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,453,Beaumont,30.08626304,-94.10168278,107455.5,United States of America,1 455 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,454,Beer Sheva,31.2500163,34.8300081,196504,Israel,1 456 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,455,Beijing,39.92889223,116.3882857,9293300.5,China,1 457 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,456,Belfast,54.60001223,-5.960034425,362588,United Kingdom,1 458 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,457,Belo Horizonte,-19.91502602,-43.91500452,3974112,Brazil,1 459 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,458,Bento Goncalves,-29.1694999,-51.51996668,92561.5,Brazil,1 460 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,459,Berkeley,37.87390139,-122.271152,298257,United States of America,1 461 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,460,Independence,39.09111391,-94.41528121,130695,United States of America,1 462 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,461,Ingolstadt,48.77041974,11.44998816,141991.5,Germany,1 463 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,462,Potosi,-19.56956907,-65.75002832,160576,Bolivia,1 464 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,463,Potsdam,52.40040489,13.06999263,181693.5,Germany,1 465 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,464,Poughkeepsie,41.70023114,-73.92141585,100670.5,United States of America,1 466 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,465,Prague,50.08333701,14.46597978,582043.5,Czech Republic,1 467 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,466,Prey Veng,11.48399998,105.3240036,74000,Cambodia,1 468 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,467,Pristina,42.66670961,21.16598425,331700,Kosovo,1 469 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,468,Provo,40.24889854,-111.63777,231238,United States of America,1 470 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,469,Pskov,57.82999595,28.32993974,189979.5,Russia,1 471 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,470,Puerto Plata,19.7902171,-70.69024747,119897,Dominican Republic,1 472 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,471,Punta del Este,-34.96997272,-54.94998987,84140,Uruguay,1 473 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,472,Québec,46.83996909,-71.24561019,576386,Canada,1 474 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,473,Qyzylorda,44.80001609,65.46498572,213259.5,Kazakhstan,1 475 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,474,Racine,42.72771364,-87.81183415,105458.5,United States of America,1 476 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,475,Ragusa,36.93003135,14.72999467,67361,Italy,1 477 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,476,Ramla,31.91670012,34.86670252,63860,Israel,1 478 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,477,Rancagua,-34.17002155,-70.73998214,222981.5,Chile,1 479 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,478,Rawalpindi,33.59997622,73.04002722,1800550.5,Pakistan,1 480 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,479,Reconquista,-29.13952757,-59.65001306,86640.5,Argentina,1 481 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,480,Red Deer,52.26664044,-113.8000411,74225,Canada,1 482 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,481,Regensburg,49.02040448,12.12002478,146755,Germany,1 483 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,482,Saidu,34.75003522,72.34999182,1860310,Pakistan,1 484 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,483,Saint-Etienne,45.43039105,4.380032103,220982,France,1 485 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,484,Settat,33.01042564,-7.620010622,140415,Morocco,1 486 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,485,South Bend,41.68330711,-86.25001734,171791,United States of America,1 487 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,486,Southampton,50.90003135,-1.399976849,384417,United Kingdom,1 488 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,487,Tiraspol,46.85309491,29.63998897,137097,Moldova,1 489 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,488,Tsuruoka,38.70041424,139.830214,88052.5,Japan,1 490 | 300,London,51.49999473,-0.116721844,7994104.5,United Kingdom,4021347,489,Tubarao,-28.48003294,-49.02001591,79760,Brazil,1 491 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,490,Saskatoon,52.17003135,-106.6699854,194075.5,Canada,1 492 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,491,Sete Lagoas,-19.44962807,-44.24999699,195032,Brazil,1 493 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,492,Tauranga,-37.69642129,176.1536299,84730,New Zealand,1 494 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,493,Timbuktu,16.7665851,-3.016596518,68872,Mali,1 495 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,494,Vilnius,54.68336631,25.31663529,524697.5,Lithuania,1 496 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,495,"Washington, D.C.",38.89954938,-77.00941858,2445216.5,United States of America,1 497 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,496,Aberdeen,57.17039797,-2.079987021,186577,United Kingdom,1 498 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,497,Abilene,32.4486253,-99.73278609,108008,United States of America,1 499 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,498,Ad Damman,26.42819175,50.09967037,1411656,Saudi Arabia,1 500 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,499,Almeria,36.83034751,-2.429991497,152032.5,Spain,1 501 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,500,Amiens,49.90037661,2.300004027,118908.5,France,1 502 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,501,Amsterdam,52.34996869,4.916640176,886318,Netherlands,1 503 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,502,An Najaf,32.00033225,44.33537105,612776,Iraq,1 504 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,503,Ankang,32.67998069,109.0200016,1025000,China,1 505 | 642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,504,Annecy,45.89997479,6.116670287,77490.5,France,1 506 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,505,Riverside,33.94194501,-117.3980386,297554,United States of America,1 507 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,506,Sarnia,42.96663963,-82.3999681,113585,Canada,1 508 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,507,Shimonoseki,33.96543194,130.9454333,236198.5,Japan,1 509 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,508,Tanjungpandan,-2.750027243,107.6500077,61591,Indonesia,1 510 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,509,Topeka,39.05000531,-95.66998499,126830.5,United States of America,1 511 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,510,Vienna,48.20001528,16.36663896,2065500,Austria,1 512 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,511,Sakata,38.92003908,139.8500577,86507.5,Japan,1 513 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,512,Spokane,47.66999595,-117.4199494,272483.5,United States of America,1 514 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,513,Tukuyu,-9.249578838,33.64000321,77984,Tanzania,1 515 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,514,Bournemouth,50.72999005,-1.900049684,295272.5,United Kingdom,1 516 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,515,George Town,5.413613156,100.3293679,1610101,Malaysia,1 517 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,516,Innsbruck,47.28040733,11.4099906,133840.5,Austria,1 518 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,517,La Rochelle,46.16665102,-1.149992108,76903.5,France,1 519 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,518,La Romana,18.41700116,-68.96660201,202471.5,Dominican Republic,1 520 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,519,La Serena,-29.89999795,-71.24997685,151290,Chile,1 521 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,520,Laayoune,27.14998232,-13.20000594,182224.5,Morocco,1 522 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,521,Labe,11.31999249,-12.3000092,99612,Guinea,1 523 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,522,Lafayette,30.19997703,-92.01994938,135205.5,United States of America,1 524 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,523,Lahore,31.55997154,74.35002478,6443944,Pakistan,1 525 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,524,Lahti,60.99385968,25.66493445,97508,Finland,1 526 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,525,Lajes,-27.80958291,-50.30998885,139972,Brazil,1 527 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,526,Lansing,42.73352724,-84.54673629,198821.5,United States of America,1 528 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,527,Novoaltaysk,53.39925865,83.95884395,76218,Russia,1 529 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,528,Novocherkassk,47.41995953,40.08002356,159470.5,Russia,1 530 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,529,Nowra,-34.88284625,150.6000476,61036.5,Australia,1 531 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,530,Nueva San Salvador,13.67399699,-89.28999848,124694,El Salvador,1 532 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,531,Nyanza,-2.349586569,29.74003454,225209,Rwanda,1 533 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,532,Obihiro,42.93041445,143.1700101,169614,Japan,1 534 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,533,Oldenburg,53.1299986,8.220004434,163338,Germany,1 535 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,534,Olomouc,49.63003135,17.24999589,97829,Czech Republic,1 536 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,535,Malindi,-3.209999167,40.10002234,81160,Kenya,1 537 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,536,Manchester,53.50041526,-2.247987103,1312757.5,United Kingdom,1 538 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,537,Mangyshlak,43.69045506,51.14173561,147443,Kazakhstan,1 539 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,538,Manisa,38.63039268,27.43996822,237700,Turkey,1 540 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,539,Salzburg,47.81047833,13.0400203,178274,Austria,1 541 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,540,St. John’s,47.58498822,-52.68100692,115325.5,Canada,1 542 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,541,Uberaba,-19.7799955,-47.9500037,234807,Brazil,1 543 | 451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,542,Blagoveshchensk,50.26660748,127.5333418,206711,Russia,1 544 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,543,Utrecht,52.10034568,5.120038614,478224,Netherlands,1 545 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,544,Regina,50.45003298,-104.6170099,176183,Canada,1 546 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,545,Severodvinsk,64.57002382,39.83001298,182077.5,Russia,1 547 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,546,Tiruvannamalai,12.26037437,79.09996741,138243,India,1 548 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,547,Kiffa,16.61997906,-11.39998661,73930,Mauritania,1 549 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,548,Kigali,-1.953590069,30.06053178,802630.5,Rwanda,1 550 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,549,Kilifi,-3.609613018,39.85001176,63228.5,Kenya,1 551 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,550,Killeen,31.11728538,-97.72748214,120464,United States of America,1 552 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,551,Kimberley,-28.74683836,24.77000199,153676.5,South Africa,1 553 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,552,Kindia,10.06001772,-12.86997441,93511,Guinea,1 554 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,553,Kisumu,-0.090034567,34.75001298,306047,Kenya,1 555 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,554,Kitale,1.030465514,34.98994665,112809,Kenya,1 556 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,555,Beira,-19.82004474,34.87000565,507196.5,Mozambique,1 557 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,556,Hawalli,29.33334002,47.99999756,164212,Kuwait,1 558 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,557,Haarlem,52.38043194,4.629991006,248773.5,Netherlands,1 559 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,558,Hachinohe,40.50999371,141.5400321,225575,Japan,1 560 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,559,Hamburg,53.55002464,9.999999144,1748058.5,Germany,1 561 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,560,Hamilton,-37.77000853,175.3000386,112145,New Zealand,1 562 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,561,Hamilton,43.24998151,-79.82999577,620501,Canada,1 563 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,562,Hania,35.51221092,24.01557776,66646.5,Greece,1 564 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,563,Hannover,52.36697023,9.716657266,618815,Germany,1 565 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,564,Hartford,41.77002016,-72.67996708,518509.5,United States of America,1 566 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,565,Hatay,36.2303583,36.12000688,305564,Turkey,1 567 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,566,San Juan,18.80700306,-71.22899657,72950,Dominican Republic,1 568 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,567,Sterlitamak,53.62999392,55.96003617,220040,Russia,1 569 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,568,Uruguaiana,-29.76961831,-57.08998845,97736.5,Brazil,1 570 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,569,Eldoret,0.520005716,35.26998124,285913.5,Kenya,1 571 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,570,Sarajevo,43.8500224,18.38300167,662816.5,Bosnia and Herzegovina,1 572 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,571,Takaoka,36.67002138,136.9999991,124437,Japan,1 573 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,572,Versailles,48.80046958,2.133347533,85416,France,1 574 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,573,Cologne,50.93000368,6.950004434,983697.5,Germany,1 575 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,574,Copiapo,-27.35999795,-70.33998071,117316.5,Chile,1 576 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,575,Coral Gables,25.71541872,-80.29107874,98700.5,United States of America,1 577 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,576,Dundee,56.47038902,-3.000008384,151013.5,United Kingdom,1 578 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,577,Durban,-29.865013,30.98001054,2729000,South Africa,1 579 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,578,Edmonton,53.55002464,-113.4999819,885195.5,Canada,1 580 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,579,Bucaramanga,7.1300932,-73.12588302,790410,Colombia,1 581 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,580,Bago,17.32001385,96.51497676,264347,Myanmar,1 582 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,581,Baguio City,16.42999066,120.5699426,360269,Philippines,1 583 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,582,Bahia Blanca,-38.74002684,-62.2650214,279041,Argentina,1 584 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,583,Baku,40.39527203,49.86221716,2007150,Azerbaijan,1 585 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,584,Balakovo,52.02998822,47.80001745,172821.5,Russia,1 586 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,585,Balikesir,39.6503821,27.89001827,249833.5,Turkey,1 587 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,586,Samara,53.19500755,50.15129512,996595,Russia,1 588 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,587,St. Paul,44.94398663,-93.08497481,509961,United States of America,1 589 | 516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,588,Uberlandia,-18.89999754,-48.27998356,484862,Brazil,1 590 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,589,Nairobi,-1.283346742,36.81665686,2880273.5,Kenya,1 591 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,590,Nakhodka,67.75039817,77.51996049,159551,Russia,1 592 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,591,Plymouth,50.38538576,-4.159989259,239436,United Kingdom,1 593 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,592,Pointe-a-Pitre,16.24147504,-61.5329989,81887.5,France,1 594 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,593,Poitier,46.58329226,0.333276529,85383.5,France,1 595 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,594,Polatsk,55.48938946,28.78598425,79216,Belarus,1 596 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,595,Pori,61.47889467,21.77493933,71526,Finland,1 597 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,596,Port Elizabeth,-33.97003375,25.60002885,830527,South Africa,1 598 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,597,Port Louis,-20.16663857,57.49999385,371953.5,Mauritius,1 599 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,598,Port Moresby,-9.464707826,147.1925036,267434.5,Papua New Guinea,1 600 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,599,Portland,43.67216158,-70.2455274,99504,United States of America,1 601 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,600,Porto Alegre,-30.05001463,-51.20001205,2644870.5,Brazil,1 602 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,601,Porto-Novo,6.483310973,2.616625528,267084,Benin,1 603 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,602,Portsmouth,50.80034751,-1.080022218,323676,United Kingdom,1 604 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,603,Potenza,40.64200213,15.7989965,69060,Italy,1 605 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,604,Iskenderun,36.58041445,36.17002966,228954,Turkey,1 606 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,605,Itajai,-26.89961261,-48.68001083,241421,Brazil,1 607 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,606,Iwaki,37.0553467,140.8900459,324677,Japan,1 608 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,607,Jönköping,57.7713432,14.16501623,86491,Sweden,1 609 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,608,Jaén,37.77039349,-3.799985394,92909,Spain,1 610 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,609,Jalal Abad,40.94288719,73.00251013,162299.5,Kyrgyzstan,1 611 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,610,Jeddah,21.51688946,39.21919755,2939723,Saudi Arabia,1 612 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,611,Jelgava,56.65270347,23.71280554,64499,Latvia,1 613 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,612,Jianmen,30.65005292,113.1600073,937875,China,1 614 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,613,Jilin,43.84997072,126.5500427,2138988.5,China,1 615 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,614,Johor Bahru,1.480024637,103.7300402,838744.5,Malaysia,1 616 | 405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,615,Juazeiro,-9.420007712,-40.49996749,95132,Brazil,1 617 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,616,Ottawa,45.4166968,-75.7000153,978564.5,Canada,1 618 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,617,Ouahigouya,13.5704236,-2.419992108,70300,Burkina Faso,1 619 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,618,Ourense,42.32996014,-7.869995363,113095,Spain,1 620 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,619,Pabna,24.00038129,89.24999385,137888,Bangladesh,1 621 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,620,Palmas,-10.23773558,-48.2877867,215793.5,Brazil,1 622 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,621,Panevežys,55.74002016,24.37002641,122400,Lithuania,1 623 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,622,Pardubice,50.04041974,15.76000932,97902.5,Czech Republic,1 624 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,623,Pathein,16.77040916,94.74996822,216014.5,Myanmar,1 625 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,624,Pavlodar,52.29999758,76.95002112,316254,Kazakhstan,1 626 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,625,Pec,43.88973574,20.33011796,137332.5,Serbia,1 627 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,626,Peoria,40.69998212,-89.67004114,142622,United States of America,1 628 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,627,Perpignan,42.69998924,2.899967406,128663,France,1 629 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,628,Phoenix,33.53997988,-112.0699917,2436022.5,United States of America,1 630 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,629,Pietermaritzburg,-29.61004148,30.39002071,620898,South Africa,1 631 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,630,Bani,18.279999,-70.33100347,66709,Dominican Republic,1 632 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,631,San Fernando,-34.58002236,-70.98996688,60746,Chile,1 633 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,632,St.-Denis,-20.87889484,55.44807776,163621,France,1 634 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,633,Umeå,63.82999147,20.23999426,76101,Sweden,1 635 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,634,Leeuwarden,53.25037884,5.783357298,108601,Netherlands,1 636 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,635,Leon,42.57997072,-5.570006553,135014,Spain,1 637 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,636,Lexington,38.05001467,-84.50002079,244972,United States of America,1 638 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,637,Liberec,50.79995994,15.07999914,99972.5,Czech Republic,1 639 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,638,Lida,53.88847943,25.28464758,99126,Belarus,1 640 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,639,Lincoln,40.81997479,-96.68000086,244146,United States of America,1 641 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,640,Bologna,44.50042198,11.34002071,429694.5,Italy,1 642 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,641,Elazig,38.67997622,39.22999792,271492,Turkey,1 643 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,642,Ruhengeri,-1.499612611,29.63001542,86685,Rwanda,1 644 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,643,Soledad,10.92001691,-74.76999455,520704,Colombia,1 645 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,644,Toyama,36.69999371,137.2300109,329172,Japan,1 646 | 593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,645,Criciuma,-28.68002073,-49.38996749,183085.5,Brazil,1 647 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,646,Salamanca,40.97040489,-5.670000449,160456.5,Spain,1 648 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,647,Spring Hill,28.47894513,-82.54771102,91887.5,United States of America,1 649 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,648,Turkistan,43.30155458,68.25489294,86743.5,Kazakhstan,1 650 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,649,Salt Lake City,40.7750163,-111.9300519,572013,United States of America,1 651 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,650,St. George,37.10415509,-113.583336,79988,United States of America,1 652 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,651,Tyler,32.35108604,-95.30078272,101561.5,United States of America,1 653 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,652,Riga,56.95002382,24.09996537,723802.5,Latvia,1 654 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,653,Sheffield,53.36667666,-1.499996583,922800,United Kingdom,1 655 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,654,Tolyatti,53.48039064,49.53004106,648622,Russia,1 656 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,655,Buenos Aires,-34.60250161,-58.39753137,11862073,Argentina,1 657 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,656,Conselheiro Lafaiete,-20.6700187,-43.78999923,102926,Brazil,1 658 | 630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,657,Columbus,32.47043276,-84.98001734,202225,United States of America,1 659 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,658,Sasebo,33.1631295,129.7177046,224347.5,Japan,1 660 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,659,Semey,50.43499514,80.2750378,302066.5,Kazakhstan,1 661 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,660,Taunggyi,20.78199907,97.03800065,160115,Myanmar,1 662 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,661,Thimphu,27.47298586,89.63901404,88930.5,Bhutan,1 663 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,662,Vila Velha,-20.36760822,-40.31798893,742413.5,Brazil,1 664 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,663,Warsaw,52.25000063,20.99999955,1704569.5,Poland,1 665 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,664,Antananarivo,-18.91663735,47.5166239,1544216.5,Madagascar,1 666 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,665,Antsirabe,-19.85001707,47.03329423,307921,Madagascar,1 667 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,666,Antsiranana,-12.27650152,49.3115261,76312,Madagascar,1 668 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,667,Aqtobe,50.28001752,57.16998816,260493,Kazakhstan,1 669 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,668,Arapiraca,-9.750013409,-36.66999455,177115,Brazil,1 670 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,669,Araxa,-19.5795943,-46.95001306,70159.5,Brazil,1 671 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,670,Örebro,59.2803467,15.2199906,95932,Sweden,1 672 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,671,Arezzo,43.46172569,11.87497514,82613,Italy,1 673 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,672,Arlington,32.68476076,-97.02023849,545107.5,United States of America,1 674 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,673,Armavir,45.00039146,41.13003699,191813.5,Russia,1 675 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,674,San Cristobal,18.4159981,-70.10900052,154040,Dominican Republic,1 676 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,675,St. Petersburg,27.77053876,-82.67938257,523314.5,United States of America,1 677 | 432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,676,Ulm,48.40039064,9.999999144,146703,Germany,1 678 | -------------------------------------------------------------------------------- /docs/csv-data/Flowmap_Cities_one_to_one.csv: -------------------------------------------------------------------------------- 1 | s_city_id,s_city,s_lat,s_lon,s_pop,s_country,s_Volume,s_Vol2,e_city_id,e_City,e_lat,e_lon,e_pop,e_country,e_vol,e_Vol2 2 | 1,Sarh,9.149969909,18.39002966,135862,Chad,33,505,238,Hechi,23.09653465,109.6091129,3275189.5,China,291099,10 3 | 10,Asheville,35.60119773,-82.55414474,105775,United States of America,3,832,623,San Jose,9.93501243,-84.08405135,642862,Costa Rica,302064,20 4 | 17,Ballarat,-37.55958209,143.8400468,73404,Australia,29,900,222,Haifa,32.8204114,34.98002478,639150,Israel,400017,30 5 | 23,Elkhart,41.68294537,-85.96879419,100295,United States of America,23,696,657,Ulaanbaatar,47.9166734,106.9166158,827306,Mongolia,645321,15 6 | 43,Chengdu,30.67000002,104.0700195,4036718.5,China,31,534,262,Johannesburg,-26.17004474,28.03000972,2730734.5,South Africa,666365,17 7 | 57,Beirut,33.87197512,35.50970821,1779062.5,Lebanon,3,946,183,Dakar,14.71583173,-17.47313013,2540200,Senegal,765122,9 8 | 96,Mar del Plata,-38.00002033,-57.57998438,554916,Argentina,20,842,579,Rome,41.89595563,12.48325842,1687226,Italy,800446,12 9 | 110,Tacoma,47.21131594,-122.5150131,460273,United States of America,29,885,103,Berlin,52.52181866,13.40154862,3250007,Germany,904561,36 10 | 150,Utsunomiya,36.54997703,139.8700048,558808.5,Japan,6,672,373,Mendoza,-32.88333006,-68.81661117,827815,Argentina,987654,36 11 | 175,Charlottesville,38.02918907,-78.47692591,61314,United States of America,17,532,237,Ipoh,4.599989236,101.0649833,656227,Malaysia,1148668,8 12 | 199,Ceske Budejovice,48.98001935,14.46003699,97452,Czech Republic,20,881,276,Lima,-12.04801268,-77.05006209,7385117,Peru,1222446,31 13 | 216,Tripoli,32.89250002,13.18001176,1209199,Libya,34,665,562,Reykjavík,64.15002362,-21.95001449,140059,Iceland,1241978,27 14 | 232,Nagaoka,37.45041302,138.8600406,187560,Japan,20,952,389,Miami,25.7876107,-80.22410608,2983947,United States of America,1354625,14 15 | 259,Sunderland,54.92001853,-1.380029746,315449.5,United Kingdom,29,877,489,Phnom Penh,11.55003013,104.9166345,1466000,Cambodia,1504012,24 16 | 327,Santo Angelo,-28.30004393,-54.28003076,65013,Brazil,24,826,35,Barcelona,41.38329958,2.183370319,3250797.5,Spain,2988556,22 17 | 361,Osnabrück,52.28043805,8.049988972,198865,Germany,1,852,1,Alexandria,31.20001935,29.94999589,3988258,Egypt,3502678,11 18 | 362,Groningen,53.22040651,6.580001179,198941,Netherlands,12,730,128,Chicago,41.82999066,-87.75005497,5915976,United States of America,3954100,11 19 | 504,Annecy,45.89997479,6.116670287,77490.5,France,3,874,642,Tokyo,35.68501691,139.7514074,22006299.5,Japan,4512331,26 20 | 542,Blagoveshchensk,50.26660748,127.5333418,206711,Russia,14,728,451,Oslo,59.91669029,10.74997921,707500,Norway,5121333,14 21 | 588,Uberlandia,-18.89999754,-48.27998356,484862,Brazil,20,916,516,Quito,-0.214988181,-78.50005111,1550407,Ecuador,5211978,6 22 | 615,Juazeiro,-9.420007712,-40.49996749,95132,Brazil,9,731,405,Moscow,55.75216412,37.61552283,10452000,Russia,6465542,33 23 | 645,Criciuma,-28.68002073,-49.38996749,183085.5,Brazil,3,777,593,San Bernardino,34.12038373,-117.3000342,973690.5,United States of America,6546546,7 24 | 657,Columbus,32.47043276,-84.98001734,202225,United States of America,22,931,630,Seoul,37.5663491,126.999731,9796000,South Korea,7778584,9 25 | 676,Ulm,48.40039064,9.999999144,146703,Germany,29,530,432,New York,40.74997906,-73.98001693,13524139,United States of America,10445464,34 26 | -------------------------------------------------------------------------------- /docs/main/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Canvas Flowmap Layer with LeafletJS 10 | 11 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /img/img_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwasilgeo/Leaflet.Canvas-Flowmap-Layer/7ae3238d3bbe11512eeda5ce47b5593c172b23e6/img/img_01.png -------------------------------------------------------------------------------- /src/CanvasFlowmapLayer.js: -------------------------------------------------------------------------------- 1 | (function(factory, window) { 2 | // module loaders support for LeafletJS plugins, see: 3 | // https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md#module-loaders 4 | 5 | // AMD module that relies on "leaflet" 6 | if (typeof define === 'function' && define.amd) { 7 | define(['leaflet'], factory); 8 | 9 | // Common JS module that relies on "leaflet" 10 | } else if (typeof exports === 'object') { 11 | module.exports = factory(require('leaflet')); 12 | } 13 | 14 | // attach plugin to the global leaflet "L" variable 15 | if (typeof window !== 'undefined' && window.L) { 16 | window.L.CanvasFlowmapLayer = factory(L); 17 | 18 | window.L.canvasFlowmapLayer = function(originAndDestinationGeoJsonPoints, opts) { 19 | return new window.L.CanvasFlowmapLayer(originAndDestinationGeoJsonPoints, opts); 20 | }; 21 | } 22 | }(function(L) { 23 | // layer source code 24 | var canvasRenderer = L.canvas(); 25 | 26 | var CanvasFlowmapLayer = L.GeoJSON.extend({ 27 | options: { 28 | // this is only a default option example, 29 | // developers will most likely need to provide this 30 | // options object with values unique to their data 31 | originAndDestinationFieldIds: { 32 | originUniqueIdField: 'origin_id', 33 | originGeometry: { 34 | x: 'origin_lon', 35 | y: 'origin_lat' 36 | }, 37 | destinationUniqueIdField: 'destination_id', 38 | destinationGeometry: { 39 | x: 'destination_lon', 40 | y: 'destination_lat' 41 | } 42 | }, 43 | 44 | canvasBezierStyle: { 45 | type: 'simple', 46 | symbol: { 47 | // use canvas styling options (compare to CircleMarker styling below) 48 | strokeStyle: 'rgba(255, 0, 51, 0.8)', 49 | lineWidth: 0.75, 50 | lineCap: 'round', 51 | shadowColor: 'rgb(255, 0, 51)', 52 | shadowBlur: 1.5 53 | } 54 | }, 55 | 56 | animatedCanvasBezierStyle: { 57 | type: 'simple', 58 | symbol: { 59 | // use canvas styling options (compare to CircleMarker styling below) 60 | strokeStyle: 'rgb(255, 46, 88)', 61 | lineWidth: 1.25, 62 | lineDashOffsetSize: 4, // custom property used with animation sprite sizes 63 | lineCap: 'round', 64 | shadowColor: 'rgb(255, 0, 51)', 65 | shadowBlur: 2 66 | } 67 | }, 68 | 69 | // valid values: 'selection' or 'all' 70 | // use 'all' to display all Bezier paths immediately 71 | // use 'selection' if Bezier paths will be drawn with user interactions 72 | pathDisplayMode: 'all', 73 | 74 | wrapAroundCanvas: true, 75 | 76 | animationStarted: false, 77 | 78 | animationEasingFamily: 'Cubic', 79 | 80 | animationEasingType: 'In', 81 | 82 | animationDuration: 2000, 83 | 84 | pointToLayer: function(geoJsonPoint, latlng) { 85 | return L.circleMarker(latlng); 86 | }, 87 | 88 | style: function(geoJsonFeature) { 89 | // use leaflet's path styling options 90 | 91 | // since the GeoJSON feature properties are modified by the layer, 92 | // developers can rely on the "isOrigin" property to set different 93 | // symbols for origin vs destination CircleMarker stylings 94 | 95 | if (geoJsonFeature.properties.isOrigin) { 96 | return { 97 | renderer: canvasRenderer, // recommended to use L.canvas() 98 | radius: 5, 99 | weight: 1, 100 | color: 'rgb(195, 255, 62)', 101 | fillColor: 'rgba(195, 255, 62, 0.6)', 102 | fillOpacity: 0.6 103 | }; 104 | } else { 105 | return { 106 | renderer: canvasRenderer, 107 | radius: 2.5, 108 | weight: 0.25, 109 | color: 'rgb(17, 142, 170)', 110 | fillColor: 'rgb(17, 142, 170)', 111 | fillOpacity: 0.7 112 | }; 113 | } 114 | } 115 | }, 116 | 117 | _customCanvases: [], 118 | 119 | initialize: function(geoJson, options) { 120 | // same as L.GeoJSON intialize method, but first performs custom GeoJSON 121 | // data parsing and reformatting before finally calling L.GeoJSON addData method 122 | L.setOptions(this, options); 123 | 124 | this._animationPropertiesStatic = { 125 | offset: 0, 126 | resetOffset: 200, 127 | repeat: Infinity, 128 | yoyo: false 129 | }; 130 | 131 | this._animationPropertiesDynamic = { 132 | duration: null, 133 | easingInfo: null 134 | }; 135 | 136 | this._layers = {}; 137 | 138 | // beginning of customized initialize method 139 | if (geoJson && this.options.originAndDestinationFieldIds) { 140 | this.setOriginAndDestinationGeoJsonPoints(geoJson); 141 | } 142 | 143 | // establish animation properties using Tween.js library 144 | // currently requires the developer to add it to their own app index.html 145 | // TODO: find better way to wrap it up in this layer source code 146 | if (window.hasOwnProperty('TWEEN')) { 147 | // set this._animationPropertiesDynamic.duration value 148 | this.setAnimationDuration(this.options.animationDuration); 149 | // set this._animationPropertiesDynamic.easingInfo value 150 | this.setAnimationEasing(this.options.animationEasingFamily, this.options.animationEasingType); 151 | 152 | // initiate the active animation tween 153 | this._animationTween = new TWEEN.Tween(this._animationPropertiesStatic) 154 | .to({ 155 | offset: this._animationPropertiesStatic.resetOffset 156 | }, this._animationPropertiesDynamic.duration) 157 | .easing(this._animationPropertiesDynamic.easingInfo.tweenEasingFunction) 158 | .repeat(this._animationPropertiesStatic.repeat) 159 | .yoyo(this._animationPropertiesStatic.yoyo) 160 | .start(); 161 | } else { 162 | // Tween.js lib isn't available, 163 | // ensure that animations aren't attempted at the beginning 164 | this.options.animationStarted = false; 165 | } 166 | }, 167 | 168 | setOriginAndDestinationGeoJsonPoints: function(geoJsonFeatureCollection) { 169 | if (geoJsonFeatureCollection.features) { 170 | var configOriginGeometryObject = this.options.originAndDestinationFieldIds.originGeometry; 171 | var configDestinationGeometryObject = this.options.originAndDestinationFieldIds.destinationGeometry; 172 | 173 | geoJsonFeatureCollection.features.forEach(function(feature, index) { 174 | if (feature.type === 'Feature' && feature.geometry && feature.geometry.type === 'Point') { 175 | // origin feature -- modify attribute properties and geometry 176 | feature.properties.isOrigin = true; 177 | feature.properties._isSelectedForPathDisplay = this.options.pathDisplayMode === 'all' ? true : false; 178 | feature.properties._uniqueId = index + '_origin'; 179 | 180 | feature.geometry.coordinates = [ 181 | feature.properties[configOriginGeometryObject.x], 182 | feature.properties[configOriginGeometryObject.y] 183 | ]; 184 | 185 | // destination feature -- clone, modify, and push to feature collection 186 | var destinationFeature = JSON.parse(JSON.stringify(feature)); 187 | 188 | destinationFeature.properties.isOrigin = false; 189 | destinationFeature.properties._isSelectedForPathDisplay = false; 190 | destinationFeature.properties._uniqueId = index + '_destination'; 191 | 192 | destinationFeature.geometry.coordinates = [ 193 | destinationFeature.properties[configDestinationGeometryObject.x], 194 | destinationFeature.properties[configDestinationGeometryObject.y] 195 | ]; 196 | 197 | geoJsonFeatureCollection.features.push(destinationFeature); 198 | } 199 | }, this); 200 | 201 | // all origin/destination features are available for future internal used 202 | // but only a filtered subset of these are drawn on the map 203 | this.originAndDestinationGeoJsonPoints = geoJsonFeatureCollection; 204 | var geoJsonPointsToDraw = this._filterGeoJsonPointsToDraw(geoJsonFeatureCollection); 205 | this.addData(geoJsonPointsToDraw); 206 | } else { 207 | // TODO: improved handling of invalid incoming GeoJson FeatureCollection? 208 | this.originAndDestinationGeoJsonPoints = null; 209 | } 210 | 211 | return this; 212 | }, 213 | 214 | onAdd: function(map) { 215 | // call the L.GeoJSON onAdd method, 216 | // then continue with custom code 217 | L.GeoJSON.prototype.onAdd.call(this, map); 218 | 219 | // create new canvas element for optional, animated bezier curves 220 | this._animationCanvasElement = this._insertCustomCanvasElement(map, this.options); 221 | 222 | // create new canvas element for manually drawing bezier curves 223 | // - most of the magic happens in this canvas element 224 | // - this canvas element is established last because it will be 225 | // inserted before (underneath) the animation canvas element 226 | this._canvasElement = this._insertCustomCanvasElement(map, this.options); 227 | 228 | // create a reference to both canvas elements in an array for convenience 229 | this._customCanvases = [this._canvasElement, this._animationCanvasElement] 230 | 231 | // establish custom event listeners 232 | this.on('click mouseover', this._modifyInteractionEvent, this); 233 | map.on('move', this._resetCanvas, this); 234 | map.on('moveend', this._resetCanvasAndWrapGeoJsonCircleMarkers, this); 235 | map.on('resize', this._resizeCanvas, this); 236 | if (map.options.zoomAnimation && L.Browser.any3d) { 237 | map.on('zoomanim', this._animateZoom, this); 238 | } 239 | 240 | // calculate initial size and position of canvas 241 | // and draw its content for the first time 242 | this._resizeCanvas(); 243 | this._resetCanvasAndWrapGeoJsonCircleMarkers(); 244 | 245 | return this; 246 | }, 247 | 248 | onRemove: function(map) { 249 | // call the L.GeoJSON onRemove method, 250 | // then continue with custom code 251 | L.GeoJSON.prototype.onRemove.call(this, map); 252 | 253 | this._clearCanvas(); 254 | 255 | this._customCanvases.forEach(function(canvas) { 256 | L.DomUtil.remove(canvas); 257 | }); 258 | 259 | // remove custom event listeners 260 | this.off('click mouseover', this._modifyInteractionEvent, this); 261 | map.off('move', this._resetCanvas, this); 262 | map.off('moveend', this._resetCanvasAndWrapGeoJsonCircleMarkers, this); 263 | map.off('resize', this._resizeCanvas, this); 264 | if (map.options.zoomAnimation) { 265 | map.off('zoomanim', this._animateZoom, this); 266 | } 267 | 268 | return this; 269 | }, 270 | 271 | bringToBack: function() { 272 | // call the L.GeoJSON bringToBack method to manage the point graphics 273 | L.GeoJSON.prototype.bringToBack.call(this); 274 | 275 | // keep the animation canvas element on top of the main canvas element 276 | L.DomUtil.toBack(this._animationCanvasElement); 277 | 278 | // keep the main canvas element underneath the animation canvas element 279 | L.DomUtil.toBack(this._canvasElement); 280 | 281 | return this; 282 | }, 283 | 284 | bringToFront: function() { 285 | // keep the main canvas element underneath the animation canvas element 286 | L.DomUtil.toFront(this._canvasElement); 287 | 288 | // keep the animation canvas element on top of the main canvas element 289 | L.DomUtil.toFront(this._animationCanvasElement); 290 | 291 | // call the L.GeoJSON bringToFront method to manage the point graphics 292 | L.GeoJSON.prototype.bringToFront.call(this); 293 | 294 | return this; 295 | }, 296 | 297 | setAnimationDuration: function(milliseconds) { 298 | milliseconds = Number(milliseconds) || this.options.animationDuration; 299 | 300 | // change the tween duration on the active animation tween 301 | if (this._animationTween) { 302 | this._animationTween.to({ 303 | offset: this._animationPropertiesStatic.resetOffset 304 | }, milliseconds); 305 | } 306 | 307 | this._animationPropertiesDynamic.duration = milliseconds; 308 | }, 309 | 310 | setAnimationEasing: function(easingFamily, easingType) { 311 | var tweenEasingFunction; 312 | if ( 313 | TWEEN.Easing.hasOwnProperty(easingFamily) && 314 | TWEEN.Easing[easingFamily].hasOwnProperty(easingType) 315 | ) { 316 | tweenEasingFunction = TWEEN.Easing[easingFamily][easingType]; 317 | } else { 318 | easingFamily = this.options.animationEasingFamily; 319 | easingType = this.options.animationEasingType; 320 | tweenEasingFunction = TWEEN.Easing[easingFamily][easingType]; 321 | } 322 | 323 | // change the tween easing function on the active animation tween 324 | if (this._animationTween) { 325 | this._animationTween.easing(tweenEasingFunction); 326 | } 327 | 328 | this._animationPropertiesDynamic.easingInfo = { 329 | easingFamily: easingFamily, 330 | easingType: easingType, 331 | tweenEasingFunction: tweenEasingFunction 332 | }; 333 | }, 334 | 335 | getAnimationEasingOptions: function(prettyPrint) { 336 | var tweenEasingConsoleOptions = {}; 337 | var tweenEasingOptions = {}; 338 | 339 | Object.keys(TWEEN.Easing).forEach(function(family) { 340 | tweenEasingConsoleOptions[family] = { 341 | types: Object.keys(TWEEN.Easing[family]).join('", "') 342 | }; 343 | 344 | tweenEasingOptions[family] = { 345 | types: Object.keys(TWEEN.Easing[family]) 346 | }; 347 | }); 348 | 349 | if (!!prettyPrint) { 350 | console.table(tweenEasingConsoleOptions); 351 | } 352 | 353 | return tweenEasingOptions; 354 | }, 355 | 356 | playAnimation: function() { 357 | this.options.animationStarted = true; 358 | this._redrawCanvas(); 359 | }, 360 | 361 | stopAnimation: function() { 362 | this.options.animationStarted = false; 363 | this._redrawCanvas(); 364 | }, 365 | 366 | selectFeaturesForPathDisplay: function(selectionFeatures, selectionMode) { 367 | this._applyFeaturesSelection(selectionFeatures, selectionMode, '_isSelectedForPathDisplay'); 368 | }, 369 | 370 | selectFeaturesForPathDisplayById: function(uniqueOriginOrDestinationIdField, idValue, originBoolean, selectionMode) { 371 | if ( 372 | uniqueOriginOrDestinationIdField !== this.options.originAndDestinationFieldIds.originUniqueIdField && 373 | uniqueOriginOrDestinationIdField !== this.options.originAndDestinationFieldIds.destinationUniqueIdField 374 | ) { 375 | console.error('Invalid unique id field supplied for origin or destination. It must be one of these: ' + 376 | this.options.originAndDestinationFieldIds.originUniqueIdField + ', ' + this.options.originAndDestinationFieldIds.destinationUniqueIdField); 377 | return; 378 | } 379 | 380 | var existingOriginOrDestinationFeature = this.originAndDestinationGeoJsonPoints.features.filter(function(feature) { 381 | return feature.properties.isOrigin === originBoolean && 382 | feature.properties[uniqueOriginOrDestinationIdField] === idValue; 383 | })[0]; 384 | 385 | var odInfo = this._getSharedOriginOrDestinationFeatures(existingOriginOrDestinationFeature); 386 | 387 | if (odInfo.isOriginFeature) { 388 | this.selectFeaturesForPathDisplay(odInfo.sharedOriginFeatures, selectionMode); 389 | } else { 390 | this.selectFeaturesForPathDisplay(odInfo.sharedDestinationFeatures, selectionMode); 391 | } 392 | }, 393 | 394 | clearAllPathSelections: function() { 395 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 396 | feature.properties._isSelectedForPathDisplay = false; 397 | }); 398 | 399 | this._resetCanvas(); 400 | }, 401 | 402 | selectAllFeaturesForPathDisplay: function() { 403 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 404 | if (feature.properties.isOrigin) { 405 | feature.properties._isSelectedForPathDisplay = true; 406 | } else { 407 | feature.properties._isSelectedForPathDisplay = false; 408 | } 409 | }); 410 | 411 | this._resetCanvas(); 412 | }, 413 | 414 | _filterGeoJsonPointsToDraw: function(geoJsonFeatureCollection) { 415 | var newGeoJson = { 416 | type: 'FeatureCollection', 417 | features: [] 418 | }; 419 | 420 | var originUniqueIdValues = []; 421 | var destinationUniqueIdValues = []; 422 | 423 | var originUniqueIdField = this.options.originAndDestinationFieldIds.originUniqueIdField; 424 | var destinationUniqueIdField = this.options.originAndDestinationFieldIds.destinationUniqueIdField; 425 | 426 | geoJsonFeatureCollection.features.forEach(function(feature) { 427 | var isOrigin = feature.properties.isOrigin; 428 | 429 | if (isOrigin && originUniqueIdValues.indexOf(feature.properties[originUniqueIdField]) === -1) { 430 | originUniqueIdValues.push(feature.properties[originUniqueIdField]); 431 | newGeoJson.features.push(feature); 432 | } else if (!isOrigin && destinationUniqueIdValues.indexOf(feature.properties[destinationUniqueIdField]) === -1) { 433 | destinationUniqueIdValues.push(feature.properties[destinationUniqueIdField]); 434 | newGeoJson.features.push(feature); 435 | } else { 436 | // do not attempt to draw an origin or destination circle on the canvas if it is already in one of the tracking arrays 437 | return; 438 | } 439 | }); 440 | 441 | return newGeoJson; 442 | }, 443 | 444 | _insertCustomCanvasElement: function(map, options) { 445 | var canvas = L.DomUtil.create('canvas', 'leaflet-zoom-animated'); 446 | 447 | var originProp = L.DomUtil.testProp(['transformOrigin', 'WebkitTransformOrigin', 'msTransformOrigin']); 448 | canvas.style[originProp] = '50% 50%'; 449 | 450 | var pane = map.getPane(options.pane); 451 | pane.insertBefore(canvas, pane.firstChild); 452 | 453 | return canvas; 454 | }, 455 | 456 | _modifyInteractionEvent: function(e) { 457 | var odInfo = this._getSharedOriginOrDestinationFeatures(e.layer.feature); 458 | e.isOriginFeature = odInfo.isOriginFeature; 459 | e.sharedOriginFeatures = odInfo.sharedOriginFeatures; 460 | e.sharedDestinationFeatures = odInfo.sharedDestinationFeatures; 461 | }, 462 | 463 | _getSharedOriginOrDestinationFeatures: function(testFeature) { 464 | var isOriginFeature = testFeature.properties.isOrigin; 465 | var sharedOriginFeatures = []; 466 | var sharedDestinationFeatures = []; 467 | 468 | if (isOriginFeature) { 469 | // for an ORIGIN point that was interacted with, 470 | // make an array of all other ORIGIN features with the same ORIGIN ID field 471 | var originUniqueIdField = this.options.originAndDestinationFieldIds.originUniqueIdField; 472 | var testFeatureOriginId = testFeature.properties[originUniqueIdField]; 473 | sharedOriginFeatures = this.originAndDestinationGeoJsonPoints.features.filter(function(feature) { 474 | return feature.properties.isOrigin && 475 | feature.properties[originUniqueIdField] === testFeatureOriginId; 476 | }); 477 | } else { 478 | // for a DESTINATION point that was interacted with, 479 | // make an array of all other ORIGIN features with the same DESTINATION ID field 480 | var destinationUniqueIdField = this.options.originAndDestinationFieldIds.destinationUniqueIdField; 481 | var testFeatureDestinationId = testFeature.properties[destinationUniqueIdField]; 482 | sharedDestinationFeatures = this.originAndDestinationGeoJsonPoints.features.filter(function(feature) { 483 | return feature.properties.isOrigin && 484 | feature.properties[destinationUniqueIdField] === testFeatureDestinationId; 485 | }); 486 | } 487 | 488 | return { 489 | isOriginFeature: isOriginFeature, // Boolean 490 | sharedOriginFeatures: sharedOriginFeatures, // Array of features 491 | sharedDestinationFeatures: sharedDestinationFeatures // Array of features 492 | }; 493 | }, 494 | 495 | _applyFeaturesSelection: function(selectionFeatures, selectionMode, selectionAttributeName) { 496 | var selectionIds = selectionFeatures.map(function(feature) { 497 | return feature.properties._uniqueId; 498 | }); 499 | 500 | if (selectionMode === 'SELECTION_NEW') { 501 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 502 | if (selectionIds.indexOf(feature.properties._uniqueId) > -1) { 503 | feature.properties[selectionAttributeName] = true; 504 | } else { 505 | feature.properties[selectionAttributeName] = false; 506 | } 507 | }); 508 | } else if (selectionMode === 'SELECTION_ADD') { 509 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 510 | if (selectionIds.indexOf(feature.properties._uniqueId) > -1) { 511 | feature.properties[selectionAttributeName] = true; 512 | } 513 | }); 514 | } else if (selectionMode === 'SELECTION_SUBTRACT') { 515 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 516 | if (selectionIds.indexOf(feature.properties._uniqueId) > -1) { 517 | feature.properties[selectionAttributeName] = false; 518 | } 519 | }); 520 | } else { 521 | return; 522 | } 523 | 524 | this._resetCanvas(); 525 | }, 526 | 527 | _animateZoom: function(e) { 528 | // see: https://github.com/Leaflet/Leaflet.heat 529 | var scale = this._map.getZoomScale(e.zoom); 530 | var offset = this._map._getCenterOffset(e.center)._multiplyBy(-scale).subtract(this._map._getMapPanePos()); 531 | 532 | if (L.DomUtil.setTransform) { 533 | this._customCanvases.forEach(function(canvas) { 534 | L.DomUtil.setTransform(canvas, offset, scale); 535 | }); 536 | } else { 537 | this._customCanvases.forEach(function(canvas) { 538 | canvas.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ')'; 539 | }); 540 | } 541 | }, 542 | 543 | _resizeCanvas: function() { 544 | // update the canvas size 545 | var size = this._map.getSize(); 546 | this._customCanvases.forEach(function(canvas) { 547 | canvas.width = size.x; 548 | canvas.height = size.y; 549 | }); 550 | 551 | this._resetCanvas(); 552 | }, 553 | 554 | _resetCanvas: function() { 555 | if (!this._map) { 556 | // stop early if the layer is not currently on the map 557 | return; 558 | } 559 | 560 | // update the canvas position and redraw its content 561 | var topLeft = this._map.containerPointToLayerPoint([0, 0]); 562 | this._customCanvases.forEach(function(canvas) { 563 | L.DomUtil.setPosition(canvas, topLeft); 564 | }); 565 | 566 | this._redrawCanvas(); 567 | }, 568 | 569 | _resetCanvasAndWrapGeoJsonCircleMarkers: function() { 570 | this._resetCanvas(); 571 | // Leaflet will redraw a CircleMarker when its latLng is changed 572 | // sometimes they are drawn 2+ times if this occurs during many "move" events 573 | // so for now, only chang CircleMarker latlng after a single "moveend" event 574 | this._wrapGeoJsonCircleMarkers(); 575 | }, 576 | 577 | _redrawCanvas: function() { 578 | // draw canvas content (only the Bezier curves) 579 | if (this._map && this.originAndDestinationGeoJsonPoints) { 580 | this._clearCanvas(); 581 | 582 | // loop over each of the "selected" features and re-draw the canvas paths 583 | this._drawSelectedCanvasPaths(false); 584 | 585 | if (this._animationFrameId) { 586 | L.Util.cancelAnimFrame(this._animationFrameId); 587 | } 588 | 589 | if ( 590 | this.options.animationStarted && 591 | this.originAndDestinationGeoJsonPoints.features.some(function(feature) { 592 | return feature.properties._isSelectedForPathDisplay; 593 | }) 594 | ) { 595 | // start animation loop if the layer is currently set for showing animations, 596 | // and if there is at least 1 feature selected for displaying paths 597 | this._animator(); 598 | } 599 | } 600 | }, 601 | 602 | _clearCanvas: function() { 603 | this._customCanvases.forEach(function(canvas) { 604 | canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); 605 | }); 606 | 607 | if (this._animationFrameId) { 608 | L.Util.cancelAnimFrame(this._animationFrameId); 609 | } 610 | }, 611 | 612 | _drawSelectedCanvasPaths: function(animate) { 613 | var ctx = animate ? 614 | this._animationCanvasElement.getContext('2d') : 615 | this._canvasElement.getContext('2d'); 616 | 617 | var originAndDestinationFieldIds = this.options.originAndDestinationFieldIds; 618 | 619 | this.originAndDestinationGeoJsonPoints.features.forEach(function(feature) { 620 | 621 | if (feature.properties._isSelectedForPathDisplay) { 622 | var originXCoordinate = feature.properties[originAndDestinationFieldIds.originGeometry.x]; 623 | var originYCoordinate = feature.properties[originAndDestinationFieldIds.originGeometry.y]; 624 | var destinationXCoordinate = feature.properties[originAndDestinationFieldIds.destinationGeometry.x]; 625 | var destinationYCoordinate = feature.properties[originAndDestinationFieldIds.destinationGeometry.y]; 626 | 627 | // origin and destination points for drawing curved lines 628 | // ensure that canvas features will be drawn beyond +/-180 longitude 629 | var originLatLng = this._wrapAroundLatLng(L.latLng([originYCoordinate, originXCoordinate])); 630 | var destinationLatLng = this._wrapAroundLatLng(L.latLng([destinationYCoordinate, destinationXCoordinate])); 631 | 632 | // convert geometry to screen coordinates for canvas drawing 633 | var screenOriginPoint = this._map.latLngToContainerPoint(originLatLng); 634 | var screenDestinationPoint = this._map.latLngToContainerPoint(destinationLatLng); 635 | 636 | // get the canvas symbol properties, 637 | // and draw a curved canvas line 638 | var symbol; 639 | if (animate) { 640 | symbol = this._getSymbolProperties(feature, this.options.animatedCanvasBezierStyle); 641 | ctx.beginPath(); 642 | this._animateCanvasLineSymbol(ctx, symbol, screenOriginPoint, screenDestinationPoint); 643 | ctx.stroke(); 644 | ctx.closePath(); 645 | } else { 646 | symbol = this._getSymbolProperties(feature, this.options.canvasBezierStyle); 647 | ctx.beginPath(); 648 | this._applyCanvasLineSymbol(ctx, symbol, screenOriginPoint, screenDestinationPoint); 649 | ctx.stroke(); 650 | ctx.closePath(); 651 | } 652 | } 653 | }, this); 654 | }, 655 | 656 | _getSymbolProperties: function(feature, canvasSymbolConfig) { 657 | // get the canvas symbol properties 658 | var symbol; 659 | var filteredSymbols; 660 | if (canvasSymbolConfig.type === 'simple') { 661 | symbol = canvasSymbolConfig.symbol; 662 | } else if (canvasSymbolConfig.type === 'uniqueValue') { 663 | filteredSymbols = canvasSymbolConfig.uniqueValueInfos.filter(function(info) { 664 | return info.value === feature.properties[canvasSymbolConfig.field]; 665 | }); 666 | symbol = filteredSymbols[0].symbol; 667 | } else if (canvasSymbolConfig.type === 'classBreaks') { 668 | filteredSymbols = canvasSymbolConfig.classBreakInfos.filter(function(info) { 669 | return ( 670 | info.classMinValue <= feature.properties[canvasSymbolConfig.field] && 671 | info.classMaxValue >= feature.properties[canvasSymbolConfig.field] 672 | ); 673 | }); 674 | if (filteredSymbols.length) { 675 | symbol = filteredSymbols[0].symbol; 676 | } else { 677 | symbol = canvasSymbolConfig.defaultSymbol; 678 | } 679 | } 680 | return symbol; 681 | }, 682 | 683 | _applyCanvasLineSymbol: function(ctx, symbolObject, screenOriginPoint, screenDestinationPoint) { 684 | ctx.lineCap = symbolObject.lineCap; 685 | ctx.lineWidth = symbolObject.lineWidth; 686 | ctx.strokeStyle = symbolObject.strokeStyle; 687 | ctx.shadowBlur = symbolObject.shadowBlur; 688 | ctx.shadowColor = symbolObject.shadowColor; 689 | ctx.moveTo(screenOriginPoint.x, screenOriginPoint.y); 690 | ctx.bezierCurveTo(screenOriginPoint.x, screenDestinationPoint.y, screenDestinationPoint.x, screenDestinationPoint.y, screenDestinationPoint.x, screenDestinationPoint.y); 691 | }, 692 | 693 | _animateCanvasLineSymbol: function(ctx, symbolObject, screenOriginPoint, screenDestinationPoint) { 694 | ctx.lineCap = symbolObject.lineCap; 695 | ctx.lineWidth = symbolObject.lineWidth; 696 | ctx.strokeStyle = symbolObject.strokeStyle; 697 | ctx.shadowBlur = symbolObject.shadowBlur; 698 | ctx.shadowColor = symbolObject.shadowColor; 699 | ctx.setLineDash([symbolObject.lineDashOffsetSize, (this._animationPropertiesStatic.resetOffset - symbolObject.lineDashOffsetSize)]); 700 | ctx.lineDashOffset = -this._animationPropertiesStatic.offset; // this makes the dot appear to move when the entire top canvas is redrawn 701 | ctx.moveTo(screenOriginPoint.x, screenOriginPoint.y); 702 | ctx.bezierCurveTo(screenOriginPoint.x, screenDestinationPoint.y, screenDestinationPoint.x, screenDestinationPoint.y, screenDestinationPoint.x, screenDestinationPoint.y); 703 | }, 704 | 705 | _animator: function(time) { 706 | this._animationCanvasElement.getContext('2d') 707 | .clearRect(0, 0, this._animationCanvasElement.width, this._animationCanvasElement.height); 708 | 709 | this._drawSelectedCanvasPaths(true); // draw it again to give the appearance of a moving dot with a new lineDashOffset 710 | 711 | TWEEN.update(time); 712 | 713 | this._animationFrameId = L.Util.requestAnimFrame(this._animator, this); 714 | }, 715 | 716 | _wrapGeoJsonCircleMarkers: function() { 717 | // ensure that the GeoJson point features, 718 | // which are drawn on the map as individual CircleMarker layers, 719 | // will be drawn beyond +/-180 longitude 720 | this.eachLayer(function(layer) { 721 | var wrappedLatLng = this._wrapAroundLatLng(layer.getLatLng()); 722 | layer.setLatLng(wrappedLatLng); 723 | }, this); 724 | }, 725 | 726 | _wrapAroundLatLng: function(latLng) { 727 | if (this._map && this.options.wrapAroundCanvas) { 728 | var wrappedLatLng = latLng.clone(); 729 | var mapCenterLng = this._map.getCenter().lng; 730 | var wrapAroundDiff = mapCenterLng - wrappedLatLng.lng; 731 | if (wrapAroundDiff < -180 || wrapAroundDiff > 180) { 732 | wrappedLatLng.lng += (Math.round(wrapAroundDiff / 360) * 360); 733 | } 734 | return wrappedLatLng; 735 | } else { 736 | return latLng; 737 | } 738 | } 739 | }); 740 | 741 | return CanvasFlowmapLayer; 742 | 743 | }, window)); 744 | --------------------------------------------------------------------------------