diff --git a/CHANGELOG.md b/CHANGELOG.md index 407bc80..0b4b24f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,44 @@ # Changelog ## development +- Allow the key to be an array in the location data. For example: +```json +[ + { + "key": "US", + "latitude": 37.09024, + "longitude": -95.712891, + "name": "United States" + }, + { + "key": [ + "US.CA","US-CA","US_California" + ], + "latitude": 36.17, + "longitude": -119.7462, + "name": "California" + }, + { + "key": [ + "US.IA","US-IA","US_Iowa" + ], + "latitude": 42.0046, + "longitude": -93.214, + "name": "Iowa" + }, + { + "key": "Unknown", + "latitude": 66, + "longitude": 66, + "name": "Unknown" + } +] +``` +- Support hierarchical keys with segments delimited by '.-_'. The longest match at a segment boundary wins. For example, with the location data above, a key of "US.CA.PaloAlto" will be matching "US.CA". "US-Unknown" will match "US". +- If the location data has an entry with key="unknown", this entry will be returned for any un-matched input data. +- Added a built-in location data file "world_regions", with 2 letter country code and provinces in China and states in the US. +- Made circle area (instead of radius) to be linear in data value. +- Added 'kMGTP' unit to the data value ## v0.16.0 - Add compatibility with Grafana 8 diff --git a/README.md b/README.md index 7cf3b92..ac8057f 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ Time Series data contains a timestamp, a metric name and a numeric value. In oth ```json [ {"target": "SE", "datapoints": [[183255.0, 1529755200]]}, - {"target": "US", "datapoints": [[192224.0, 1529755200]]} + {"target": "US", "datapoints": [[192224.0, 1529755200]]}, + {"target": "US.CA.PaloAlto", "datapoints": [[3922.0, 1529755200]]} ] ``` @@ -65,11 +66,37 @@ Location data should be in the JSON format and should be an array of JSON object "latitude": 37.09024, "longitude": -95.712891, "name": "United States" + }, + { + "key": [ + "US.CA", + "US-CA", + "US_California" + ], + "latitude": 36.17, + "longitude": -119.7462, + "name": "California" + }, + { + "key": [ + "US.IA", + "US-IA", + "US_Iowa" + ], + "latitude": 42.0046, + "longitude": -93.214, + "name": "Iowa" + }, + { + "key": "Unknown", + "latitude": 66, + "longitude": 66, + "name": "Unknown" } ] ``` -The metric name (target in the example data) will be matched with a key field from the location data. With this example data there will be two circles drawn on the map, one for Sweden and one for the United States with values 183255 and 192224. +The metric name (target in the example data) will be matched with a key field from the location data. With this example data there will be three circles drawn on the map, one for Sweden, one for the United States and one for California with values 183255, 192224 and 3922. ### Table Format @@ -115,8 +142,9 @@ Supported Databases: The following location files are included in the plugin: -- Countries (2 letter codes) -- Countries (3 letter codes) +- Countries (2-letter codes) +- Countries (3-letter codes) +- World Regions (2-letter country codes with 2-letter codes for states in the US and provinces in China) - US states Alternatively, you can provide your own location lists by using: @@ -124,11 +152,11 @@ Alternatively, you can provide your own location lists by using: - A JSON endpoint that returns a list of locations - A JSONP endpoint that returns a list of locations -This works by matching country codes (like US or GB or FR) or US state codes (TX or NY) to a metric name. If a metric name matches a country in the list of countries then a circle will be drawn at that location. +This works by matching country codes (like US or GB or FR) or US state codes (TX or NY) to a metric name. Hierarchical metric name is supported and the different levels should be delimitded by '.', '-' or '\_'. If a metric name matches a key in the location file then a circle will be drawn at that location. The longest match at the delimiter boundary wins. The key "Unknown" will match all the otherwise unmatched metric names. The build-in map "World Regions" supports 2-letter country codes with the states in the US and provinces in China. If you want to match to other data than countries or states, then you will have to provide custom location data. The current way to do that is via a JSON endpoint that returns a json file with location data (See Map Data Options) -The size of the circle depends on the value of the matched metric. Circle size is relative e.g. if you have 3 countries with values 1, 2 and 3 or 100, 200 and 300 then you will get one small circle, one medium circle and one large circle. +The size of the circle depends on the value of the matched metric. Circle size is relative and the area is linear to the value e.g. if you have 3 countries with values 1, 2 and 3 or 100, 200 and 300 then you will get one small circle, one medium circle and one large circle. ### Time Series - Graphite and InfluxDB @@ -237,8 +265,9 @@ There are four ways to provide data to this plugin: - *countries*: This is a list of all the countries in the world. It works by matching a country code (US, FR, AU) to a node alias in a time series query. - *states*: Similar to countries but for the states in USA e.g. CA for California + - *world_regions*: On top of countries, added states in USA and provinces in China with hierarchical keys e.g. US.CA for California, CN.GD for Guangdong. - *geohash*: An ElasticSearch query that returns geohashes. - - *json*: A json endpoint that returns custom json. Examples of the format are the [countries data used in first option](https://github.com/grafana/worldmap-panel/blob/master/src/data/countries.json) or [this list of cities](https://github.com/grafana/worldmap-panel/blob/master/src/data/probes.json). + - *json*: A json endpoint that returns custom json. Examples of the format are the [countries data used in first option](https://github.com/grafana/worldmap-panel/blob/master/src/data/countries.json) or [this list of world_regions](https://github.com/panodata/panodata-map-panel/blob/main/src/data/world_regions.json). - *jsonp*: A jsonp endpoint that returns custom json wrapped as jsonp. Use this if you are having problems with CORS. - *table*: This expects the metric query to return data points with a field named geohash or two fields/columns named `latitude` and `longitude`. This field should contain a string in the [geohash form](https://www.elastic.co/guide/en/elasticsearch/guide/current/geohashes.html). For example: London -> "gcpvh3zgu992". diff --git a/src/data/world_regions.json b/src/data/world_regions.json new file mode 100644 index 0000000..41ed9e5 --- /dev/null +++ b/src/data/world_regions.json @@ -0,0 +1,2245 @@ +[ + { + "key": "Unknown", + "latitude": 20, + "longitude": 170, + "name": "Unknown" + }, + { + "key": ["CN_shanghai","CN-SH","CN.SH"], + "latitude": 31.1667, + "longitude": 121.4667, + "name": "Shanghai" + }, + { + "key": ["CN_guangdong","CN-GD","CN.GD"], + "latitude": 23.1288, + "longitude": 113.2590, + "name": "Guangdong" + }, + { + "key": ["CN_sichuan","CN-SC","CN.SC"], + "latitude": 30.6636, + "longitude": 104.0667, + "name": "Sichuan" + }, + { + "key": ["CN_tianjin","CN-TJ","CN.TJ"], + "latitude": 39.1467, + "longitude": 117.2056, + "name": "Tianjin" + }, + { + "key": ["CN_hebei","CN-HE","CN.HE"], + "latitude": 38.0422, + "longitude": 114.5086, + "name": "Hebei" + }, + { + "key": ["CN_hubei","CN-HB","CN.HB"], + "latitude": 30.5872, + "longitude": 114.2881, + "name": "Hubei" + }, + { + "key": ["CN_chongqing","CN-CQ","CN.CQ"], + "latitude": 29.5500, + "longitude": 106.5069, + "name": "Chongqing" + }, + { + "key": ["CN_jilin","CN-JL","CN.JL"], + "latitude": 43.9000, + "longitude": 125.2000, + "name": "Jilin" + }, + { + "key": ["CN_jiangsu","CN-JS","CN.JS"], + "latitude": 32.0500, + "longitude": 118.7667, + "name": "Jiangsu" + }, + { + "key": ["CN_anhui","CN-AH","CN.AH"], + "latitude": 31.8639, + "longitude": 117.2808, + "name": "Anhui" + }, + { + "key": ["CN_guangxi","CN-GX","CN.GX"], + "latitude": 22.8192, + "longitude": 108.3150, + "name": "Guangxi" + }, + { + "key": ["CN_shaanxi","CN-SN","CN.SN"], + "latitude": 34.2667, + "longitude": 108.9000, + "name": "Shaanxi" + }, + { + "key": ["CN_liaoning","CN-LN","CN.LN"], + "latitude": 41.8039, + "longitude": 123.4258, + "name": "Liaoning" + }, + { + "key": ["CN_hunan","CN-HN","CN.HN"], + "latitude": 28.1987, + "longitude": 112.9709, + "name": "Hunan" + }, + { + "key": ["CN_henan","CN-HA","CN.HA"], + "latitude": 34.7492, + "longitude": 113.6605, + "name": "Henan" + }, + { + "key": ["CN_zhejiang","CN-ZJ","CN.ZJ"], + "latitude": 30.2500, + "longitude": 120.1675, + "name": "Zhejiang" + }, + { + "key": ["CN_yunnan","CN-YN","CN.YN"], + "latitude": 25.0433, + "longitude": 102.7061, + "name": "Yunnan" + }, + { + "key": ["CN_fujian","CN-FJ","CN.FJ"], + "latitude": 26.0769, + "longitude": 119.2917, + "name": "Fujian" + }, + { + "key": ["CN_jiangxi","CN-JX","CN.JX"], + "latitude": 28.6842, + "longitude": 115.8872, + "name": "Jiangxi" + }, + { + "key": ["CN_heilongjiang","CN-HL","CN.HL"], + "latitude": 45.7500, + "longitude": 126.6333, + "name": "Heilongjiang" + }, + { + "key": ["CN_guizhou","CN-GZ","CN.GZ"], + "latitude": 26.5794, + "longitude": 106.7078, + "name": "Guizhou" + }, + { + "key": ["CN_gansu","CN-GS","CN.GS"], + "latitude": 36.0617, + "longitude": 103.8318, + "name": "Gansu" + }, + { + "key": ["CN_shanxi","CN-SX","CN.SX"], + "latitude": 37.8733, + "longitude": 112.5425, + "name": "Shanxi" + }, + { + "key": ["CN_shandong","CN-SD","CN.SD"], + "latitude": 36.6667, + "longitude": 116.9833, + "name": "Shandong" + }, + { + "key": ["CN_xinjiang","CN-XJ","CN.XJ"], + "latitude": 43.8250, + "longitude": 87.6000, + "name": "Xinjiang" + }, + { + "key": ["CN_neimenggu","CN-NM","CN.NM"], + "latitude": 40.8151, + "longitude": 111.6629, + "name": "Inner Mongolia" + }, + { + "key": ["CN_qinghai","CN-QH","CN.QH"], + "latitude": 36.6239, + "longitude": 101.7787, + "name": "Qinghai" + }, + { + "key": ["CN_hainan","CN-HI","CN.HI"], + "latitude": 20.0200, + "longitude": 110.3200, + "name": "Hainan" + }, + { + "key": ["CN_ningxia","CN-NX","CN.NX"], + "latitude": 38.4795, + "longitude": 106.2254, + "name": "Ningxia" + }, + { + "key": ["CN_xizang","CN-XZ","CN.XZ"], + "latitude": 29.6500, + "longitude": 91.1000, + "name": "Tibet" + }, + { + "key": [ + "US.AK", + "US-AK", + "US_Alaska" + ], + "latitude": 61.385, + "longitude": -152.2683, + "name": "Alaska" + }, + { + "key": [ + "US.AL", + "US-AL", + "US_Alabama" + ], + "latitude": 32.799, + "longitude": -86.8073, + "name": "Alabama" + }, + { + "key": [ + "US.AR", + "US-AR", + "US_Arkansas" + ], + "latitude": 34.9513, + "longitude": -92.3809, + "name": "Arkansas" + }, + { + "key": [ + "US.AS", + "US-AS", + "US_AmericanSamoa" + ], + "latitude": 14.2417, + "longitude": -170.7197, + "name": "American Samoa" + }, + { + "key": [ + "US.AZ", + "US-AZ", + "US_Arizona" + ], + "latitude": 33.7712, + "longitude": -111.3877, + "name": "Arizona" + }, + { + "key": [ + "US.CA", + "US-CA", + "US_California" + ], + "latitude": 36.17, + "longitude": -119.7462, + "name": "California" + }, + { + "key": [ + "US.CO", + "US-CO", + "US_Colorado" + ], + "latitude": 39.0646, + "longitude": -105.3272, + "name": "Colorado" + }, + { + "key": [ + "US.CT", + "US-CT", + "US_Connecticut" + ], + "latitude": 41.5834, + "longitude": -72.7622, + "name": "Connecticut" + }, + { + "key": [ + "US.DC", + "US-DC", + "US_WashingtonDC", + "US_DistrictofColumbia" + ], + "latitude": 38.8964, + "longitude": -77.0262, + "name": "Washington DC" + }, + { + "key": [ + "US.DE", + "US-DE", + "US_Delaware" + ], + "latitude": 39.3498, + "longitude": -75.5148, + "name": "Delaware" + }, + { + "key": [ + "US.FL", + "US-FL", + "US_Florida" + ], + "latitude": 27.8333, + "longitude": -81.717, + "name": "Florida" + }, + { + "key": [ + "US.GA", + "US-GA", + "US_Georgia" + ], + "latitude": 32.9866, + "longitude": -83.6487, + "name": "Georgia" + }, + { + "key": [ + "US.HI", + "US-HI", + "US_Hawaii" + ], + "latitude": 21.1098, + "longitude": -157.5311, + "name": "Hawaii" + }, + { + "key": [ + "US.IA", + "US-IA", + "US_Iowa" + ], + "latitude": 42.0046, + "longitude": -93.214, + "name": "Iowa" + }, + { + "key": [ + "US.ID", + "US-ID", + "US_Idaho" + ], + "latitude": 44.2394, + "longitude": -114.5103, + "name": "Idaho" + }, + { + "key": [ + "US.IL", + "US-IL", + "US_Illinois" + ], + "latitude": 40.3363, + "longitude": -89.0022, + "name": "Illinois" + }, + { + "key": [ + "US.IN", + "US-IN", + "US_Indiana" + ], + "latitude": 39.8647, + "longitude": -86.2604, + "name": "Indiana" + }, + { + "key": [ + "US.KS", + "US-KS", + "US_Kansas" + ], + "latitude": 38.5111, + "longitude": -96.8005, + "name": "Kansas" + }, + { + "key": [ + "US.KY", + "US-KY", + "US_Kentucky" + ], + "latitude": 37.669, + "longitude": -84.6514, + "name": "Kentucky" + }, + { + "key": [ + "US.LA", + "US-LA", + "US_Louisiana" + ], + "latitude": 31.1801, + "longitude": -91.8749, + "name": "Louisiana" + }, + { + "key": [ + "US.MA", + "US-MA", + "US_Massachusetts" + ], + "latitude": 42.2373, + "longitude": -71.5314, + "name": "Massachusetts" + }, + { + "key": [ + "US.MD", + "US-MD", + "US_Maryland" + ], + "latitude": 39.0724, + "longitude": -76.7902, + "name": "Maryland" + }, + { + "key": [ + "US.ME", + "US-ME", + "US_Maine" + ], + "latitude": 44.6074, + "longitude": -69.3977, + "name": "Maine" + }, + { + "key": [ + "US.MI", + "US-MI", + "US_Michigan" + ], + "latitude": 43.3504, + "longitude": -84.5603, + "name": "Michigan" + }, + { + "key": [ + "US.MN", + "US-MN", + "US_Minnesota" + ], + "latitude": 45.7326, + "longitude": -93.9196, + "name": "Minnesota" + }, + { + "key": [ + "US.MO", + "US-MO", + "US_Missouri" + ], + "latitude": 38.4623, + "longitude": -92.302, + "name": "Missouri" + }, + { + "key": [ + "US.MP", + "US-MP", + "US_NorthernMarianaIslands" + ], + "latitude": 14.8058, + "longitude": 145.5505, + "name": "Northern Mariana Islands" + }, + { + "key": [ + "US.MS", + "US-MS", + "US_Mississippi" + ], + "latitude": 32.7673, + "longitude": -89.6812, + "name": "Mississippi" + }, + { + "key": [ + "US.MT", + "US-MT", + "US_Montana" + ], + "latitude": 46.9048, + "longitude": -110.3261, + "name": "Montana" + }, + { + "key": [ + "US.NC", + "US-NC", + "US_NorthCarolina" + ], + "latitude": 35.6411, + "longitude": -79.8431, + "name": "North Carolina" + }, + { + "key": [ + "US.ND", + "US-ND", + "US_NorthDakota" + ], + "latitude": 47.5362, + "longitude": -99.793, + "name": "North Dakota" + }, + { + "key": [ + "US.NE", + "US-NE", + "US_Nebraska" + ], + "latitude": 41.1289, + "longitude": -98.2883, + "name": "Nebraska" + }, + { + "key": [ + "US.NH", + "US-NH", + "US_NewHampshire" + ], + "latitude": 43.4108, + "longitude": -71.5653, + "name": "New Hampshire" + }, + { + "key": [ + "US.NJ", + "US-NJ", + "US_NewJersey" + ], + "latitude": 40.314, + "longitude": -74.5089, + "name": "New Jersey" + }, + { + "key": [ + "US.NM", + "US-NM", + "US_NewMexico" + ], + "latitude": 34.8375, + "longitude": -106.2371, + "name": "New Mexico" + }, + { + "key": [ + "US.NV", + "US-NV", + "US_Nevada" + ], + "latitude": 38.4199, + "longitude": -117.1219, + "name": "Nevada" + }, + { + "key": [ + "US.NY", + "US-NY", + "US_NewYork" + ], + "latitude": 42.1497, + "longitude": -74.9384, + "name": "New York" + }, + { + "key": [ + "US.OH", + "US-OH", + "US_Ohio" + ], + "latitude": 40.3736, + "longitude": -82.7755, + "name": "Ohio" + }, + { + "key": [ + "US.OK", + "US-OK", + "US_Oklahoma" + ], + "latitude": 35.5376, + "longitude": -96.9247, + "name": "Oklahoma" + }, + { + "key": [ + "US.OR", + "US-OR", + "US_Oregon" + ], + "latitude": 44.5672, + "longitude": -122.1269, + "name": "Oregon" + }, + { + "key": [ + "US.PA", + "US-PA", + "US_Pennsylvania" + ], + "latitude": 40.5773, + "longitude": -77.264, + "name": "Pennsylvania" + }, + { + "key": [ + "US.PR", + "US-PR", + "US_PuertoRico" + ], + "latitude": 18.2766, + "longitude": -66.335, + "name": "Puerto Rico" + }, + { + "key": [ + "US.RI", + "US-RI", + "US_RhodeIsland" + ], + "latitude": 41.6772, + "longitude": -71.5101, + "name": "Rhode Island" + }, + { + "key": [ + "US.SC", + "US-SC", + "US_SouthCarolina" + ], + "latitude": 33.8191, + "longitude": -80.9066, + "name": "South Carolina" + }, + { + "key": [ + "US.SD", + "US-SD", + "US_SouthDakota" + ], + "latitude": 44.2853, + "longitude": -99.4632, + "name": "South Dakota" + }, + { + "key": [ + "US.TN", + "US-TN", + "US_Tennessee" + ], + "latitude": 35.7449, + "longitude": -86.7489, + "name": "Tennessee" + }, + { + "key": [ + "US.TX", + "US-TX", + "US_Texas" + ], + "latitude": 31.106, + "longitude": -97.6475, + "name": "Texas" + }, + { + "key": [ + "US.UT", + "US-UT", + "US_Utah" + ], + "latitude": 40.1135, + "longitude": -111.8535, + "name": "Utah" + }, + { + "key": [ + "US.VA", + "US-VA", + "US_Virginia" + ], + "latitude": 37.768, + "longitude": -78.2057, + "name": "Virginia" + }, + { + "key": [ + "US.VI", + "US-VI", + "US_U.S.VirginIslands" + ], + "latitude": 18.0001, + "longitude": -64.8199, + "name": "U.S. Virgin Islands" + }, + { + "key": [ + "US.VT", + "US-VT", + "US_Vermont" + ], + "latitude": 44.0407, + "longitude": -72.7093, + "name": "Vermont" + }, + { + "key": [ + "US.WA", + "US-WA", + "US_Washington" + ], + "latitude": 47.3917, + "longitude": -121.5708, + "name": "Washington" + }, + { + "key": [ + "US.WI", + "US-WI", + "US_Wisconsin" + ], + "latitude": 44.2563, + "longitude": -89.6385, + "name": "Wisconsin" + }, + { + "key": [ + "US.WV", + "US-WV", + "US_WestVirginia" + ], + "latitude": 38.468, + "longitude": -80.9696, + "name": "West Virginia" + }, + { + "key": [ + "US.WY", + "US-WY", + "US_Wyoming" + ], + "latitude": 42.7475, + "longitude": -107.2085, + "name": "Wyoming" + }, + { + "key": "AD", + "latitude": 42.546245, + "longitude": 1.601554, + "name": "Andorra" + }, + { + "key": "AE", + "latitude": 23.424076, + "longitude": 53.847818, + "name": "United Arab Emirates" + }, + { + "key": "AF", + "latitude": 33.93911, + "longitude": 67.709953, + "name": "Afghanistan" + }, + { + "key": "AG", + "latitude": 17.060816, + "longitude": -61.796428, + "name": "Antigua and Barbuda" + }, + { + "key": "AI", + "latitude": 18.220554, + "longitude": -63.068615, + "name": "Anguilla" + }, + { + "key": "AL", + "latitude": 41.153332, + "longitude": 20.168331, + "name": "Albania" + }, + { + "key": "AM", + "latitude": 40.069099, + "longitude": 45.038189, + "name": "Armenia" + }, + { + "key": "AN", + "latitude": 12.226079, + "longitude": -69.060087, + "name": "Netherlands Antilles" + }, + { + "key": "AO", + "latitude": -11.202692, + "longitude": 17.873887, + "name": "Angola" + }, + { + "key": "AQ", + "latitude": -75.250973, + "longitude": -0.071389, + "name": "Antarctica" + }, + { + "key": "AR", + "latitude": -38.416097, + "longitude": -63.616672, + "name": "Argentina" + }, + { + "key": "AS", + "latitude": -14.270972, + "longitude": -170.132217, + "name": "American Samoa" + }, + { + "key": "AT", + "latitude": 47.516231, + "longitude": 14.550072, + "name": "Austria" + }, + { + "key": "AU", + "latitude": -25.274398, + "longitude": 133.775136, + "name": "Australia" + }, + { + "key": "AW", + "latitude": 12.52111, + "longitude": -69.968338, + "name": "Aruba" + }, + { + "key": "AX", + "latitude": 60.3385485, + "longitude": 20.2712585, + "name": "Åland" + }, + { + "key": "AZ", + "latitude": 40.143105, + "longitude": 47.576927, + "name": "Azerbaijan" + }, + { + "key": "BA", + "latitude": 43.915886, + "longitude": 17.679076, + "name": "Bosnia and Herzegovina" + }, + { + "key": "BB", + "latitude": 13.193887, + "longitude": -59.543198, + "name": "Barbados" + }, + { + "key": "BD", + "latitude": 23.684994, + "longitude": 90.356331, + "name": "Bangladesh" + }, + { + "key": "BE", + "latitude": 50.503887, + "longitude": 4.469936, + "name": "Belgium" + }, + { + "key": "BF", + "latitude": 12.238333, + "longitude": -1.561593, + "name": "Burkina Faso" + }, + { + "key": "BG", + "latitude": 42.733883, + "longitude": 25.48583, + "name": "Bulgaria" + }, + { + "key": "BH", + "latitude": 25.930414, + "longitude": 50.637772, + "name": "Bahrain" + }, + { + "key": "BI", + "latitude": -3.373056, + "longitude": 29.918886, + "name": "Burundi" + }, + { + "key": "BJ", + "latitude": 9.30769, + "longitude": 2.315834, + "name": "Benin" + }, + { + "key": "BL", + "latitude": 17.9000000, + "longitude": -62.8333330, + "name": "Saint-Barthélemy" + }, + { + "key": "BM", + "latitude": 32.321384, + "longitude": -64.75737, + "name": "Bermuda" + }, + { + "key": "BN", + "latitude": 4.535277, + "longitude": 114.727669, + "name": "Brunei" + }, + { + "key": "BO", + "latitude": -16.290154, + "longitude": -63.588653, + "name": "Bolivia" + }, + { + "key": "BQ", + "latitude": 12.1783611, + "longitude": -68.2385339, + "name": "Bonaire, Sint Eustatius, and Saba" + }, + { + "key": "BR", + "latitude": -14.235004, + "longitude": -51.92528, + "name": "Brazil" + }, + { + "key": "BS", + "latitude": 25.03428, + "longitude": -77.39628, + "name": "Bahamas" + }, + { + "key": "BT", + "latitude": 27.514162, + "longitude": 90.433601, + "name": "Bhutan" + }, + { + "key": "BV", + "latitude": -54.423199, + "longitude": 3.413194, + "name": "Bouvet Island" + }, + { + "key": "BW", + "latitude": -22.328474, + "longitude": 24.684866, + "name": "Botswana" + }, + { + "key": "BY", + "latitude": 53.709807, + "longitude": 27.953389, + "name": "Belarus" + }, + { + "key": "BZ", + "latitude": 17.189877, + "longitude": -88.49765, + "name": "Belize" + }, + { + "key": "CA", + "latitude": 56.130366, + "longitude": -106.346771, + "name": "Canada" + }, + { + "key": "CC", + "latitude": -12.164165, + "longitude": 96.870956, + "name": "Cocos [Keeling] Islands" + }, + { + "key": "CD", + "latitude": -4.038333, + "longitude": 21.758664, + "name": "Congo [DRC]" + }, + { + "key": "CF", + "latitude": 6.611111, + "longitude": 20.939444, + "name": "Central African Republic" + }, + { + "key": "CG", + "latitude": -0.228021, + "longitude": 15.827659, + "name": "Congo [Republic]" + }, + { + "key": "CH", + "latitude": 46.818188, + "longitude": 8.227512, + "name": "Switzerland" + }, + { + "key": "CI", + "latitude": 7.539989, + "longitude": -5.54708, + "name": "Côte d'Ivoire" + }, + { + "key": "CK", + "latitude": -21.236736, + "longitude": -159.777671, + "name": "Cook Islands" + }, + { + "key": "CL", + "latitude": -35.675147, + "longitude": -71.542969, + "name": "Chile" + }, + { + "key": "CM", + "latitude": 7.369722, + "longitude": 12.354722, + "name": "Cameroon" + }, + { + "key": "CN", + "latitude": 37, + "longitude": 92, + "name": "China" + }, + { + "key": "CO", + "latitude": 4.570868, + "longitude": -74.297333, + "name": "Colombia" + }, + { + "key": "CR", + "latitude": 9.748917, + "longitude": -83.753428, + "name": "Costa Rica" + }, + { + "key": "CU", + "latitude": 21.521757, + "longitude": -77.781167, + "name": "Cuba" + }, + { + "key": "CV", + "latitude": 16.002082, + "longitude": -24.013197, + "name": "Cape Verde" + }, + { + "key": "CW", + "latitude": 12.1695700, + "longitude": -68.9900200, + "name": "Curaçao" + }, + { + "key": "CX", + "latitude": -10.447525, + "longitude": 105.690449, + "name": "Christmas Island" + }, + { + "key": "CY", + "latitude": 35.126413, + "longitude": 33.429859, + "name": "Cyprus" + }, + { + "key": "CZ", + "latitude": 49.817492, + "longitude": 15.472962, + "name": "Czech Republic" + }, + { + "key": "DE", + "latitude": 51.165691, + "longitude": 10.451526, + "name": "Germany" + }, + { + "key": "DJ", + "latitude": 11.825138, + "longitude": 42.590275, + "name": "Djibouti" + }, + { + "key": "DK", + "latitude": 56.26392, + "longitude": 9.501785, + "name": "Denmark" + }, + { + "key": "DM", + "latitude": 15.414999, + "longitude": -61.370976, + "name": "Dominica" + }, + { + "key": "DO", + "latitude": 18.735693, + "longitude": -70.162651, + "name": "Dominican Republic" + }, + { + "key": "DZ", + "latitude": 28.033886, + "longitude": 1.659626, + "name": "Algeria" + }, + { + "key": "EC", + "latitude": -1.831239, + "longitude": -78.183406, + "name": "Ecuador" + }, + { + "key": "EE", + "latitude": 58.595272, + "longitude": 25.013607, + "name": "Estonia" + }, + { + "key": "EG", + "latitude": 26.820553, + "longitude": 30.802498, + "name": "Egypt" + }, + { + "key": "EH", + "latitude": 24.215527, + "longitude": -12.885834, + "name": "Western Sahara" + }, + { + "key": "ER", + "latitude": 15.179384, + "longitude": 39.782334, + "name": "Eritrea" + }, + { + "key": "ES", + "latitude": 40.463667, + "longitude": -3.74922, + "name": "Spain" + }, + { + "key": "ET", + "latitude": 9.145, + "longitude": 40.489673, + "name": "Ethiopia" + }, + { + "key": "FI", + "latitude": 61.92411, + "longitude": 25.748151, + "name": "Finland" + }, + { + "key": "FJ", + "latitude": -16.578193, + "longitude": 179.414413, + "name": "Fiji" + }, + { + "key": "FK", + "latitude": -51.796253, + "longitude": -59.523613, + "name": "Falkland Islands [Islas Malvinas]" + }, + { + "key": "FM", + "latitude": 7.425554, + "longitude": 150.550812, + "name": "Micronesia" + }, + { + "key": "FO", + "latitude": 61.892635, + "longitude": -6.911806, + "name": "Faroe Islands" + }, + { + "key": "FR", + "latitude": 46.227638, + "longitude": 2.213749, + "name": "France" + }, + { + "key": "GA", + "latitude": -0.803689, + "longitude": 11.609444, + "name": "Gabon" + }, + { + "key": "GB", + "latitude": 55.378051, + "longitude": -3.435973, + "name": "United Kingdom" + }, + { + "key": "GD", + "latitude": 12.262776, + "longitude": -61.604171, + "name": "Grenada" + }, + { + "key": "GE", + "latitude": 42.315407, + "longitude": 43.356892, + "name": "Georgia" + }, + { + "key": "GF", + "latitude": 3.933889, + "longitude": -53.125782, + "name": "French Guiana" + }, + { + "key": "GG", + "latitude": 49.465691, + "longitude": -2.585278, + "name": "Guernsey" + }, + { + "key": "GH", + "latitude": 7.946527, + "longitude": -1.023194, + "name": "Ghana" + }, + { + "key": "GI", + "latitude": 36.137741, + "longitude": -5.345374, + "name": "Gibraltar" + }, + { + "key": "GL", + "latitude": 71.706936, + "longitude": -42.604303, + "name": "Greenland" + }, + { + "key": "GM", + "latitude": 13.443182, + "longitude": -15.310139, + "name": "Gambia" + }, + { + "key": "GN", + "latitude": 9.945587, + "longitude": -9.696645, + "name": "Guinea" + }, + { + "key": "GP", + "latitude": 16.995971, + "longitude": -62.067641, + "name": "Guadeloupe" + }, + { + "key": "GQ", + "latitude": 1.650801, + "longitude": 10.267895, + "name": "Equatorial Guinea" + }, + { + "key": "GR", + "latitude": 39.074208, + "longitude": 21.824312, + "name": "Greece" + }, + { + "key": "GS", + "latitude": -54.429579, + "longitude": -36.587909, + "name": "South Georgia and the South Sandwich Islands" + }, + { + "key": "GT", + "latitude": 15.783471, + "longitude": -90.230759, + "name": "Guatemala" + }, + { + "key": "GU", + "latitude": 13.444304, + "longitude": 144.793731, + "name": "Guam" + }, + { + "key": "GW", + "latitude": 11.803749, + "longitude": -15.180413, + "name": "Guinea-Bissau" + }, + { + "key": "GY", + "latitude": 4.860416, + "longitude": -58.93018, + "name": "Guyana" + }, + { + "key": "GZ", + "latitude": 31.354676, + "longitude": 34.308825, + "name": "Gaza Strip" + }, + { + "key": "HK", + "latitude": 22.396428, + "longitude": 114.109497, + "name": "Hong Kong" + }, + { + "key": "HM", + "latitude": -53.08181, + "longitude": 73.504158, + "name": "Heard Island and McDonald Islands" + }, + { + "key": "HN", + "latitude": 15.199999, + "longitude": -86.241905, + "name": "Honduras" + }, + { + "key": "HR", + "latitude": 45.1, + "longitude": 15.2, + "name": "Croatia" + }, + { + "key": "HT", + "latitude": 18.971187, + "longitude": -72.285215, + "name": "Haiti" + }, + { + "key": "HU", + "latitude": 47.162494, + "longitude": 19.503304, + "name": "Hungary" + }, + { + "key": "ID", + "latitude": -0.789275, + "longitude": 113.921327, + "name": "Indonesia" + }, + { + "key": "IE", + "latitude": 53.41291, + "longitude": -8.24389, + "name": "Ireland" + }, + { + "key": "IL", + "latitude": 31.046051, + "longitude": 34.851612, + "name": "Israel" + }, + { + "key": "IM", + "latitude": 54.236107, + "longitude": -4.548056, + "name": "Isle of Man" + }, + { + "key": "IN", + "latitude": 20.593684, + "longitude": 78.96288, + "name": "India" + }, + { + "key": "IO", + "latitude": -6.343194, + "longitude": 71.876519, + "name": "British Indian Ocean Territory" + }, + { + "key": "IQ", + "latitude": 33.223191, + "longitude": 43.679291, + "name": "Iraq" + }, + { + "key": "IR", + "latitude": 32.427908, + "longitude": 53.688046, + "name": "Iran" + }, + { + "key": "IS", + "latitude": 64.963051, + "longitude": -19.020835, + "name": "Iceland" + }, + { + "key": "IT", + "latitude": 41.87194, + "longitude": 12.56738, + "name": "Italy" + }, + { + "key": "JE", + "latitude": 49.214439, + "longitude": -2.13125, + "name": "Jersey" + }, + { + "key": "JM", + "latitude": 18.109581, + "longitude": -77.297508, + "name": "Jamaica" + }, + { + "key": "JO", + "latitude": 30.585164, + "longitude": 36.238414, + "name": "Jordan" + }, + { + "key": "JP", + "latitude": 36.204824, + "longitude": 138.252924, + "name": "Japan" + }, + { + "key": "KE", + "latitude": -0.023559, + "longitude": 37.906193, + "name": "Kenya" + }, + { + "key": "KG", + "latitude": 41.20438, + "longitude": 74.766098, + "name": "Kyrgyzstan" + }, + { + "key": "KH", + "latitude": 12.565679, + "longitude": 104.990963, + "name": "Cambodia" + }, + { + "key": "KI", + "latitude": -3.370417, + "longitude": -168.734039, + "name": "Kiribati" + }, + { + "key": "KM", + "latitude": -11.875001, + "longitude": 43.872219, + "name": "Comoros" + }, + { + "key": "KN", + "latitude": 17.357822, + "longitude": -62.782998, + "name": "Saint Kitts and Nevis" + }, + { + "key": "KP", + "latitude": 40.339852, + "longitude": 127.510093, + "name": "North Korea" + }, + { + "key": "KR", + "latitude": 35.907757, + "longitude": 127.766922, + "name": "South Korea" + }, + { + "key": "KW", + "latitude": 29.31166, + "longitude": 47.481766, + "name": "Kuwait" + }, + { + "key": "KY", + "latitude": 19.513469, + "longitude": -80.566956, + "name": "Cayman Islands" + }, + { + "key": "KZ", + "latitude": 48.019573, + "longitude": 66.923684, + "name": "Kazakhstan" + }, + { + "key": "LA", + "latitude": 19.85627, + "longitude": 102.495496, + "name": "Laos" + }, + { + "key": "LB", + "latitude": 33.854721, + "longitude": 35.862285, + "name": "Lebanon" + }, + { + "key": "LC", + "latitude": 13.909444, + "longitude": -60.978893, + "name": "Saint Lucia" + }, + { + "key": "LI", + "latitude": 47.166, + "longitude": 9.555373, + "name": "Liechtenstein" + }, + { + "key": "LK", + "latitude": 7.873054, + "longitude": 80.771797, + "name": "Sri Lanka" + }, + { + "key": "LR", + "latitude": 6.428055, + "longitude": -9.429499, + "name": "Liberia" + }, + { + "key": "LS", + "latitude": -29.609988, + "longitude": 28.233608, + "name": "Lesotho" + }, + { + "key": "LT", + "latitude": 55.169438, + "longitude": 23.881275, + "name": "Lithuania" + }, + { + "key": "LU", + "latitude": 49.815273, + "longitude": 6.129583, + "name": "Luxembourg" + }, + { + "key": "LV", + "latitude": 56.879635, + "longitude": 24.603189, + "name": "Latvia" + }, + { + "key": "LY", + "latitude": 26.3351, + "longitude": 17.228331, + "name": "Libya" + }, + { + "key": "MA", + "latitude": 31.791702, + "longitude": -7.09262, + "name": "Morocco" + }, + { + "key": "MC", + "latitude": 43.750298, + "longitude": 7.412841, + "name": "Monaco" + }, + { + "key": "MD", + "latitude": 47.411631, + "longitude": 28.369885, + "name": "Moldova" + }, + { + "key": "ME", + "latitude": 42.708678, + "longitude": 19.37439, + "name": "Montenegro" + }, + { + "key": "MF", + "latitude": 18.0825500, + "longitude": -63.0522510, + "name": "Saint Martin" + }, + { + "key": "MG", + "latitude": -18.766947, + "longitude": 46.869107, + "name": "Madagascar" + }, + { + "key": "MH", + "latitude": 7.131474, + "longitude": 171.184478, + "name": "Marshall Islands" + }, + { + "key": "MK", + "latitude": 41.608635, + "longitude": 21.745275, + "name": "Macedonia [FYROM]" + }, + { + "key": "ML", + "latitude": 17.570692, + "longitude": -3.996166, + "name": "Mali" + }, + { + "key": "MM", + "latitude": 21.913965, + "longitude": 95.956223, + "name": "Myanmar [Burma]" + }, + { + "key": "MN", + "latitude": 46.862496, + "longitude": 103.846656, + "name": "Mongolia" + }, + { + "key": "MO", + "latitude": 22.198745, + "longitude": 113.543873, + "name": "Macau" + }, + { + "key": "MP", + "latitude": 17.33083, + "longitude": 145.38469, + "name": "Northern Mariana Islands" + }, + { + "key": "MQ", + "latitude": 14.641528, + "longitude": -61.024174, + "name": "Martinique" + }, + { + "key": "MR", + "latitude": 21.00789, + "longitude": -10.940835, + "name": "Mauritania" + }, + { + "key": "MS", + "latitude": 16.742498, + "longitude": -62.187366, + "name": "Montserrat" + }, + { + "key": "MT", + "latitude": 35.937496, + "longitude": 14.375416, + "name": "Malta" + }, + { + "key": "MU", + "latitude": -20.348404, + "longitude": 57.552152, + "name": "Mauritius" + }, + { + "key": "MV", + "latitude": 3.202778, + "longitude": 73.22068, + "name": "Maldives" + }, + { + "key": "MW", + "latitude": -13.254308, + "longitude": 34.301525, + "name": "Malawi" + }, + { + "key": "MX", + "latitude": 23.634501, + "longitude": -102.552784, + "name": "Mexico" + }, + { + "key": "MY", + "latitude": 4.210484, + "longitude": 101.975766, + "name": "Malaysia" + }, + { + "key": "MZ", + "latitude": -18.665695, + "longitude": 35.529562, + "name": "Mozambique" + }, + { + "key": "NA", + "latitude": -22.95764, + "longitude": 18.49041, + "name": "Namibia" + }, + { + "key": "NC", + "latitude": -20.904305, + "longitude": 165.618042, + "name": "New Caledonia" + }, + { + "key": "NE", + "latitude": 17.607789, + "longitude": 8.081666, + "name": "Niger" + }, + { + "key": "NF", + "latitude": -29.040835, + "longitude": 167.954712, + "name": "Norfolk Island" + }, + { + "key": "NG", + "latitude": 9.081999, + "longitude": 8.675277, + "name": "Nigeria" + }, + { + "key": "NI", + "latitude": 12.865416, + "longitude": -85.207229, + "name": "Nicaragua" + }, + { + "key": "NL", + "latitude": 52.132633, + "longitude": 5.291266, + "name": "Netherlands" + }, + { + "key": "NO", + "latitude": 60.472024, + "longitude": 8.468946, + "name": "Norway" + }, + { + "key": "NP", + "latitude": 28.394857, + "longitude": 84.124008, + "name": "Nepal" + }, + { + "key": "NR", + "latitude": -0.522778, + "longitude": 166.931503, + "name": "Nauru" + }, + { + "key": "NU", + "latitude": -19.054445, + "longitude": -169.867233, + "name": "Niue" + }, + { + "key": "NZ", + "latitude": -40.900557, + "longitude": 174.885971, + "name": "New Zealand" + }, + { + "key": "OM", + "latitude": 21.512583, + "longitude": 55.923255, + "name": "Oman" + }, + { + "key": "PA", + "latitude": 8.537981, + "longitude": -80.782127, + "name": "Panama" + }, + { + "key": "PE", + "latitude": -9.189967, + "longitude": -75.015152, + "name": "Peru" + }, + { + "key": "PF", + "latitude": -17.679742, + "longitude": -149.406843, + "name": "French Polynesia" + }, + { + "key": "PG", + "latitude": -6.314993, + "longitude": 143.95555, + "name": "Papua New Guinea" + }, + { + "key": "PH", + "latitude": 12.879721, + "longitude": 121.774017, + "name": "Philippines" + }, + { + "key": "PK", + "latitude": 30.375321, + "longitude": 69.345116, + "name": "Pakistan" + }, + { + "key": "PL", + "latitude": 51.919438, + "longitude": 19.145136, + "name": "Poland" + }, + { + "key": "PM", + "latitude": 46.941936, + "longitude": -56.27111, + "name": "Saint Pierre and Miquelon" + }, + { + "key": "PN", + "latitude": -24.703615, + "longitude": -127.439308, + "name": "Pitcairn Islands" + }, + { + "key": "PR", + "latitude": 18.220833, + "longitude": -66.590149, + "name": "Puerto Rico" + }, + { + "key": "PS", + "latitude": 31.952162, + "longitude": 35.233154, + "name": "Palestinian Territories" + }, + { + "key": "PT", + "latitude": 39.399872, + "longitude": -8.224454, + "name": "Portugal" + }, + { + "key": "PW", + "latitude": 7.51498, + "longitude": 134.58252, + "name": "Palau" + }, + { + "key": "PY", + "latitude": -23.442503, + "longitude": -58.443832, + "name": "Paraguay" + }, + { + "key": "QA", + "latitude": 25.354826, + "longitude": 51.183884, + "name": "Qatar" + }, + { + "key": "RE", + "latitude": -21.115141, + "longitude": 55.536384, + "name": "Réunion" + }, + { + "key": "RO", + "latitude": 45.943161, + "longitude": 24.96676, + "name": "Romania" + }, + { + "key": "RS", + "latitude": 44.016521, + "longitude": 21.005859, + "name": "Serbia" + }, + { + "key": "RU", + "latitude": 61.52401, + "longitude": 105.318756, + "name": "Russia" + }, + { + "key": "RW", + "latitude": -1.940278, + "longitude": 29.873888, + "name": "Rwanda" + }, + { + "key": "SA", + "latitude": 23.885942, + "longitude": 45.079162, + "name": "Saudi Arabia" + }, + { + "key": "SB", + "latitude": -9.64571, + "longitude": 160.156194, + "name": "Solomon Islands" + }, + { + "key": "SC", + "latitude": -4.679574, + "longitude": 55.491977, + "name": "Seychelles" + }, + { + "key": "SD", + "latitude": 12.862807, + "longitude": 30.217636, + "name": "Sudan" + }, + { + "key": "SE", + "latitude": 60.128161, + "longitude": 18.643501, + "name": "Sweden" + }, + { + "key": "SG", + "latitude": 1.352083, + "longitude": 103.819836, + "name": "Singapore" + }, + { + "key": "SH", + "latitude": -24.143474, + "longitude": -10.030696, + "name": "Saint Helena" + }, + { + "key": "SI", + "latitude": 46.151241, + "longitude": 14.995463, + "name": "Slovenia" + }, + { + "key": "SJ", + "latitude": 77.553604, + "longitude": 23.670272, + "name": "Svalbard and Jan Mayen" + }, + { + "key": "SK", + "latitude": 48.669026, + "longitude": 19.699024, + "name": "Slovakia" + }, + { + "key": "SL", + "latitude": 8.460555, + "longitude": -11.779889, + "name": "Sierra Leone" + }, + { + "key": "SM", + "latitude": 43.94236, + "longitude": 12.457777, + "name": "San Marino" + }, + { + "key": "SN", + "latitude": 14.497401, + "longitude": -14.452362, + "name": "Senegal" + }, + { + "key": "SO", + "latitude": 5.152149, + "longitude": 46.199616, + "name": "Somalia" + }, + { + "key": "SR", + "latitude": 3.919305, + "longitude": -56.027783, + "name": "Suriname" + }, + { + "key": "ST", + "latitude": 0.18636, + "longitude": 6.613081, + "name": "São Tomé and Príncipe" + }, + { + "key": "SV", + "latitude": 13.794185, + "longitude": -88.89653, + "name": "El Salvador" + }, + { + "key": "SX", + "latitude": 18.030827, + "longitude": -63.073633, + "name": "Sint Maarten" + }, + { + "key": "SY", + "latitude": 34.802075, + "longitude": 38.996815, + "name": "Syria" + }, + { + "key": "SZ", + "latitude": -26.522503, + "longitude": 31.465866, + "name": "Swaziland" + }, + { + "key": "TC", + "latitude": 21.694025, + "longitude": -71.797928, + "name": "Turks and Caicos Islands" + }, + { + "key": "TD", + "latitude": 15.454166, + "longitude": 18.732207, + "name": "Chad" + }, + { + "key": "TF", + "latitude": -49.280366, + "longitude": 69.348557, + "name": "French Southern Territories" + }, + { + "key": "TG", + "latitude": 8.619543, + "longitude": 0.824782, + "name": "Togo" + }, + { + "key": "TH", + "latitude": 15.870032, + "longitude": 100.992541, + "name": "Thailand" + }, + { + "key": "TJ", + "latitude": 38.861034, + "longitude": 71.276093, + "name": "Tajikistan" + }, + { + "key": "TK", + "latitude": -8.967363, + "longitude": -171.855881, + "name": "Tokelau" + }, + { + "key": "TL", + "latitude": -8.874217, + "longitude": 125.727539, + "name": "Timor-Leste" + }, + { + "key": "TM", + "latitude": 38.969719, + "longitude": 59.556278, + "name": "Turkmenistan" + }, + { + "key": "TN", + "latitude": 33.886917, + "longitude": 9.537499, + "name": "Tunisia" + }, + { + "key": "TO", + "latitude": -21.178986, + "longitude": -175.198242, + "name": "Tonga" + }, + { + "key": "TR", + "latitude": 38.963745, + "longitude": 35.243322, + "name": "Turkey" + }, + { + "key": "TT", + "latitude": 10.691803, + "longitude": -61.222503, + "name": "Trinidad and Tobago" + }, + { + "key": "TV", + "latitude": -7.109535, + "longitude": 177.64933, + "name": "Tuvalu" + }, + { + "key": "TW", + "latitude": 23.69781, + "longitude": 120.960515, + "name": "Taiwan" + }, + { + "key": "TZ", + "latitude": -6.369028, + "longitude": 34.888822, + "name": "Tanzania" + }, + { + "key": "UA", + "latitude": 48.379433, + "longitude": 31.16558, + "name": "Ukraine" + }, + { + "key": "UG", + "latitude": 1.373333, + "longitude": 32.290275, + "name": "Uganda" + }, + { + "key": "UM", + "latitude": 0, + "longitude": 0, + "name": "U.S. Minor Outlying Islands" + }, + { + "key": "US", + "latitude": 37.09024, + "longitude": -95.712891, + "name": "United States" + }, + { + "key": "UY", + "latitude": -32.522779, + "longitude": -55.765835, + "name": "Uruguay" + }, + { + "key": "UZ", + "latitude": 41.377491, + "longitude": 64.585262, + "name": "Uzbekistan" + }, + { + "key": "VA", + "latitude": 41.902916, + "longitude": 12.453389, + "name": "Vatican City" + }, + { + "key": "VC", + "latitude": 12.984305, + "longitude": -61.287228, + "name": "Saint Vincent and the Grenadines" + }, + { + "key": "VE", + "latitude": 6.42375, + "longitude": -66.58973, + "name": "Venezuela" + }, + { + "key": "VG", + "latitude": 18.420695, + "longitude": -64.639968, + "name": "British Virgin Islands" + }, + { + "key": "VI", + "latitude": 18.335765, + "longitude": -64.896335, + "name": "U.S. Virgin Islands" + }, + { + "key": "VN", + "latitude": 14.058324, + "longitude": 108.277199, + "name": "Vietnam" + }, + { + "key": "VU", + "latitude": -15.376706, + "longitude": 166.959158, + "name": "Vanuatu" + }, + { + "key": "WF", + "latitude": -13.768752, + "longitude": -177.156097, + "name": "Wallis and Futuna" + }, + { + "key": "WS", + "latitude": -13.759029, + "longitude": -172.104629, + "name": "Samoa" + }, + { + "key": "XK", + "latitude": 42.602636, + "longitude": 20.902977, + "name": "Kosovo" + }, + { + "key": "YE", + "latitude": 15.552727, + "longitude": 48.516388, + "name": "Yemen" + }, + { + "key": "YT", + "latitude": -12.8275, + "longitude": 45.166244, + "name": "Mayotte" + }, + { + "key": "ZA", + "latitude": -30.559482, + "longitude": 22.937506, + "name": "South Africa" + }, + { + "key": "ZM", + "latitude": -13.133897, + "longitude": 27.849332, + "name": "Zambia" + }, + { + "key": "ZW", + "latitude": -19.015438, + "longitude": 29.154857, + "name": "Zimbabwe" + } +] diff --git a/src/data_formatter.test.ts b/src/data_formatter.test.ts index 2dbebdd..3fe3441 100644 --- a/src/data_formatter.test.ts +++ b/src/data_formatter.test.ts @@ -287,6 +287,131 @@ describe('DataFormatter', () => { }); }); + describe('when the time series data only match unknown in location', () => { + beforeEach(() => { + jQuery.extend(ctrl, { + panel: { + valueName: 'total', + }, + locations: [ + { key: 'IE', name: 'Ireland', latitude: 1, longitude: 1 }, + { key: 'unknown', name: 'Unknown', latitude: 99, longitude: 99 }, + ], + series: [ + { alias: 'SX', datapoints: [1, 2], stats: { total: 3 } }, + { alias: 'IE', datapoints: [5, 2], stats: { total: 7 } }, + ], + }); + dataFormatter = new DataFormatter(ctrl); + dataFormatter.setTimeseriesValues(ctrl.series, formattedData); + }); + + it('should format the data and match the serie to a location', () => { + expect(formattedData[1].key).toEqual('IE'); + expect(formattedData[1].locationName).toEqual('Ireland'); + expect(formattedData[1].locationLatitude).toEqual(1); + expect(formattedData[1].locationLongitude).toEqual(1); + expect(formattedData[1].value).toEqual(7); + + expect(formattedData[0].key).toEqual('SX'); + expect(formattedData[0].locationName).toEqual('Unknown'); + expect(formattedData[0].locationLatitude).toEqual(99); + expect(formattedData[0].locationLongitude).toEqual(99); + expect(formattedData[0].value).toEqual(3); + }); + }); + + describe('when the time series partially match in location', () => { + beforeEach(() => { + jQuery.extend(ctrl, { + panel: { + valueName: 'total', + }, + locations: [ + { key: 'IE', name: 'Ireland', latitude: 1, longitude: 1 }, + { key: 'IE.Loc1', name: 'Ireland Loc1', latitude: 1, longitude: 2 }, + { key: 'unknown', name: 'Unknown', latitude: 99, longitude: 99 }, + ], + series: [ + { alias: 'SX', datapoints: [1, 2], stats: { total: 3 } }, + { alias: 'IE.loC1-Sub2', datapoints: [5, 2], stats: { total: 7 } }, + { alias: 'IE.loC1Sub2', datapoints: [15, 2], stats: { total: 17 } }, + ], + }); + dataFormatter = new DataFormatter(ctrl); + dataFormatter.setTimeseriesValues(ctrl.series, formattedData); + }); + + it('should format the data and match the serie to a location', () => { + expect(formattedData[1].key).toEqual('IE.loC1-Sub2'); + expect(formattedData[1].locationName).toEqual('Ireland Loc1'); + expect(formattedData[1].locationLatitude).toEqual(1); + expect(formattedData[1].locationLongitude).toEqual(2); + expect(formattedData[1].value).toEqual(7); + + expect(formattedData[2].key).toEqual('IE.loC1Sub2'); + expect(formattedData[2].locationName).toEqual('Ireland'); + expect(formattedData[2].locationLatitude).toEqual(1); + expect(formattedData[2].locationLongitude).toEqual(1); + expect(formattedData[2].value).toEqual(17); + + expect(formattedData[0].key).toEqual('SX'); + expect(formattedData[0].locationName).toEqual('Unknown'); + expect(formattedData[0].locationLatitude).toEqual(99); + expect(formattedData[0].locationLongitude).toEqual(99); + expect(formattedData[0].value).toEqual(3); + }); + }); + + describe('when the location data key is array', () => { + beforeEach(() => { + jQuery.extend(ctrl, { + panel: { + valueName: 'total', + }, + locations: [ + { key: 'IE', name: 'Ireland', latitude: 1, longitude: 1 }, + { key: ['IE.Loc1', 'IE-L1'], name: 'Ireland Loc1', latitude: 1, longitude: 2 }, + { key: 'unknown', name: 'Unknown', latitude: 99, longitude: 99 }, + ], + series: [ + { alias: 'SX', datapoints: [1, 2], stats: { total: 3 } }, + { alias: 'IE.loC1-Sub2', datapoints: [5, 2], stats: { total: 7 } }, + { alias: 'IE-l1-Sub2', datapoints: [2, 2], stats: { total: 4 } }, + { alias: 'IE.loC1Sub2', datapoints: [15, 2], stats: { total: 17 } }, + ], + }); + dataFormatter = new DataFormatter(ctrl); + dataFormatter.setTimeseriesValues(ctrl.series, formattedData); + }); + + it('should format the data and match the serie to a location', () => { + expect(formattedData[1].key).toEqual('IE.loC1-Sub2'); + expect(formattedData[1].locationName).toEqual('Ireland Loc1'); + expect(formattedData[1].locationLatitude).toEqual(1); + expect(formattedData[1].locationLongitude).toEqual(2); + expect(formattedData[1].value).toEqual(7); + + expect(formattedData[2].key).toEqual('IE-l1-Sub2'); + expect(formattedData[2].locationName).toEqual('Ireland Loc1'); + expect(formattedData[2].locationLatitude).toEqual(1); + expect(formattedData[2].locationLongitude).toEqual(2); + expect(formattedData[2].value).toEqual(4); + + expect(formattedData[3].key).toEqual('IE.loC1Sub2'); + expect(formattedData[3].locationName).toEqual('Ireland'); + expect(formattedData[3].locationLatitude).toEqual(1); + expect(formattedData[3].locationLongitude).toEqual(1); + expect(formattedData[3].value).toEqual(17); + + expect(formattedData[0].key).toEqual('SX'); + expect(formattedData[0].locationName).toEqual('Unknown'); + expect(formattedData[0].locationLatitude).toEqual(99); + expect(formattedData[0].locationLongitude).toEqual(99); + expect(formattedData[0].value).toEqual(3); + }); + }); + describe('when the time series data has decimals', () => { describe('and decimals are specified as an integer', () => { beforeEach(() => { diff --git a/src/data_formatter.ts b/src/data_formatter.ts index 41045e5..2a7cbfd 100644 --- a/src/data_formatter.ts +++ b/src/data_formatter.ts @@ -87,17 +87,41 @@ export default class DataFormatter { if (seriesData && seriesData.length > 0) { let highestValue = 0; let lowestValue = Number.MAX_VALUE; + let locMap = {}; + this.ctrl.locations.forEach(loc => { + let keys = _.isArray(loc.key) ? loc.key : [loc.key]; + keys.forEach(key => { + locMap[key.toUpperCase()] = loc; + }); + }); + + let _lastIndexOfDelimiters = function(str) { + const delimiters = '._-'; + let ind = str.length - 1; + for (; ind >= 0; ind--) { + if (delimiters.indexOf(str.charAt(ind)) >= 0) { + break; + } + } + return ind; + }; seriesData.forEach(serie => { const lastPoint = _.last(serie.datapoints); const lastValue = _.isArray(lastPoint) ? lastPoint[0] : null; - const location = _.find(this.ctrl.locations, loc => { - return loc.key.toUpperCase() === serie.alias.toUpperCase(); - }); - - // Todo: Propagate user-level notification? - if (!location) { - return; + let aliasCap = serie.alias.toUpperCase(); + let location = locMap[aliasCap]; + while (!location) { + let ind = _lastIndexOfDelimiters(aliasCap); + if (ind <= 0) { + location = locMap['UNKNOWN']; + if (location) { + break; + } + return; + } + aliasCap = aliasCap.substr(0, ind); + location = locMap[aliasCap]; } if (_.isString(lastValue)) { diff --git a/src/model.ts b/src/model.ts index e0ef570..a454919 100644 --- a/src/model.ts +++ b/src/model.ts @@ -74,6 +74,12 @@ export const LocationSources = [ type: LocationType.TimeseriesBuiltin, format: LocationFormat.Timeseries, }, + { + id: 'world_regions', + label: '2-letter country codes with optional region code', + type: LocationType.TimeseriesBuiltin, + format: LocationFormat.Timeseries, + }, { id: 'states', label: '2-letter US state codes', diff --git a/src/partials/editor.html b/src/partials/editor.html index 1cfe2cc..edbab01 100644 --- a/src/partials/editor.html +++ b/src/partials/editor.html @@ -228,6 +228,13 @@
Mapping time series data
The time series (group by) name should be a 3-letter country code. For example "USA" for United States or "FRA" for France.

