svgmap
Version:
svgMap is a JavaScript library that lets you easily create an interactable world map comparing customizable data for each country.
1,434 lines (1,327 loc) • 154 kB
JavaScript
/*! svgMap | https://github.com/StephanWagner/svgMap | MIT License | Copyright Stephan Wagner | https://stephanwagner.me */
// Wrapper function
function svgMapWrapper(svgPanZoom) {
var svgMap = function (options) {
this.init(options);
};
// Initialize SVG Worldmap
svgMap.prototype.init = function (options) {
// Default options, pass a custom options object to overwrite specific
var defaultOptions = {
// The element to render the map in
targetElementID: '',
// Minimum and maximum zoom
minZoom: 1,
maxZoom: 25,
// Initial zoom
initialZoom: 1.06,
// Initial pan
initialPan: {
x: 0,
y: 0
},
// Zoom sensitivity
zoomScaleSensitivity: 0.2,
// Zoom with mousewheel
mouseWheelZoomEnabled: true,
// Allow zooming only when one of the following keys is pressed: 'shift', 'control', 'alt' (Windows), 'command' (MacOS), 'option' (MacOS)
mouseWheelZoomWithKey: false,
// The message to show for non MacOS systems
mouseWheelKeyMessage: 'Press the [ALT] key to zoom',
// The message to show for MacOS
mouseWheelKeyMessageMac: 'Press the [COMMAND] key to zoom',
// Data colors
colorMax: '#CC0033',
colorMin: '#FFE5D9',
colorNoData: '#E2E2E2',
// Color attribute for setting a manual color in the data object
manualColorAttribute: 'color',
// The flag type can be 'image' or 'emoji'
flagType: 'image',
// The URL to the flags when using flag type 'image', {0} will get replaced with the lowercase country id
flagURL:
'https://cdn.jsdelivr.net/gh/hjnilsson/country-flags@latest/svg/{0}.svg',
// Decide whether to show the flag option or not
hideFlag: false,
// Whether attributes with no data should be displayed
hideMissingData: false,
// The default text to be shown when no data is present
noDataText: 'No data available',
// Set to true to open the link on mobile devices, set to false (default) to show the tooltip
touchLink: false,
// Set to true to show the to show a zoom reset button
showZoomReset: false,
// Called when a tooltip is created to custimize the tooltip content
onGetTooltip: function (tooltipDiv, countryID, countryValues) {
return null;
},
// Country specific options
countries: {
// Western Sahara: Set to false to combine Morocco (MA) and Western Sahara (EH)
EH: true
},
// Set to true to show a drop down menu with the continents
showContinentSelector: false,
};
this.options = Object.assign({}, defaultOptions, options || {});
// Abort if target element not found
if (
!this.options.targetElementID ||
!document.getElementById(this.options.targetElementID)
) {
this.error('Target element not found');
}
// Abort if no data
if (!this.options.data) {
this.error('No data');
}
// Global id
this.id = this.options.targetElementID;
// Wrapper element
this.wrapper = document.getElementById(this.options.targetElementID);
this.wrapper.classList.add('svgMap-wrapper');
// Container element
this.container = document.createElement('div');
this.container.classList.add('svgMap-container');
this.wrapper.appendChild(this.container);
// Block scrolling when option is enabled
if (
this.options.mouseWheelZoomEnabled &&
this.options.mouseWheelZoomWithKey
) {
this.addMouseWheelZoomNotice();
this.addMouseWheelZoomWithKeyEvents();
}
// Map container element
this.mapContainer = document.createElement('div');
this.mapContainer.classList.add('svgMap-map-container');
this.container.appendChild(this.mapContainer);
// Create the map
this.createMap();
// Apply map data
this.applyData(this.options.data);
};
// Countries
svgMap.prototype.countries = {
AF: 'Afghanistan',
AX: 'Åland Islands',
AL: 'Albania',
DZ: 'Algeria',
AS: 'American Samoa',
AD: 'Andorra',
AO: 'Angola',
AI: 'Anguilla',
AQ: 'Antarctica',
AG: 'Antigua and Barbuda',
AR: 'Argentina',
AM: 'Armenia',
AW: 'Aruba',
AU: 'Australia',
AT: 'Austria',
AZ: 'Azerbaijan',
BS: 'Bahamas',
BH: 'Bahrain',
BD: 'Bangladesh',
BB: 'Barbados',
BY: 'Belarus',
BE: 'Belgium',
BZ: 'Belize',
BJ: 'Benin',
BM: 'Bermuda',
BT: 'Bhutan',
BO: 'Bolivia',
BA: 'Bosnia and Herzegovina',
BW: 'Botswana',
BR: 'Brazil',
IO: 'British Indian Ocean Territory',
VG: 'British Virgin Islands',
BN: 'Brunei Darussalam',
BG: 'Bulgaria',
BF: 'Burkina Faso',
BI: 'Burundi',
KH: 'Cambodia',
CM: 'Cameroon',
CA: 'Canada',
CV: 'Cape Verde',
BQ: 'Caribbean Netherlands',
KY: 'Cayman Islands',
CF: 'Central African Republic',
TD: 'Chad',
CL: 'Chile',
CN: 'China',
CX: 'Christmas Island',
CC: 'Cocos Islands',
CO: 'Colombia',
KM: 'Comoros',
CG: 'Congo',
CK: 'Cook Islands',
CR: 'Costa Rica',
HR: 'Croatia',
CU: 'Cuba',
CW: 'Curaçao',
CY: 'Cyprus',
CZ: 'Czech Republic',
CD: 'Democratic Republic of the Congo',
DK: 'Denmark',
DJ: 'Djibouti',
DM: 'Dominica',
DO: 'Dominican Republic',
EC: 'Ecuador',
EG: 'Egypt',
SV: 'El Salvador',
GQ: 'Equatorial Guinea',
ER: 'Eritrea',
EE: 'Estonia',
ET: 'Ethiopia',
FK: 'Falkland Islands',
FO: 'Faroe Islands',
FM: 'Federated States of Micronesia',
FJ: 'Fiji',
FI: 'Finland',
FR: 'France',
GF: 'French Guiana',
PF: 'French Polynesia',
TF: 'French Southern Territories',
GA: 'Gabon',
GM: 'Gambia',
GE: 'Georgia',
DE: 'Germany',
GH: 'Ghana',
GI: 'Gibraltar',
GR: 'Greece',
GL: 'Greenland',
GD: 'Grenada',
GP: 'Guadeloupe',
GU: 'Guam',
GT: 'Guatemala',
GN: 'Guinea',
GW: 'Guinea-Bissau',
GY: 'Guyana',
HT: 'Haiti',
HN: 'Honduras',
HK: 'Hong Kong',
HU: 'Hungary',
IS: 'Iceland',
IN: 'India',
ID: 'Indonesia',
IR: 'Iran',
IQ: 'Iraq',
IE: 'Ireland',
IM: 'Isle of Man',
IL: 'Israel',
IT: 'Italy',
CI: 'Ivory Coast',
JM: 'Jamaica',
JP: 'Japan',
JE: 'Jersey',
JO: 'Jordan',
KZ: 'Kazakhstan',
KE: 'Kenya',
KI: 'Kiribati',
XK: 'Kosovo',
KW: 'Kuwait',
KG: 'Kyrgyzstan',
LA: 'Laos',
LV: 'Latvia',
LB: 'Lebanon',
LS: 'Lesotho',
LR: 'Liberia',
LY: 'Libya',
LI: 'Liechtenstein',
LT: 'Lithuania',
LU: 'Luxembourg',
MO: 'Macau',
MK: 'Macedonia',
MG: 'Madagascar',
MW: 'Malawi',
MY: 'Malaysia',
MV: 'Maldives',
ML: 'Mali',
MT: 'Malta',
MH: 'Marshall Islands',
MQ: 'Martinique',
MR: 'Mauritania',
MU: 'Mauritius',
YT: 'Mayotte',
MX: 'Mexico',
MD: 'Moldova',
MC: 'Monaco',
MN: 'Mongolia',
ME: 'Montenegro',
MS: 'Montserrat',
MA: 'Morocco',
MZ: 'Mozambique',
MM: 'Myanmar',
NA: 'Namibia',
NR: 'Nauru',
NP: 'Nepal',
NL: 'Netherlands',
NC: 'New Caledonia',
NZ: 'New Zealand',
NI: 'Nicaragua',
NE: 'Niger',
NG: 'Nigeria',
NU: 'Niue',
NF: 'Norfolk Island',
KP: 'North Korea',
MP: 'Northern Mariana Islands',
NO: 'Norway',
OM: 'Oman',
PK: 'Pakistan',
PW: 'Palau',
PS: 'Palestine',
PA: 'Panama',
PG: 'Papua New Guinea',
PY: 'Paraguay',
PE: 'Peru',
PH: 'Philippines',
PN: 'Pitcairn Islands',
PL: 'Poland',
PT: 'Portugal',
PR: 'Puerto Rico',
QA: 'Qatar',
RE: 'Reunion',
RO: 'Romania',
RU: 'Russia',
RW: 'Rwanda',
SH: 'Saint Helena',
KN: 'Saint Kitts and Nevis',
LC: 'Saint Lucia',
PM: 'Saint Pierre and Miquelon',
VC: 'Saint Vincent and the Grenadines',
WS: 'Samoa',
SM: 'San Marino',
ST: 'São Tomé and Príncipe',
SA: 'Saudi Arabia',
SN: 'Senegal',
RS: 'Serbia',
SC: 'Seychelles',
SL: 'Sierra Leone',
SG: 'Singapore',
SX: 'Sint Maarten',
SK: 'Slovakia',
SI: 'Slovenia',
SB: 'Solomon Islands',
SO: 'Somalia',
ZA: 'South Africa',
GS: 'South Georgia and the South Sandwich Islands',
KR: 'South Korea',
SS: 'South Sudan',
ES: 'Spain',
LK: 'Sri Lanka',
SD: 'Sudan',
SR: 'Suriname',
SJ: 'Svalbard and Jan Mayen',
SZ: 'Eswatini',
SE: 'Sweden',
CH: 'Switzerland',
SY: 'Syria',
TW: 'Taiwan',
TJ: 'Tajikistan',
TZ: 'Tanzania',
TH: 'Thailand',
TL: 'Timor-Leste',
TG: 'Togo',
TK: 'Tokelau',
TO: 'Tonga',
TT: 'Trinidad and Tobago',
TN: 'Tunisia',
TR: 'Turkey',
TM: 'Turkmenistan',
TC: 'Turks and Caicos Islands',
TV: 'Tuvalu',
UG: 'Uganda',
UA: 'Ukraine',
AE: 'United Arab Emirates',
GB: 'United Kingdom',
US: 'United States',
UM: 'United States Minor Outlying Islands',
VI: 'United States Virgin Islands',
UY: 'Uruguay',
UZ: 'Uzbekistan',
VU: 'Vanuatu',
VA: 'Vatican City',
VE: 'Venezuela',
VN: 'Vietnam',
WF: 'Wallis and Futuna',
EH: 'Western Sahara',
YE: 'Yemen',
ZM: 'Zambia',
ZW: 'Zimbabwe'
};
// Apply the data to the map
svgMap.prototype.applyData = function (data) {
var max = null;
var min = null;
// Get highest and lowest value
Object.keys(data.values).forEach(function (countryID) {
var value = parseInt(data.values[countryID][data.applyData], 10);
max === null && (max = value);
min === null && (min = value);
value > max && (max = value);
value < min && (min = value);
});
data.data[data.applyData].thresholdMax &&
(max = Math.min(max, data.data[data.applyData].thresholdMax));
data.data[data.applyData].thresholdMin &&
(min = Math.max(min, data.data[data.applyData].thresholdMin));
// Loop through countries and set colors
Object.keys(this.countries).forEach(
function (countryID) {
var element = document.getElementById(
this.id + '-map-country-' + countryID
);
if (!element) {
return;
}
if (!data.values[countryID]) {
element.setAttribute('fill', this.toHex(this.options.colorNoData));
return;
}
if (typeof data.values[countryID].color != 'undefined') {
element.setAttribute('fill', data.values[countryID].color);
return;
}
var value = Math.max(
min,
parseInt(data.values[countryID][data.applyData], 10)
);
var ratio = Math.max(0, Math.min(1, (value - min) / (max - min)));
var color = this.getColor(
this.toHex(this.options.colorMax),
this.toHex(this.options.colorMin),
ratio || ratio === 0 ? ratio : 1
);
element.setAttribute('fill', color);
}.bind(this)
);
};
// Emoji flags
svgMap.prototype.emojiFlags = {
AF: '🇦🇫',
AX: '🇦🇽',
AL: '🇦🇱',
DZ: '🇩🇿',
AS: '🇦🇸',
AD: '🇦🇩',
AO: '🇦🇴',
AI: '🇦🇮',
AQ: '🇦🇶',
AG: '🇦🇬',
AR: '🇦🇷',
AM: '🇦🇲',
AW: '🇦🇼',
AU: '🇦🇺',
AT: '🇦🇹',
AZ: '🇦🇿',
BS: '🇧🇸',
BH: '🇧🇭',
BD: '🇧🇩',
BB: '🇧🇧',
BY: '🇧🇾',
BE: '🇧🇪',
BZ: '🇧🇿',
BJ: '🇧🇯',
BM: '🇧🇲',
BT: '🇧🇹',
BO: '🇧🇴',
BA: '🇧🇦',
BW: '🇧🇼',
BR: '🇧🇷',
IO: '🇮🇴',
VG: '🇻🇬',
BN: '🇧🇳',
BG: '🇧🇬',
BF: '🇧🇫',
BI: '🇧🇮',
KH: '🇰🇭',
CM: '🇨🇲',
CA: '🇨🇦',
CV: '🇨🇻',
BQ: '🇧🇶',
KY: '🇰🇾',
CF: '🇨🇫',
TD: '🇹🇩',
CL: '🇨🇱',
CN: '🇨🇳',
CX: '🇨🇽',
CC: '🇨🇨',
CO: '🇨🇴',
KM: '🇰🇲',
CG: '🇨🇬',
CK: '🇨🇰',
CR: '🇨🇷',
HR: '🇭🇷',
CU: '🇨🇺',
CW: '🇨🇼',
CY: '🇨🇾',
CZ: '🇨🇿',
CD: '🇨🇩',
DK: '🇩🇰',
DJ: '🇩🇯',
DM: '🇩🇲',
DO: '🇩🇴',
EC: '🇪🇨',
EG: '🇪🇬',
SV: '🇸🇻',
GQ: '🇬🇶',
ER: '🇪🇷',
EE: '🇪🇪',
ET: '🇪🇹',
FK: '🇫🇰',
FO: '🇫🇴',
FM: '🇫🇲',
FJ: '🇫🇯',
FI: '🇫🇮',
FR: '🇫🇷',
GF: '🇬🇫',
PF: '🇵🇫',
TF: '🇹🇫',
GA: '🇬🇦',
GM: '🇬🇲',
GE: '🇬🇪',
DE: '🇩🇪',
GH: '🇬🇭',
GI: '🇬🇮',
GR: '🇬🇷',
GL: '🇬🇱',
GD: '🇬🇩',
GP: '🇬🇵',
GU: '🇬🇺',
GT: '🇬🇹',
GN: '🇬🇳',
GW: '🇬🇼',
GY: '🇬🇾',
HT: '🇭🇹',
HN: '🇭🇳',
HK: '🇭🇰',
HU: '🇭🇺',
IS: '🇮🇸',
IN: '🇮🇳',
ID: '🇮🇩',
IR: '🇮🇷',
IQ: '🇮🇶',
IE: '🇮🇪',
IM: '🇮🇲',
IL: '🇮🇱',
IT: '🇮🇹',
CI: '🇨🇮',
JM: '🇯🇲',
JP: '🇯🇵',
JE: '🇯🇪',
JO: '🇯🇴',
KZ: '🇰🇿',
KE: '🇰🇪',
KI: '🇰🇮',
XK: '🇽🇰',
KW: '🇰🇼',
KG: '🇰🇬',
LA: '🇱🇦',
LV: '🇱🇻',
LB: '🇱🇧',
LS: '🇱🇸',
LR: '🇱🇷',
LY: '🇱🇾',
LI: '🇱🇮',
LT: '🇱🇹',
LU: '🇱🇺',
MO: '🇲🇴',
MK: '🇲🇰',
MG: '🇲🇬',
MW: '🇲🇼',
MY: '🇲🇾',
MV: '🇲🇻',
ML: '🇲🇱',
MT: '🇲🇹',
MH: '🇲🇭',
MQ: '🇲🇶',
MR: '🇲🇷',
MU: '🇲🇺',
YT: '🇾🇹',
MX: '🇲🇽',
MD: '🇲🇩',
MC: '🇲🇨',
MN: '🇲🇳',
ME: '🇲🇪',
MS: '🇲🇸',
MA: '🇲🇦',
MZ: '🇲🇿',
MM: '🇲🇲',
NA: '🇳🇦',
NR: '🇳🇷',
NP: '🇳🇵',
NL: '🇳🇱',
NC: '🇳🇨',
NZ: '🇳🇿',
NI: '🇳🇮',
NE: '🇳🇪',
NG: '🇳🇬',
NU: '🇳🇺',
NF: '🇳🇫',
KP: '🇰🇵',
MP: '🇲🇵',
NO: '🇳🇴',
OM: '🇴🇲',
PK: '🇵🇰',
PW: '🇵🇼',
PS: '🇵🇸',
PA: '🇵🇦',
PG: '🇵🇬',
PY: '🇵🇾',
PE: '🇵🇪',
PH: '🇵🇭',
PN: '🇵🇳',
PL: '🇵🇱',
PT: '🇵🇹',
PR: '🇵🇷',
QA: '🇶🇦',
RE: '🇷🇪',
RO: '🇷🇴',
RU: '🇷🇺',
RW: '🇷🇼',
SH: '🇸🇭',
KN: '🇰🇳',
LC: '🇱🇨',
PM: '🇵🇲',
VC: '🇻🇨',
WS: '🇼🇸',
SM: '🇸🇲',
ST: '🇸🇹',
SA: '🇸🇦',
SN: '🇸🇳',
RS: '🇷🇸',
SC: '🇸🇨',
SL: '🇸🇱',
SG: '🇸🇬',
SX: '🇸🇽',
SK: '🇸🇰',
SI: '🇸🇮',
SB: '🇸🇧',
SO: '🇸🇴',
ZA: '🇿🇦',
GS: '🇬🇸',
KR: '🇰🇷',
SS: '🇸🇸',
ES: '🇪🇸',
LK: '🇱🇰',
SD: '🇸🇩',
SR: '🇸🇷',
SJ: '🇸🇯',
SZ: '🇸🇿',
SE: '🇸🇪',
CH: '🇨🇭',
SY: '🇸🇾',
TW: '🇹🇼',
TJ: '🇹🇯',
TZ: '🇹🇿',
TH: '🇹🇭',
TL: '🇹🇱',
TG: '🇹🇬',
TK: '🇹🇰',
TO: '🇹🇴',
TT: '🇹🇹',
TN: '🇹🇳',
TR: '🇹🇷',
TM: '🇹🇲',
TC: '🇹🇨',
TV: '🇹🇻',
UG: '🇺🇬',
UA: '🇺🇦',
AE: '🇦🇪',
GB: '🇬🇧',
US: '🇺🇸',
UM: '🇺🇲',
VI: '🇻🇮',
UY: '🇺🇾',
UZ: '🇺🇿',
VU: '🇻🇺',
VA: '🇻🇦',
VE: '🇻🇪',
VN: '🇻🇳',
WF: '🇼🇫',
EH: '🇪🇭',
YE: '🇾🇪',
ZM: '🇿🇲',
ZW: '🇿🇼'
};
svgMap.prototype.continents = {
"EA": {
"iso": "EA",
"name": "World"
},
"AF": {
"iso": "AF",
"name": "Africa",
"pan": {
x: 454, y: 250
},
"zoom": 1.90
},
"AS": {
"iso": "AS",
"name": "Asia",
"pan": {
x: 904, y: 80
},
"zoom": 1.8
},
"EU": {
"iso": "EU",
"name": "Europe",
"pan": {
x: 404, y: 80
},
"zoom": 5
},
"NA": {
"iso": "NA",
"name": "North America",
"pan": {
x: 104, y: 55
},
"zoom": 2.6
},
"MA": {
"iso": "MA",
"name": "Middle America",
"pan": {
x: 104, y: 200
},
"zoom": 2.6
},
"SA": {
"iso": "SA",
"name": "South America",
"pan": {
x: 104, y: 340
},
"zoom": 2.2
},
"OC": {
"iso": "OC",
"name": "Oceania",
"pan": {
x: 954, y: 350
},
"zoom": 1.90
},
}
// Create the SVG map
svgMap.prototype.createMap = function () {
// Create the tooltip
this.createTooltip();
// Create map wrappers
this.mapWrapper = this.createElement(
'div',
'svgMap-map-wrapper',
this.mapContainer
);
this.mapImage = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg'
);
this.mapImage.setAttribute('viewBox', '0 0 2000 1001');
this.mapImage.classList.add('svgMap-map-image');
this.mapWrapper.appendChild(this.mapImage);
// Add controls
var mapControlsWrapper = this.createElement(
'div',
'svgMap-map-controls-wrapper',
this.mapWrapper
);
var zoomContainer = this.createElement(
'div',
'svgMap-map-controls-zoom',
mapControlsWrapper
);
['in', 'out', 'reset'].forEach(
function (item) {
if (item === 'reset' && this.options.showZoomReset || item !== 'reset') {
var zoomControlName =
'zoomControl' + item.charAt(0).toUpperCase() + item.slice(1);
this[zoomControlName] = this.createElement(
'button',
'svgMap-control-button svgMap-zoom-button svgMap-zoom-' +
item +
'-button',
zoomContainer
);
this[zoomControlName].type = 'button';
this[zoomControlName].addEventListener(
'click',
function () {
this.zoomMap(item);
}.bind(this),
{ passive: true }
);
}
}.bind(this)
);
// Add accessible names to zoom controls
this.zoomControlIn.setAttribute('aria-label', 'Zoom in');
this.zoomControlOut.setAttribute('aria-label', 'Zoom out');
if (this.options.showContinentSelector) {
// Add continent controls
var mapContinentControlsWrapper = this.createElement(
'div',
'svgMap-map-continent-controls-wrapper',
this.mapWrapper
);
this["continentSelect"] = this.createElement(
'select',
'svgMap-continent-select',
mapContinentControlsWrapper
);
var that = this;
Object.keys(svgMap.prototype.continents).forEach(
function (item) {
let element = that.createElement(
'option',
'svgMap-continent-option svgMap-continent-iso-' + svgMap.prototype.continents[item].iso,
that["continentSelect"],
svgMap.prototype.continents[item].name
);
element.value = item
}
);
this.continentSelect.addEventListener(
'change',
function (e) {
const continent = e.target.value;
if (continent) this.zoomContinent(e.target.value);
}.bind(that),
{ passive: true }
);
mapContinentControlsWrapper.setAttribute('aria-label', 'Select continent');
}
// Fix countries
var mapPaths = Object.assign({}, this.mapPaths);
if (!this.options.countries.EH) {
mapPaths.MA.d = mapPaths['MA-EH'].d;
delete mapPaths.EH;
}
delete mapPaths['MA-EH'];
// Expose tooltipMove function
this.tooltipMoveEvent = function (e) {
this.moveTooltip(e);
}.bind(this);
// Add map elements
Object.keys(mapPaths).forEach(
function (countryID) {
var countryData = this.mapPaths[countryID];
if (!countryData.d) {
return;
}
var countryElement = document.createElementNS(
'http://www.w3.org/2000/svg',
'path'
);
countryElement.setAttribute('d', countryData.d);
countryElement.setAttribute(
'id',
this.id + '-map-country-' + countryID
);
countryElement.setAttribute('data-id', countryID);
countryElement.classList.add('svgMap-country');
this.mapImage.appendChild(countryElement);
// Tooltip events
// Add tooltip when touch is used
countryElement.addEventListener(
'touchstart',
function (e) {
countryElement.parentNode.appendChild(countryElement);
countryElement.classList.add('svgMap-active');
var countryID = countryElement.getAttribute('data-id');
var countryLink = countryElement.getAttribute('data-link');
if (this.options.touchLink) {
if (countryLink) {
window.location.href = countryLink;
return;
}
}
this.setTooltipContent(this.getTooltipContent(countryID));
this.showTooltip(e);
this.moveTooltip(e);
countryElement.addEventListener(
'touchmove',
this.tooltipMoveEvent,
{
passive: true
}
);
}.bind(this),
{ passive: true }
);
countryElement.addEventListener(
'mouseenter',
function (e) {
countryElement.parentNode.appendChild(countryElement);
var countryID = countryElement.getAttribute('data-id');
this.setTooltipContent(this.getTooltipContent(countryID));
this.showTooltip(e);
countryElement.addEventListener(
'mousemove',
this.tooltipMoveEvent,
{
passive: true
}
);
}.bind(this),
{ passive: true }
);
if (
this.options.data.values &&
this.options.data.values[countryID] &&
this.options.data.values[countryID]['link']
) {
countryElement.setAttribute(
'data-link',
this.options.data.values[countryID]['link']
);
if (this.options.data.values[countryID]['linkTarget']) {
countryElement.setAttribute(
'data-link-target',
this.options.data.values[countryID]['linkTarget']
);
}
let dragged = false;
countryElement.addEventListener('mousedown', function () { dragged = false });
countryElement.addEventListener('touchstart', function () { dragged = false });
countryElement.addEventListener('mousemove', function () { dragged = true });
countryElement.addEventListener('touchmove', function () { dragged = true });
const clickHandler = function (e) {
if (dragged) {
return;
}
const link = countryElement.getAttribute('data-link');
const target = countryElement.getAttribute('data-link-target');
if (target) {
window.open(link, target);
} else {
window.location.href = link;
}
}
countryElement.addEventListener('click', clickHandler);
countryElement.addEventListener('touchend', clickHandler);
}
// Hide tooltip when mouse leaves the country area
countryElement.addEventListener(
'mouseleave',
function () {
this.hideTooltip();
countryElement.removeEventListener(
'mousemove',
this.tooltipMoveEvent,
{
passive: true
}
);
}.bind(this),
{ passive: true }
);
// Hide tooltip when touch ends
countryElement.addEventListener(
'touchend',
function () {
this.hideTooltip();
countryElement.classList.remove('svgMap-active');
countryElement.removeEventListener(
'touchmove',
this.tooltipMoveEvent,
{ passive: true }
);
}.bind(this),
{ passive: true }
);
}.bind(this)
);
// Expose instance
var me = this;
// Init pan zoom
this.mapPanZoom = svgPanZoom(this.mapImage, {
zoomEnabled: true,
fit: true,
center: true,
minZoom: this.options.minZoom,
maxZoom: this.options.maxZoom,
zoomScaleSensitivity: this.options.zoomScaleSensitivity,
controlIconsEnabled: false,
mouseWheelZoomEnabled: this.options.mouseWheelZoomEnabled,
preventMouseEventsDefault: true,
onZoom: function () {
me.setControlStatuses();
},
beforePan: function (oldPan, newPan) {
var gutterWidth = me.mapWrapper.offsetWidth * 0.85;
var gutterHeight = me.mapWrapper.offsetHeight * 0.85;
var sizes = this.getSizes();
var leftLimit =
-((sizes.viewBox.x + sizes.viewBox.width) * sizes.realZoom) +
gutterWidth;
var rightLimit =
sizes.width - gutterWidth - sizes.viewBox.x * sizes.realZoom;
var topLimit =
-((sizes.viewBox.y + sizes.viewBox.height) * sizes.realZoom) +
gutterHeight;
var bottomLimit =
sizes.height - gutterHeight - sizes.viewBox.y * sizes.realZoom;
return {
x: Math.max(leftLimit, Math.min(rightLimit, newPan.x)),
y: Math.max(topLimit, Math.min(bottomLimit, newPan.y))
};
}
});
if (this.options.initialPan.x != 0 || this.options.initialPan.y != 0) {
// Init zoom and pan
this.mapPanZoom.zoomAtPointBy(this.options.initialZoom, {
x: this.options.initialPan.x,
y: this.options.initialPan.y
});
} else {
// Init zoom
this.mapPanZoom.zoom(this.options.initialZoom);
}
// Initial zoom statuses
this.setControlStatuses();
};
// Create the tooltip content
svgMap.prototype.getTooltipContent = function (countryID) {
// Custom tooltip
if (this.options.onGetTooltip) {
var customDiv = this.options.onGetTooltip(
this.tooltip,
countryID,
this.options.data.values[countryID]
);
if (customDiv) {
return customDiv;
}
}
var tooltipContentWrapper = this.createElement(
'div',
'svgMap-tooltip-content-container'
);
if (this.options.hideFlag === false) {
// Flag
var flagContainer = this.createElement(
'div',
'svgMap-tooltip-flag-container svgMap-tooltip-flag-container-' +
this.options.flagType,
tooltipContentWrapper
);
if (this.options.flagType === 'image') {
this.createElement(
'img',
'svgMap-tooltip-flag',
flagContainer
).setAttribute(
'src',
this.options.flagURL.replace('{0}', countryID.toLowerCase())
);
} else if (this.options.flagType === 'emoji') {
flagContainer.innerHTML = this.emojiFlags[countryID];
}
}
// Title
this.createElement(
'div',
'svgMap-tooltip-title',
tooltipContentWrapper
).innerHTML = this.getCountryName(countryID);
// Content
var tooltipContent = this.createElement(
'div',
'svgMap-tooltip-content',
tooltipContentWrapper
);
if (!this.options.data.values[countryID]) {
this.createElement(
'div',
'svgMap-tooltip-no-data',
tooltipContent
).innerHTML = this.options.noDataText;
} else {
var tooltipContentTable = '<table>';
Object.keys(this.options.data.data).forEach(
function (key) {
var item = this.options.data.data[key];
var value = this.options.data.values[countryID][key];
if ((value !== undefined && this.options.hideMissingData === true) || this.options.hideMissingData === false) {
item.floatingNumbers && (value = value.toFixed(1));
item.thousandSeparator &&
(value = this.numberWithCommas(value, item.thousandSeparator));
value = item.format
? item.format.replace('{0}', '<span>' + value + '</span>')
: '<span>' + value + '</span>';
tooltipContentTable +=
'<tr><td>' + (item.name || '') + '</td><td>' + value + '</td></tr>';
}
}.bind(this)
);
tooltipContentTable += '</table>';
tooltipContent.innerHTML = tooltipContentTable;
}
return tooltipContentWrapper;
};
// Set the disabled statuses for buttons
svgMap.prototype.setControlStatuses = function () {
this.zoomControlIn.classList.remove('svgMap-disabled');
this.zoomControlIn.setAttribute('aria-disabled', 'false');
this.zoomControlOut.classList.remove('svgMap-disabled');
this.zoomControlOut.setAttribute('aria-disabled', 'false');
if (this.options.showZoomReset) {
this.zoomControlReset.classList.remove('svgMap-disabled');
this.zoomControlReset.setAttribute('aria-disabled', 'false');
}
if (this.mapPanZoom.getZoom().toFixed(3) <= this.options.minZoom) {
this.zoomControlOut.classList.add('svgMap-disabled');
this.zoomControlOut.setAttribute('aria-disabled', 'true');
}
if (this.mapPanZoom.getZoom().toFixed(3) >= this.options.maxZoom) {
this.zoomControlIn.classList.add('svgMap-disabled');
this.zoomControlIn.setAttribute('aria-disabled', 'true');
}
if (this.options.showZoomReset && this.mapPanZoom.getZoom().toFixed(3) == this.options.initialZoom) {
this.zoomControlReset.classList.add('svgMap-disabled');
this.zoomControlReset.setAttribute('aria-disabled', 'true');
}
};
// Zoom map
svgMap.prototype.zoomMap = function (direction) {
if (
this[
'zoomControl' + direction.charAt(0).toUpperCase() + direction.slice(1)
].classList.contains('svgMap-disabled')
) {
return false;
}
if (direction === 'reset') {
this.mapPanZoom.reset();
if (this.options.initialPan.x != 0 || this.options.initialPan.y != 0) {
// Init zoom and pan
this.mapPanZoom.zoomAtPointBy(this.options.initialZoom, {
x: this.options.initialPan.x,
y: this.options.initialPan.y
});
} else {
// Init zoom
this.mapPanZoom.zoom(this.options.initialZoom);
}
} else {
this.mapPanZoom[direction == 'in' ? 'zoomIn' : 'zoomOut']();
}
};
// Zoom to Contient
svgMap.prototype.zoomContinent = function (contientIso) {
const continent = this.continents[contientIso];
if (continent.iso == "EA") this.mapPanZoom.reset()
else if (continent.pan) {
this.mapPanZoom.reset()
this.mapPanZoom.zoomAtPoint(continent.zoom, continent.pan);
}
};
// Add elements to show the zoom with keys notice
svgMap.prototype.addMouseWheelZoomNotice = function () {
var noticeWrapper = document.createElement('div');
noticeWrapper.classList.add('svgMap-block-zoom-notice');
var noticeContainer = document.createElement('div');
noticeContainer.innerHTML =
navigator.appVersion.indexOf('Mac') != -1
? this.options.mouseWheelKeyMessageMac
: this.options.mouseWheelKeyMessage;
noticeWrapper.append(noticeContainer);
this.wrapper.append(noticeWrapper);
};
// Show the zoom with keys notice
svgMap.prototype.showMouseWheelZoomNotice = function (duration) {
if (this.mouseWheelNoticeJustHidden) {
return;
}
this.autoHideMouseWheelNoticeTimeout &&
clearTimeout(this.autoHideMouseWheelNoticeTimeout);
this.autoHideMouseWheelNoticeTimeout = setTimeout(
function () {
this.hideMouseWheelZoomNotice();
}.bind(this),
duration || 2400
);
this.wrapper.classList.add('svgMap-block-zoom-notice-active');
};
// Hide the zoom with keys notice
svgMap.prototype.hideMouseWheelZoomNotice = function () {
this.wrapper.classList.remove('svgMap-block-zoom-notice-active');
this.autoHideMouseWheelNoticeTimeout &&
clearTimeout(this.autoHideMouseWheelNoticeTimeout);
};
// Block shing the zoom wheel notice for some time
svgMap.prototype.blockMouseWheelZoomNotice = function (duration) {
this.mouseWheelNoticeJustHidden = true;
this.mouseWheelNoticeJustHiddenTimeout &&
clearTimeout(this.mouseWheelNoticeJustHiddenTimeout);
this.mouseWheelNoticeJustHiddenTimeout = setTimeout(
function () {
this.mouseWheelNoticeJustHidden = false;
}.bind(this),
duration || 600
);
};
// Add the events when you are only allowed to scrool with a key pressed
svgMap.prototype.addMouseWheelZoomWithKeyEvents = function () {
// Add events to wrapper
this.wrapper.addEventListener(
'wheel',
function (ev) {
if (!document.body.classList.contains('svgMap-zoom-key-pressed')) {
this.showMouseWheelZoomNotice();
} else {
this.hideMouseWheelZoomNotice();
this.blockMouseWheelZoomNotice();
}
}.bind(this),
{
passive: true
}
);
// Add with keydown
document.addEventListener(
'keydown',
function (ev) {
if (
ev.key == 'Alt' ||
ev.key == 'Control' ||
ev.key == 'Meta' ||
ev.key == 'Shift'
) {
document.body.classList.add('svgMap-zoom-key-pressed');
this.hideMouseWheelZoomNotice();
this.blockMouseWheelZoomNotice();
}
}.bind(this)
);
// Fallback with wheel as sometimes it wont trigger when window is out of focus
this.wrapper.addEventListener('wheel', function (ev) {
if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey) {
document.body.classList.add('svgMap-zoom-key-pressed');
// TODO wont be removed when window out of focus
}
});
// Only add following events to the document once
if (document.body.classList.contains('svgMap-key-events-added')) {
return false;
}
document.body.classList.add('svgMap-key-events-added');
// Remove with keyup
document.addEventListener('keyup', function (ev) {
if (
ev.key == 'Alt' ||
ev.key == 'Control' ||
ev.key == 'Meta' ||
ev.key == 'Shift'
) {
document.body.classList.remove('svgMap-zoom-key-pressed');
}
});
};
// Map paths
svgMap.prototype.mapPaths = {
'AF': {
d: 'M1369.9,333.8h-5.4l-3.8-0.5l-2.5,2.9l-2.1,0.7l-1.5,1.3l-2.6-2.1l-1-5.4l-1.6-0.3v-2l-3.2-1.5l-1.7,2.3l0.2,2.6 l-0.6,0.9l-3.2-0.1l-0.9,3l-2.1-1.3l-3.3,2.1l-1.8-0.8l-4.3-1.4h-2.9l-1.6-0.2l-2.9-1.7l-0.3,2.3l-4.1,1.2l0.1,5.2l-2.5,2l-4,0.9 l-0.4,3l-3.9,0.8l-5.9-2.4l-0.5,8l-0.5,4.7l2.5,0.9l-1.6,3.5l2.7,5.1l1.1,4l4.3,1.1l1.1,4l-3.9,5.8l9.6,3.2l5.3-0.9l3.3,0.8l0.9-1.4 l3.8,0.5l6.6-2.6l-0.8-5.4l2.3-3.6h4l0.2-1.7l4-0.9l2.1,0.6l1.7-1.8l-1.1-3.8l1.5-3.8l3-1.6l-3-4.2l5.1,0.2l0.9-2.3l-0.8-2.5l2-2.7 l-1.4-3.2l-1.9-2.8l2.4-2.8l5.3-1.3l5.8-0.8l2.4-1.2l2.8-0.7L1369.9,333.8L1369.9,333.8z'
},
'AL': {
d: 'M1077.5,300.5l-2,3.1l0.5,1.9l0,0l1,1l-0.5,1.9l-0.1,4.3l0.7,3l3,2.1l0.2,1.4l1,0.4l2.1-3l0.1-2.1l1.6-0.9V312 l-2.3-1.6l-0.9-2.6l0.4-2.1l0,0l-0.5-2.3l-1.3-0.6l-1.3-1.6l-1.3,0.5L1077.5,300.5L1077.5,300.5z'
},
'DZ': {
d: 'M1021,336.9l-3.6,0.4l-2.2-1.5h-5.6l-4.9,2.6l-2.7-1l-8.7,0.5l-8.9,1.2l-5,2l-3.4,2.6l-5.7,1.2l-5.1,3.5l2,4.1 l0.3,3.9l1.8,6.7l1.4,1.4l-1,2.5l-7,1l-2.5,2.4l-3.1,0.5l-0.3,4.7l-6.3,2.5l-2.1,3.2L944,383l-5.4,1l-8.9,4.7l-0.1,7.5v0.4l-0.1,1.2 l20.3,15.5l18.4,13.9l18.6,13.8l1.3,3l3.4,1.8l2.6,1.1l0.1,4l6.1-0.6l7.8-2.8l15.8-12.5l18.6-12.2l-2.5-4l-4.3-2.9l-2.6,1.2l-2-3.6 l-0.2-2.7l-3.4-4.7l2.1-2.6l-0.5-4l0.6-3.5l-0.5-2.9l0.9-5.2l-0.4-3l-1.9-5.6l-2.6-11.3l-3.4-2.6v-1.5l-4.5-3.8l-0.6-4.8l3.2-3.6 l1.1-5.3l-1-6.2L1021,336.9L1021,336.9z'
},
'AD': {
d: 'M985.4,301.7l0.2-0.4l-0.2-0.2l-0.7-0.2l-0.3-0.1l-0.4,0.3l-0.1,0.3l0.1,0.1v0.4l0.1,0.2h0.4L985.4,301.7 L985.4,301.7z'
},
'AO': {
d: 'M1068.3,609.6l-16.6-0.1l-1.9,0.7l-1.7-0.1l-2.3,0.9l-0.5,1.2l2.8,4l1.1,4.3l1.6,6.1l-1.7,2.6l-0.3,1.3l1.3,3.8 l1.5,3.9l1.6,2.2l0.3,3.6l-0.7,4.8l-1.8,2.8l-3.3,4.2l-1.3,2.6l-1.9,5.7l-0.3,2.7l-2,5.9l-0.9,5.5l0.5,4l2.7-1.2l3.3-1l3.6,0.1 l3.2,2.9l0.9-0.4l22.5-0.3l3.7,3l13.4,0.9l10.3-2.5l-3.5-4l-3.6-5.2l0.8-20.3l11.6,0.1l-0.5-2.2l0.9-2.4l-0.9-3l0.7-3l-0.5-2 l-2.6-0.4l-3.5,1l-2.4-0.2l-1.4,0.6l0.5-7.6l-1.9-2.3l-0.3-4l0.9-3.8l-1.2-2.4v-4h-6.8l0.5-2.3h-2.9l-0.3,1.1l-3.4,0.3l-1.5,3.7 l-0.9,1.6l-3-0.9l-1.9,0.9l-3.7,0.5l-2.1-3.3l-1.3-2.1l-1.6-3.8L1068.3,609.6L1068.3,609.6z M1046.5,608.3l0.2-2.7l0.9-1.7l2-1.3 l-2-2.2l-1.8,1.1l-2.2,2.7l1.4,4.8L1046.5,608.3L1046.5,608.3z'
},
'AI': {
d: 'M627.9,456.2l0.1-0.2l-0.2-0.1l-0.8,0.5v0.1L627.9,456.2z'
},
'AG': {
d: 'M634.3,463.8l0.2-0.1v-0.1v-0.2l-0.1-0.1l-0.1-0.2l-0.4-0.2l-0.5,0.5v0.2l0.1,0.3l0.6,0.1L634.3,463.8L634.3,463.8z M634.5,460.3v-0.5l-0.1-0.2h-0.3l-0.1-0.1h-0.1l-0.1,0.1l0.1,0.6l0.5,0.3L634.5,460.3L634.5,460.3z'
},
'AR': {
d: 'M669.8,920.7l0.9-3l-7.3-1.5l-7.7-3.6l-4.3-4.6l-3-2.8l5.9,13.5h5l2.9,0.2l3.3,2.1L669.8,920.7L669.8,920.7z M619.4,712.6l-7.4-1.5l-4,5.7l0.9,1.6l-1.1,6.6l-5.6,3.2l1.6,10.6l-0.9,2l2,2.5l-3.2,4l-2.6,5.9l-0.9,5.8l1.7,6.2l-2.1,6.5 l4.9,10.9l1.6,1.2l1.3,5.9l-1.6,6.2l1.4,5.4l-2.9,4.3l1.5,5.9l3.3,6.3l-2.5,2.4l0.3,5.7l0.7,6.4l3.3,7.6l-1.6,1.2l3.6,7.1l3.1,2.3 l-0.8,2.6l2.8,1.3l1.3,2.3l-1.8,1.1l1.8,3.7l1.1,8.2l-0.7,5.3l1.8,3.2l-0.1,3.9l-2.7,2.7l3.1,6.6l2.6,2.2l3.1-0.4l1.8,4.6l3.5,3.6 l12,0.8l4.8,0.9l2.2,0.4l-4.7-3.6l-4.1-6.3l0.9-2.9l3.5-2.5l0.5-7.2l4.7-3.5l-0.2-5.6l-5.2-1.3l-6.4-4.5l-0.1-4.7l2.9-3.1l4.7-0.1 l0.2-3.3l-1.2-6.1l2.9-3.9l4.1-1.9l-2.5-3.2l-2.2,2l-4-1.9l-2.5-6.2l1.5-1.6l5.6,2.3l5-0.9l2.5-2.2l-1.8-3.1l-0.1-4.8l-2-3.8 l5.8,0.6l10.2-1.3l6.9-3.4l3.3-8.3l-0.3-3.2l-3.9-2.8l-0.1-4.5l-7.8-5.5l-0.3-3.3l-0.4-4.2l0.9-1.4l-1.1-6.3l0.3-6.5l0.5-5.1 l5.9-8.6l5.3-6.2l3.3-2.6l4.2-3.5l-0.5-5.1l-3.1-3.7l-2.6,1.2l-0.3,5.7l-4.3,4.8l-4.2,1.1l-6.2-1l-5.7-1.8l4.2-9.6l-1.1-2.8 l-5.9-2.5l-7.2-4.7l-4.6-1L632,713.7l-1-1.3l-6.3-0.3l-1.6,5.1L619.4,712.6L619.4,712.6z'
},
'AM': {
d: 'M1219,325.1l-0.9-4.4l-2.5-1.1l-2.5-1.7l1-2l-3.1-2.2l0.7-1.5l-2.2-1.1l-1.4-1.7l-6.9,1l1.3,2.2v3.1l4.2,1.5 l2.4,1.9l1-0.2l1.8,1.7h2.3l0.2,1l2.8,3.7L1219,325.1L1219,325.1z'
},
'AW': {
d: 'M586.6,492.9l-0.1-0.1l-0.3-0.6l-0.3-0.3l-0.1,0.1l-0.1,0.3l0.3,0.3l0.3,0.4l0.3,0.1L586.6,492.9L586.6,492.9z'
},
'AU': {
d: 'M1726.7,832l-3-0.5l-1.9,2.9l-0.6,5.4l-2.1,4l-0.5,5.3l3,0.2l0.8,0.3l6.6-4.3l0.6,1.7l4-4.9l3.2-2.2l4.5-7.3 l-2.8-0.5l-4.8,1.2l-3.4,0.9L1726.7,832L1726.7,832z M1776.8,659.7l0.5-2.3l0.1-3.6l-1.6-3.2l0.1-2.7l-1.3-0.8l0.1-3.9l-1.2-3.2 l-2.3,2.4l-0.4,1.8l-1.5,3.5l-1.8,3.4l0.6,2.1l-1.2,1.3l-1.5,4.8l0.1,3.7l-0.7,1.8l0.3,3.1l-2.6,5l-1.3,3.5l-1.7,2.9l-1.7,3.4 l-4.1,2.1l-4.9-2.1l-0.5-2l-2.5-1.6h-1.6l-3.3-3.8l-2.5-2.2l-3.9-2l-3.9-3.5l-0.1-1.8l2.5-3.1l2.1-3.2l-0.3-2.6l1.9-0.2l2.5-2.5 l2-3.4l-2.2-3.2l-1.5,1.2l-2-0.5l-3.5,1.8l-3.2-2l-1.7,0.7l-4.5-1.6l-2.7-2.7l-3.5-1.5l-3.1,0.9l3.9,2.1l-0.3,3.2l-4.8,1.2l-2.8-0.7 l-3.6,2.2l-2.9,3.7l0.6,1.5l-2.7,1.7l-3.4,5.1l0.6,3.5l-3.4-0.6h-3.5l-2.5-3.8l-3.7-2.9l-2.8,0.8l-2.6,0.9l-0.3,1.6l-2.4-0.7 l-0.3,1.8l-3,1.1l-1.7,2.5l-3.5,3.1l-1.4,4.8l-2.3-1.3l-2.2,3.1l1.5,3l-2.6,1.2l-1.4-5.5l-4.8,5.4l-0.8,3.5l-0.7,2.5l-3.8,3.3 l-2,3.4l-3.5,2.8l-6.1,1.9l-3.1-0.2l-1.5,0.6l-1.1,1.4l-3.5,0.7l-4.7,2.4l-1.4-0.8l-2.6,0.5l-4.6,2.3l-3.2,2.7l-4.8,2.1l-3.1,4.4 l0.4-4.8l-3.1,4.6l-0.1,3.7l-1.3,3.2l-1.5,1.5l-1.3,3.7l0.9,1.9l0.1,2l1.6,5l-0.7,3.3l-1-2.5l-2.3-1.8l0.4,5.9l-1.7-2.8l0.1,2.8 l1.8,5l-0.6,5l1.7,2.5l-0.4,1.9l0.9,4.1l-1.3,3.6l-0.3,3.6l0.7,6.5l-0.7,3.7l-2.2,4.4l-0.6,2.3l-1.5,1.5l-2.9,0.8l-1.5,3.7l2.4,1.2 l4,4.1h3.6l3.8,0.3l3.3-2.1l3.4-1.8l1.4,0.3l4.5-3.4l3.8-0.3l4.1-0.7l4.2,1.2l3.6-0.6l4.6-0.2l3-2.6l2.3-3.3l5.2-1.5l6.9-3.2l5,0.4 l6.9-2.1l7.8-2.3l9.8-0.6l4,3.1l3.7,0.2l5.3,3.8l-1.6,1.5l1.8,2.4l1.3,4.6l-1.6,3.4l2.9,2.6l4.3-5.1l4.3-2.1l6.7-5.5l-1.6,4.7 l-3.4,3.2l-2.5,3.7l-4.4,3.5l5.2-1.2l4.7-4.4l-0.9,4.8l-3.2,3.1l4.7,0.8l1.3,2.6l-0.4,3.3l-1.5,4.9l1.4,4l4,1.9l2.8,0.4l2.4,1 l3.5,1.8l7.2-4.7l3.5-1.2l-2.7,3.4l2.6,1.1l2.7,2.8l4.7-2.7l3.8-2.5l6.3-2.7l6-0.2l4.2-2.3l0.9-2l3-4.5l3.9-4.8l3.6-3.2l4.4-5.6 l3.3-3.1l4.4-5l5.4-3.1l5-5.8l3.1-4.5l1.4-3.6l3.8-5.7l2.1-2.9l2.5-5.7l-0.7-5.4l1.7-3.9l1.1-3.7v-5.1l-2.8-5.1l-1.9-2.5l-2.9-3.9 l0.7-6.7l-1.5,1l-1.6-2.8l-2.5,1.4l-0.6-6.9l-2.2-4l1-1.5l-3.1-2.8l-3.2-3l-5.3-3.3l-0.9-4.3l1.3-3.3l-0.4-5.5l-1.3-0.7l-0.2-3.2 l-0.2-5.5l1.1-2.8l-2.3-2.5l-1.4-2.7l-3.9,2.4L1776.8,659.7L1776.8,659.7z'
},
'AT': {
d: 'M1060.2,264l-2.3-1.2l-2.3,0.3l-4-1.9l-1.7,0.5l-2.6,2.5l-3.8-2l-1.5,2.9l-1.7,0.8l1,4l-0.4,1.1l-1.7-1.3l-2.4-0.2 l-3.4,1.2l-4.4-0.3l-0.6,1.6l-2.6-1.7l-1.5,0.3l0.2,1.1l-0.7,1.6l2.3,1.1l2.6,0.2l3.1,0.9l0.5-1.2l4.8-1.1l1.3,2.2l7.2,1.6l4.2,0.4 l2.4-1.4l4.3-0.1l0.9-1.1l1.3-4l-1.1-1.3h2.8l0.2-2.6l-0.7-2.1L1060.2,264L1060.2,264z'
},
'AZ': {
d: 'M1210.1,318.9l-1,0.2l1.2,2.4l3.2,2.9l3.7,0.9l-2.8-3.7l-0.2-1h-2.3L1210.1,318.9L1210.1,318.9z M1220.5,309.6 l-4.3-3.8l-1.5-0.2l-1.1,0.9l3.2,3.4l-0.6,0.7l-2.8-0.4l-4.2-1.8l-1.1,1l1.4,1.7l2.2,1.1l-0.7,1.5l3.1,2.2l-1,2l2.5,1.7l2.5,1.1 l0.9,4.4l5.3-4.7l1.9-0.5l1.9,1.9l-1.2,3.1l3.8,3.4l1.3-0.3l-0.8-3.2l1.7-1.5l0.4-2.2l-0.1-5l4.2-0.5l-2-1.7l-2.5-0.2l-3.5-4.5 l-3.4-3.2l0,0l-2.6,2.5l-0.5,1.5L1220.5,309.6L1220.5,309.6z'
},
'BS': {
d: 'M574.4,437.3l0.2-0.6l-0.3-0.1l-0.5,0.7l-0.6,0.3h-0.3l-0.7-0.3h-0.5l-0.4,0.5l-0.6,0.1l0.1,0.1v0.2l-0.2,0.3v0.2 l0.1,0.3l1.5-0.1l1.3-0.2l0.7-0.9L574.4,437.3z M575.2,435.3l-0.4-0.3l-0.4,0.3l0.1,0.3L575.2,435.3L575.2,435.3z M575.2,429.5 l-0.4-0.2l-0.3,0.5l0.3,0.1l0.7-0.1l0.5,0.1l0.5,0.4l0.3-0.2l-0.1-0.1l-0.4-0.3l-0.6-0.1h-0.2L575.2,429.5L575.2,429.5z M568.6,430.8l0.7-0.6l0.7-0.3l0.9-1.1l-0.1-0.9l0.2-0.4l-0.6,0.1l-0.1,0.3l-0.1,0.3l0.3,0.4v0.2l-0.2,0.4l-0.3,0.1l-0.1,0.2 l-0.3,0.1l-0.4,0.5l-0.8,0.6l-0.2,0.3L568.6,430.8L568.6,430.8z M569.8,427.6l-0.6-0.2L569,427l-0.4-0.1l-0.1,0.2v0.2l0.1,0.4 l0.2-0.1l0.8,0.4l0.4-0.3L569.8,427.6z M565.7,426.5v-0.7l-0.4-0.5l-0.6-0.4l-0.1-1.2l-0.3-0.7l-0.2-0.6l-0.4-0.8v0.5l0.1,0.1 l0.1,0.6l0.4,0.9l0.1,0.4l-0.1,0.4l-0.4,0.1l-0.1,0.2l0.5,0.3l0.8,0.3l0.5,1.3L565.7,426.5L565.7,426.5z M561.6,423l-0.5-0.3 l-0.2-0.3l-0.7-0.7l-0.3-0.1l-0.2,0.4l0.4,0.1l0.9,0.7l0.4,0.2L561.6,423L561.6,423z M568.9,419l-0.1-0.3h-0.1l-0.3,0.1l-0.3,0.9 h0.3L568.9,419L568.9,419z M551.3,417.9l-0.2-0.3l-0.3,0.2h-0.5l-0.2,0.1h-0.4l-0.3,0.2l0.4,0.8l0.3,0.3l0.1,1l0.2,0.1l-0.1,0.7 l1.1,0.1l0.4-0.8V420v-0.1v-0.2v-0.2v-0.9l-0.3-0.5l-0.4,0.6l-0.4-0.3l0.6-0.4L551.3,417.9L551.3,417.9z M564.2,418.2l-1-1.4v-0.2 l-0.5-1.5l-0.3-0.1l-0.1,0.1l-0.1,0.2l0.4,0.4v0.4l0.3,0.2l0.4,1.1l0.4,0.4l-0.1,0.3l-0.4,0.3l-0.1,0.2h0.1l0.6-0.1h0.4L564.2,418.2 L564.2,418.2z M553.7,413l0.5-0.2l0,0l-0.3-0.2h-0.7l-0.4,0.1l-0.2,0.2l0.1,0.1l0.4,0.1L553.7,413L553.7,413z M551.3,415l-0.5-0.6 l-0.3-0.9l-0.2-0.4l0.1-0.5l-0.3-0.4l-0.6-0.4l-0.3,0.1l0.1,1.1l-0.2,0.6l-0.8,1.1l0.1,0.4l0,0l0.1,0.2l-0.5,0.4v-0.3l-0.6,0.1 l0.3,0.5l0.6,0.4l0.3,0.1l0.3-0.2v0.5l0.3,0.4l0.1,0.4l0.3-0.3l0.6-0.2l0.2-0.2l0.7-0.4v-0.2l0.1-0.6L551.3,415L551.3,415z M558,410 l-0.3-0.5l-0.1,0.1l-0.1,0.4l-0.3,0.4l0.5-0.1l0.4,0.1l0.6,0.5l0.7,0.2l0.3,0.6l0.6,0.6v0.6l-0.4,0.6l-0.1,0.7l-0.6,0.1l0.1,0.1 l0.3,0.3l0.1,0.4l0.2,0.2v-0.7l0.3-0.8l0.4-1.3l-0.1-0.3l-0.3-0.3l-0.7-0.9l-0.7-0.3L558,410L558,410z M549.2,402.1l-0.5-0.4 l-0.2,0.4v0.1l-0.1,0.3l-0.5,0.4l-0.5,0.1l-0.7-0.6l-0.2-0.1l0.8,1.1l0.3,0.1h0.4l0.9-0.3l1.6-0.5l1.7-0.2l0.1-0.2l-0.1-0.3 l-0.8,0.2l-1-0.1l-0.2,0.2h-0.4L549.2,402.1z M555.3,407.3l0.2-0.3l0.4-1.8l0.8-0.6l0.1-1.2l-0.5-0.5l-0.4-0.2l-0.1-0.2l0.1-0.2 l-0.2-0.1l-0.3-0.2l-0.4-0.6l-0.4-0.4l-0.7-0.1l-0.6-0.1l-0.4-0.1l-0.5,0.3h0.8l1.5,0.3l0.7,1.5l0.5,0.4l0.1,0.4l-0.2,0.4v0.4 l-0.3,0.5l-0.1,0.8l-0.3,0.4l-0.7,0.5l0.4,0.2l0.3,0.6L555.3,407.3L555.3,407.3z'
},
'BH': {
d: 'M1253,408.3l0.7-3l-0.5-0.9l-1.6,1.2l0.6,0.9l-0.2,0.7L1253,408.3z'
},
'BD': {
d: 'M1486.5,431.9l-4.5-10.1l-1.5,0.1l-0.2,4l-3.5-3.3l1.1-3.6l2.4-0.4l1.6-5.3l-3.4-1.1l-5,0.1l-5.4-0.9l-1.2-4.4 l-2.7-0.4l-4.8-2.7l-1.2,4.3l4.6,3.4l-3.1,2.4l-0.8,2.3l3.7,1.7l-0.4,3.8l2.6,4.8l1.6,5.2l2.2,0.6l1.7,0.7l0.6-1.2l2.5,1.3l1.3-3.5 l-0.9-2.6l5.1,0.2l2.8,3.7l1.5,3.1l0.8,3.2l2,3.3l-1.1-5.1l2.1,1L1486.5,431.9L1486.5,431.9z'
},
'BB': {
d: 'M644.9,488.9l0.4-0.4l-0.3-0.3l-0.6-0.8l-0.3,0.1v1l0.1,0.3l0.5,0.3L644.9,488.9L644.9,488.9z'
},
'BY': {
d: 'M1112.8,219.4l-5.2-1.5l-4.6,2.3l-2.6,1l0.9,2.6l-3.5,2l-0.5,3.4l-4.8,2.2h-4.6l0.6,2.7l1.7,2.3l0.3,2.4l-2.7,1.2 l1.9,2.9l0.5,2.7l2.2-0.3l2.4-1.6l3.7-0.2l5,0.5l5.6,1.5l3.8,0.1l2,0.9l1.6-1.1l1.5,1.5l4.3-0.3l2,0.6l-0.2-3.1l1.2-1.4l4.1-0.3l0,0 l-2-3.9l-1.5-2l0.8-0.6l3.9,0.2l1.6-1.3l-1.7-1.6l-3.4-1.1l0.1-1.1l-2.2-1.1l-3.7-3.9l0.6-1.6l-1-2.9l-4.8-1.4l-2.3,0.7 L1112.8,219.4L1112.8,219.4z'
},
'BE': {
d: 'M1000.7,246.2l-4.4,1.3l-3.6-0.5l0,0l-3.8,1.2l0.7,2.2l2.2,0.1l2.4,2.4l3.4,2.9l2.5-0.4l4.4,2.8l0.4-3.5l1.3-0.2 l0.4-4.2l-2.8-1.4L1000.7,246.2L1000.7,246.2z'
},
'BZ': {
d: 'M482.5,471.1l1.4-2.2l1-0.2l1.3-1.7l1-3.2l-0.3-0.6l0.9-2.3l-0.4-1l1.3-2.7l0.3-1.8h-1.1l0.1-0.9h-1l-2.5,3.9 l-0.9-0.8l-0.7,0.3l-0.1,1l-0.7,5l-1.2,7.2L482.5,471.1L482.5,471.1z'
},
'BJ': {
d: 'M996.9,498l-4.3-3.7h-2l-1.9,1.9l-1.2,1.9l-2.7,0.6l-1.2,2.8l-1.9,0.7l-0.7,3.3l1.7,1.9l2,2.3l0.2,3.1l1.1,1.3 l-0.2,14.6l1.4,4.4l4.6-0.8l0.3-10.2L992,518l1-4l1.7-1.9l2.7-4l-0.6-1.7l1.1-2.5l-1.2-3.8L996.9,498L996.9,498z'
},
'BM': {
d: 'M630.2,366.8l0.4-0.6h-0.1l-0.5,0.5l-0.6,0.2l0.1,0.1h0.1L630.2,366.8z'
},
'BT': {
d: 'M1474.7,395.5l-2.7-1.8l-2.9-0.1l-4.2-1.5l-2.6,1.6l-2.6,4.8l0.3,1.2l5.5,2.5l3.2-1l4.7,0.4l4.4-0.2l-0.4-3.9 L1474.7,395.5L1474.7,395.5z'
},
'BO': {
d: 'M655.7,700.5l1.6-1.3l-0.8-3.6l1.3-2.8l0.5-5l-1.6-4l-3.2-1.7l-0.8-2.6l0.6-3.6l-10.7-0.3l-2.7-7.4l1.6-0.1 l-0.3-2.8l-1.2-1.8l-0.5-3.7l-3.3-1.9l-3.5,0.1l-2.5-1.9l-3.8-1.2l-2.4-2.4l-6.3-1l-6.4-5.7l0.3-4.3l-0.9-2.5l0.4-4.7l-7.3,1.1 l-2.8,2.3l-4.8,2.6l-1.1,1.9l-2.9,0.2l-4.2-0.6l5.5,10.3l-1.1,2.1l0.1,4.5l0.3,5.4l-1.9,3.2l1.2,2.4l-1.1,2.1l2.8,5.3L591,684 l3.1,4.3l1.2,4.6l3.2,2.7l-1.1,6.2l3.7,7.1l3.1,8.8l3.8-0.9l4-5.7l7.4,1.5l3.7,4.6l1.6-5.1l6.3,0.3l1,1.3l1.5-7.6l-0.2-3.4l2.1-5.6 l9.5-1.9l5.1,0.1l5.4,3.3L655.7,700.5L655.7,700.5z'
},
'BA': {
d: 'M1062.2,284.9l-2.3,0.1l-1,1.3l-1.9-1.4l-0.9,2.5l2.7,2.9l1.3,1.9l2.5,2.3l2,1.4l2.2,2.5l4.7,2.4l0.4-3.4l1.5-1.4 l0.9-0.6l1.2-0.3l0.5-2.9l-2.7-2.3l1-2.7h-1.8l0,0l-2.4-1.4l-3.5,0.1L1062.2,284.9L1062.2,284.9z'
},
'BW': {
d: 'M1116.7,685l-1-0.5l-3.2,1.5h-1.6l-3.7,2.5l-2-2.6l-8.6,2.2l-4.1,0.2l-0.9,22.7l-5.4,0.2l-0.6,18.5l1.4,1l3,6.1 l-0.7,3.8l1.1,2.3l4-0.7l2.8-2.8l2.7-1.9l1.5-3.1l2.7-1.5l2.3,0.8l2.5,1.8l4.4,0.3l3.6-1.5l0.6-2l1.2-3l3-0.5l1.7-2.4l2-4.3l5.2-4.7 l8-4.7l-3.4-2.9l-4.2-0.9l-1.5-4.1l0.1-2.2l-2.3-0.7l-6-7l-1.6-3.7l-1.1-1.1L1116.7,685L1116.7,685z'
},
'BR': {
d: 'M659,560.1l-1.4,0.2l-3.1-0.5l-1.8,1.7l-2.6,1.1l-1.7,0.2l-0.7,1.3l-2.7-0.3l-3.5-3l-0.3-2.9l-1.4-3.3l1-5.4 l1.6-2.2l-1.2-3l-1.9-0.9l0.8-2.8l-1.3-1.5l-2.9,0.3l0.7,1.8l-2.1,2.4l-6.4,2.4l-4,1l-1.7,1.5l-4.4-1.6l-4.2-0.8l-1,0.6l2.4,1.6 l-0.3,4.3l0.7,4l4.8,0.5l0.3,1.4l-4.1,1.8l-0.7,2.7l-2.3,1l-4.2,1.5l-1.1,1.9l-4.4,0.5l-3-3.4l-1.1,0.8l-1-3.8l-1.6-2l-1.9,2.2 l-10.9-0.1v3.9l3.3,0.7l-0.2,2.4l-1.1-0.6l-3.2,1v4.6l2.5,2.4l0.9,3.6l-0.1,2.8l-2.2,17.4l-5.1-0.3l-0.7,1l-4.6,1.2l-6.2,4.3l-0.4,3 l-1.3,2.2l0.7,3.4l-3.3,1.9l0.1,2.7L562,620l2.6,5.8l3.3,3.8l-1,2.8l3.7,0.3l2.3,3.4l4.9,0.2l4.4-3.8l0.2,9.7l2.6,0.7l3-1.1l4.2,0.6 l2.9-0.2l1.1-1.9l4.8-2.6l2.8-2.3l7.3-1.1l-0.4,4.7l0.9,2.5l-0.3,4.3l6.4,5.7l6.3,1l2.4,2.4l3.8,1.2l2.5,1.9l3.5-0.1l3.3,1.9 l0.5,3.7l1.2,1.8l0.3,2.8l-1.6,0.1l2.7,7.4l10.7,0.3l-0.6,3.6l0.8,2.6l3.2,1.7l1.6,4l-0.5,5l-1.3,2.8l0.8,3.6l-1.6,1.3l1.9,3.6 l0.4,8.6l6,1.2l2.1-1.2l3.9,1.7l1.2,1.9l1,5.8l0.9,2.5l2,0.3l2-1.1l2.1,1.2l0.3,3.5l-0.3,3.8l-0.7,3.6l2.6-1.2l3.1,3.7l0.5,5.1 l-4.2,3.5l-3.3,2.6l-5.3,6.2l-5.9,8.6l3.4-0.7l6.2,4.9l1.9-0.2l6.2,4.1l4.8,3.5l3.8,4.3l-1.9,3l2.1,3.7l2.9-3.7l1.5-6l3.2-3l3.9-5 l4.5-11.2l3.4-3.5l0.8-3.1l0.3-6.4l-1.3-3.5l0.3-4.8l4.1-6.3l6-5.1l6-1.8l3.6-2.9l8.5-2.4h5.9l1.1-3.8l4.2-2.8l0.6-6.5l5.1-8.3 l0.5-8.5l1.6-2.6l0.3-4.1l1.1-9.9l-1-11.9l1.4-4.7l1.4-0.1l3.9-5.5l3.3-7.2l7.7-8.8l2.7-4.2l2-10.5l-1-3.9l-2-8.1l-2.1-2l-4.8-0.2 l-4.3-1.9l-7.3-7.1l-8.4-5.3l-8.4,0.3l-10.9-3.4l-6.5,2l0.8-3.5l-2.7-3.8l-9.4-3.8l-7.1-2.3l-4.2,4.1l-0.3-6.3l-9.9-1l-1.7-2 l4.2-5.2l-0.1-4.4l-3-1l-3-11.2l-1.3-3.5l-1.9,0.3l-3.5,5.8l-1.8,4.7l-2.1,2.4l-2.7,0.5l-0.8-1.8l-1.2-0.3l-1.8,1.8l-2.4-1.3 l-3.2-1.4l-2.7,0.7l-2.3-0.6l-0.5,1.8l0.9,1.3l-0.5,1.3L659,560.1L659,560.1z'
},
'VG': {
d: 'M619.2,455.1l0.3-0.2l-0.2-0.1h-0.4l-0.3,0.2l0.1,0.1H619.2L619.2,455.1z M620.3,454.7l0.4-0.4l-0.5,0.1l-0.2,0.2 l0.1,0.1h0.1L620.3,454.7L620.3,454.7z M621.1,452.9h-0.2h-0.5l0,0l0.1,0.1h0.3l0.3,0.1l0,0L621.1,452.9L621.1,452.9z'
},
'BN': {
d: 'M1617.8,543.4l2.7,3.3l1.1-2.2l2.7,0.2l0.1-4.1l0.1-3.1l-4.6,3.5L1617.8,543.4L1617.8,543.4z'
},
'BG': {
d: 'M1121.6,294.3l-3-0.7l-4-2.2l-5.8,1.4l-2.3,1.6l-7.5-0.3l-4-1l-1.9,0.5l-1.8-2.6l-1.1,1.4l0.7,2.3l2.8,2.6l-1.7,1.9 l-0.7,2l0.6,0.7l-0.7,0.9l2.8,2l0.8,4.1l3.8,0.2l3.9-1.7l3.9,2.1l4.6-0.6l-0.3-3l5-2l4.5,0.8l-2.1-3.5l1.3-4.4L1121.6,294.3 L1121.6,294.3z'
},
'BF': {
d: 'M978.8,477.2h-3.6l-1.4-1.2l-3,0.9l-5.2,2.6l-1.1,2l-4.3,2.9l-0.8,1.6l-2.3,1.3l-2.7-0.9l-1.6,1.6l-0.8,4.4 l-4.5,5.2l0.2,2.2l-1.6,2.7l0.4,3.7l2.5,1.4l1,2.1l2.5,1.3l1.9-1.6l2.7-0.2l3.8,1.6l-0.8-4.8l0.2-3.6l9.7-0.3l2.4,0.5l1.8-1l2.6,0.5 l4.9,0.1l1.9-0.7l1.2-2.8l2.7-0.6l1.2-1.9l0.1-4.4l-6.4-1.4l-0.2-3.1l-3.1-4.1l-0.8-2.9L978.8,477.2L978.8,477.2z'
},
'BI': {
d: 'M1148.2,590l-0.3-2.5l0,0l-3-0.4l-1.7,3.6l-3.5-0.5l1.4,2.9l0.1,1.1l2,6.1l-0.1,0.3l0.6-0.1l2.1-2.3l2.2-3.3 l1.4-1.4v-2L1148.2,590L1148.2,590z'
},
'KH': {
d: 'M1574.8,481.8l-5.2-2.3l-2,4.3l-4.9-2.4l-5.3-1l-7.1,1.3l-3,5.2l2.1,7.7l3.4,6.6l2.6,3.3l4.7,0.9l4.7-2.5l5.8-0.5 l-2.8-3.8l8.9-4.9l-0.1-7.7L1574.8,481.8L1574.8,481.8z'
},
'CM': {
d: 'M1060.1,502.9l0.2-4.3l-0.5-4.2l-2.2-4.1l-1.6,0.4l-0.2,2l2.3,2.6l-0.6,1.1l-0.3,2.1l-4.6,5l-1.5,4l-0.7,3.3 l-1.2,1.4l-1.1,4.5l-3,2.6l-0.8,3.2l-1.2,2.6l-0.5,2.6l-3.9,2.2l-3.2-2.6l-2.1,0.1l-3.3,3.7l-1.6,0.1l-2.7,6.1l-1.4,4.5v1.8l1.4,0.9 l1.1,2.8l2.6,1.1l2.2,4.2l-0.8,5l9.2,0.2l2.6-0.4l3.4,0.8l3.4-0.8l0.7,0.3l7.1,0.3l4.5,1.7l4.5,1.5l0.4-3.5l-0.6-1.8l-0.3-2.9 l-2.6-2.1l-2.1-3.2l-0.5-2.3l-2.6-3.3l0.4-1.