+
+
Mapping time series data
+

+ The query should be formatted as time series data. + The time series (group by) name should be a 2-letter country code with optional region code. + For example: CN_Beijing or CN-BJ for Beijing in China.

+
Mapping time series data

diff --git a/src/worldmap.test.ts b/src/worldmap.test.ts index 58008d1..0318ab4 100644 --- a/src/worldmap.test.ts +++ b/src/worldmap.test.ts @@ -27,6 +27,19 @@ describe('Worldmap', () => { }); }); + describe('when the data value is too big', () => { + it('should keep 4 significant digits and append k,M,G etc', () => { + expect(worldMap.addUnit(123)).toBe(123); + expect(worldMap.addUnit(1234)).toBe('1.234k'); + expect(worldMap.addUnit(12345)).toBe('12.35k'); + expect(worldMap.addUnit(123456789)).toBe('123.5M'); + expect(worldMap.addUnit(643456343745345642)).toBe('643.5P'); + expect(worldMap.addUnit(7653643456343745345642)).toBe('7.654Z'); + expect(worldMap.addUnit(999999653643456343745345642)).toBe('1000Y'); + expect(worldMap.addUnit(79999999653643456343745345642)).toBe('80000Y'); + }); + }); + describe('when the data has one point', () => { beforeEach(() => { ctrl.data = new DataBuilder() @@ -161,7 +174,7 @@ describe('Worldmap', () => { }); it('should create a circle with circle size 6 for mid value size', () => { - expect(worldMap.circles[1].options.radius).toBe(6); + expect(worldMap.circles[1].options.radius).toBe(Math.sqrt(52)); }); it('should create a circle with max circle size for largest value size', () => { diff --git a/src/worldmap.ts b/src/worldmap.ts index 18aa96f..e820aa8 100644 --- a/src/worldmap.ts +++ b/src/worldmap.ts @@ -347,9 +347,27 @@ export default class WorldMap { } const dataFactor = (dataPointValue - this.ctrl.data.lowestValue) / this.ctrl.data.valueRange; - const circleSizeRange = circleMaxSize - circleMinSize; + const circleSizeRange = (circleMaxSize - circleMinSize) * (circleMaxSize + circleMinSize); - return circleSizeRange * dataFactor + circleMinSize; + return Math.sqrt(circleSizeRange * dataFactor + circleMinSize * circleMinSize); + } + + addUnit(n) { + const Units = 'kMGTPEZY'; + let e = -1; + while (n >= 1000 && e < Units.length - 1) { + n = Math.round(n) / 1000; + e++; + } + if (n >= 100) { + n = Math.round(n * 10) / 10; + } else if (n >= 10) { + n = Math.round(n * 100) / 100; + } + if (e >= 0) { + n += Units.charAt(e); + } + return n; } createClickthrough(circle, dataPoint) { @@ -432,7 +450,7 @@ export default class WorldMap { if (this.ctrl.settings.formatOmitEmptyValue && value === 'n/a') { return `${locationName}`.trim(); } else { - return `${locationName}: ${value} ${unit || ''}`.trim(); + return `${locationName}: ${this.addUnit(value)} ${unit || ''}`.trim(); } }