mirror of
https://github.com/tabler/tabler.git
synced 2026-10-20 23:04:20 +04:00
Add the VectorMap plugin, a vector map with no map library (#3269)
This commit is contained in:
1 parent
68da44633d
commit
8ab6441cc7
44 files changed
+3807
-638
No files matched your search
@@ -0,0 +1,289 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
/**
|
||||
* Generates the map files of the VectorMap plugin (`core/js/maps/*.ts`) from
|
||||
* Natural Earth (https://www.naturalearthdata.com, public domain).
|
||||
*
|
||||
* The shapes are projected here, at build time, and written as ready SVG path
|
||||
* data. The plugin only puts them into an `<svg>`, so no geo library ships to
|
||||
* the browser.
|
||||
*
|
||||
* Usage: pnpm run generate:maps
|
||||
*/
|
||||
|
||||
import { writeFileSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import * as prettier from 'prettier'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const outDir = join(__dirname, '..', 'core', 'js', 'maps')
|
||||
|
||||
// Pinned, so that a new run gives the same file.
|
||||
const SOURCE = 'https://raw.githubusercontent.com/nvkelso/natural-earth-vector/v5.1.2/geojson'
|
||||
|
||||
type Position = [number, number]
|
||||
type Ring = Position[]
|
||||
|
||||
interface Feature {
|
||||
properties: Record<string, string | number | null>
|
||||
geometry: { type: 'Polygon'; coordinates: Ring[] } | { type: 'MultiPolygon'; coordinates: Ring[][] }
|
||||
}
|
||||
|
||||
interface MapConfig {
|
||||
/** File name in `core/js/maps/` and the name the map is registered under */
|
||||
name: string
|
||||
/** Natural Earth file, without the extension */
|
||||
source: string
|
||||
/** Width of the viewBox; the height follows from the projection */
|
||||
width: number
|
||||
/** Region codes left out of the map */
|
||||
exclude: string[]
|
||||
/**
|
||||
* Countries too small to have a shape in `source`. They are taken from a
|
||||
* more detailed file and put on the map as a point.
|
||||
*/
|
||||
points?: {
|
||||
/** Natural Earth file, without the extension */
|
||||
source: string
|
||||
/** Natural Earth `TYPE` values that get a point */
|
||||
types: string[]
|
||||
/** Region codes that get a point whatever their type */
|
||||
include: string[]
|
||||
}
|
||||
}
|
||||
|
||||
const maps: MapConfig[] = [
|
||||
{
|
||||
name: 'world',
|
||||
source: 'ne_110m_admin_0_countries',
|
||||
width: 1000,
|
||||
exclude: ['AQ'],
|
||||
points: {
|
||||
source: 'ne_50m_admin_0_countries',
|
||||
types: ['Sovereign country'],
|
||||
include: ['HK', 'MO'],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
// Territories with no ISO 3166-1 code in Natural Earth, keyed by `ADM0_A3`.
|
||||
// `XK` is the code Kosovo uses in practice; the other two are user-assigned.
|
||||
const CODE_OVERRIDES: Record<string, string> = {
|
||||
KOS: 'XK',
|
||||
CYN: 'XC',
|
||||
SOL: 'XS',
|
||||
}
|
||||
|
||||
// One decimal place in a 1000 unit wide viewBox is about 0.04° of longitude,
|
||||
// well below the detail of the 110m data.
|
||||
const PRECISION = 10
|
||||
|
||||
const RADIANS = Math.PI / 180
|
||||
|
||||
/**
|
||||
* Miller cylindrical projection, in radians. Placing a point on the map by its
|
||||
* coordinates takes the same formula, which is why `projection` is written
|
||||
* into the map file.
|
||||
*/
|
||||
const miller = ([lng, lat]: Position): Position => [lng * RADIANS, 1.25 * Math.log(Math.tan(Math.PI / 4 + 0.4 * lat * RADIANS))]
|
||||
|
||||
const regionCode = (properties: Feature['properties']): string | null => {
|
||||
const override = CODE_OVERRIDES[String(properties.ADM0_A3)]
|
||||
if (override) {
|
||||
return override
|
||||
}
|
||||
|
||||
// `ISO_A2` is "-99" for France and Norway; `ISO_A2_EH` has them right.
|
||||
for (const key of ['ISO_A2_EH', 'ISO_A2']) {
|
||||
const code = String(properties[key] ?? '')
|
||||
if (/^[A-Z]{2}$/.test(code)) {
|
||||
return code
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const ringsOf = (geometry: Feature['geometry']): Ring[] => (geometry.type === 'Polygon' ? geometry.coordinates : geometry.coordinates.flat())
|
||||
|
||||
// "0.5" → ".5", "-0.5" → "-.5"
|
||||
const formatNumber = (tenths: number): string => String(tenths / PRECISION).replace(/^(-?)0\./, '$1.')
|
||||
|
||||
// A minus sign already separates two numbers, so a space is only needed in
|
||||
// front of a positive one.
|
||||
const joinNumbers = (numbers: number[]): string => {
|
||||
let out = ''
|
||||
for (const number of numbers) {
|
||||
const text = formatNumber(number)
|
||||
out += out && !text.startsWith('-') ? ` ${text}` : text
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* One ring as path data: an absolute move, then relative lines. The deltas are
|
||||
* taken between already rounded points, so rounding does not add up.
|
||||
*/
|
||||
const ringPath = (points: Position[]): string => {
|
||||
const rounded: Position[] = []
|
||||
for (const [x, y] of points) {
|
||||
const point: Position = [Math.round(x * PRECISION), Math.round(y * PRECISION)]
|
||||
const last = rounded.at(-1)
|
||||
if (!last || last[0] !== point[0] || last[1] !== point[1]) {
|
||||
rounded.push(point)
|
||||
}
|
||||
}
|
||||
|
||||
// GeoJSON repeats the first point at the end; `z` closes the ring instead.
|
||||
const first = rounded[0]
|
||||
const last = rounded.at(-1)
|
||||
if (rounded.length > 1 && first && last && first[0] === last[0] && first[1] === last[1]) {
|
||||
rounded.pop()
|
||||
}
|
||||
|
||||
if (rounded.length < 3) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const deltas: number[] = []
|
||||
for (let i = 1; i < rounded.length; i++) {
|
||||
deltas.push(rounded[i][0] - rounded[i - 1][0], rounded[i][1] - rounded[i - 1][1])
|
||||
}
|
||||
|
||||
return `M${joinNumbers(rounded[0])}l${joinNumbers(deltas)}z`
|
||||
}
|
||||
|
||||
async function load(source: string): Promise<Feature[]> {
|
||||
const url = `${SOURCE}/${source}.geojson`
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not load ${url}: ${response.status}`)
|
||||
}
|
||||
|
||||
const { features } = (await response.json()) as { features: Feature[] }
|
||||
return features
|
||||
}
|
||||
|
||||
// Where the long name of Natural Earth is the formal one, not the common one
|
||||
const NAME_OVERRIDES: Record<string, string> = {
|
||||
CV: 'Cabo Verde',
|
||||
}
|
||||
|
||||
const regionName = (properties: Feature['properties']): string => NAME_OVERRIDES[regionCode(properties) ?? ''] ?? String(properties.NAME_LONG ?? properties.NAME)
|
||||
|
||||
async function generate(config: MapConfig): Promise<void> {
|
||||
const features = await load(config.source)
|
||||
|
||||
const regions: { code: string; name: string; rings: Ring[] }[] = []
|
||||
for (const feature of features) {
|
||||
const code = regionCode(feature.properties)
|
||||
if (!code) {
|
||||
console.warn(` skipped "${feature.properties.NAME}": no region code`)
|
||||
continue
|
||||
}
|
||||
|
||||
if (config.exclude.includes(code)) {
|
||||
continue
|
||||
}
|
||||
|
||||
regions.push({
|
||||
code,
|
||||
name: regionName(feature.properties),
|
||||
rings: ringsOf(feature.geometry).map((ring) => ring.map(miller)),
|
||||
})
|
||||
}
|
||||
|
||||
const duplicate = regions.find((region, index) => regions.findIndex((other) => other.code === region.code) !== index)
|
||||
if (duplicate) {
|
||||
throw new Error(`Region code "${duplicate.code}" is used twice`)
|
||||
}
|
||||
|
||||
// Fit the projected shapes into the viewBox. The y axis points down in SVG.
|
||||
let [minX, minY, maxX, maxY] = [Infinity, Infinity, -Infinity, -Infinity]
|
||||
for (const [x, y] of regions.flatMap((region) => region.rings.flat())) {
|
||||
minX = Math.min(minX, x)
|
||||
maxX = Math.max(maxX, x)
|
||||
minY = Math.min(minY, y)
|
||||
maxY = Math.max(maxY, y)
|
||||
}
|
||||
|
||||
const scale = config.width / (maxX - minX)
|
||||
const translate: Position = [-minX * scale, maxY * scale]
|
||||
const height = Math.ceil((maxY - minY) * scale)
|
||||
const round = (value: number): number => Math.round(value * 1000) / 1000
|
||||
|
||||
// A point sits where Natural Earth puts the label of the country.
|
||||
const points: { code: string; name: string; position: Position }[] = []
|
||||
if (config.points) {
|
||||
const { source, types, include } = config.points
|
||||
for (const { properties } of await load(source)) {
|
||||
const code = regionCode(properties)
|
||||
if (!code || config.exclude.includes(code) || regions.some((region) => region.code === code)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!types.includes(String(properties.TYPE)) && !include.includes(code)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const [x, y] = miller([Number(properties.LABEL_X), Number(properties.LABEL_Y)])
|
||||
const position: Position = [x * scale + translate[0], translate[1] - y * scale]
|
||||
if (!(position[0] >= 0 && position[0] <= config.width && position[1] >= 0 && position[1] <= height)) {
|
||||
throw new Error(`Point "${code}" is outside of the map`)
|
||||
}
|
||||
|
||||
points.push({ code, name: regionName(properties), position })
|
||||
}
|
||||
}
|
||||
|
||||
regions.sort((a, b) => a.code.localeCompare(b.code))
|
||||
points.sort((a, b) => a.code.localeCompare(b.code))
|
||||
|
||||
const data = {
|
||||
width: config.width,
|
||||
height,
|
||||
projection: { type: 'miller', scale: round(scale), translate: translate.map(round) },
|
||||
regions: Object.fromEntries([
|
||||
...regions.map((region) => {
|
||||
const path = region.rings.map((ring) => ringPath(ring.map(([x, y]): Position => [x * scale + translate[0], translate[1] - y * scale]))).join('')
|
||||
|
||||
if (!path) {
|
||||
throw new Error(`Region "${region.code}" has no shape left after rounding`)
|
||||
}
|
||||
|
||||
return [region.code, { name: region.name, path }]
|
||||
}),
|
||||
// A line of no length: the plugin draws it as a dot
|
||||
...points.map((point) => [point.code, { name: point.name, path: `M${joinNumbers(point.position.map((value) => Math.round(value * PRECISION)))}h0`, point: true }]),
|
||||
]),
|
||||
}
|
||||
|
||||
const source = `// Generated by \`pnpm run generate:maps\` from Natural Earth (public domain,
|
||||
// https://www.naturalearthdata.com). Do not edit by hand.
|
||||
|
||||
import type { VectorMapData } from '../src/vector-map'
|
||||
|
||||
export const ${config.name}: VectorMapData = ${JSON.stringify(data)}
|
||||
`
|
||||
|
||||
const file = join(outDir, `${config.name}.ts`)
|
||||
const options = await prettier.resolveConfig(file)
|
||||
const formatted = await prettier.format(source, { ...options, filepath: file })
|
||||
writeFileSync(file, formatted)
|
||||
|
||||
console.log(`✓ ${config.name}: ${regions.length} regions, ${points.length} points, ${config.width}x${height}, ${(formatted.length / 1024).toFixed(1)} kB`)
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
for (const config of maps) {
|
||||
await generate(config)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error: unknown) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@tabler/core": minor
|
||||
"@tabler/preview": minor
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added the `VectorMap` plugin: an SVG world map with values, color scales, a legend, markers, lines, selection, tooltips and zoom.
|
||||
@@ -8,10 +8,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const baseName = process.env.BASE_NAME || 'tabler'
|
||||
const entryFile = baseName
|
||||
// `tabler-map` is an add-on to the main bundle: its UMD build extends the
|
||||
// `tabler` global instead of creating one of its own.
|
||||
const isAddon = baseName === 'tabler-map'
|
||||
const libraryName = isAddon ? 'tabler' : baseName
|
||||
// Some entries add to a global instead of creating their own, so they can be
|
||||
// loaded next to the main bundle:
|
||||
// - `tabler-map` and `tabler-vector-map` are add-ons, their UMD builds extend
|
||||
// the `tabler` global;
|
||||
// - `maps/*` are map files, each adds its map to the `tablerVectorMaps` global.
|
||||
const isMap = baseName.startsWith('maps/')
|
||||
const isAddon = baseName === 'tabler-map' || baseName === 'tabler-vector-map'
|
||||
const libraryName = isMap ? 'tablerVectorMaps' : isAddon ? 'tabler' : baseName
|
||||
|
||||
const bannerText = getBanner()
|
||||
|
||||
@@ -29,5 +33,5 @@ export default createViteConfig({
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText,
|
||||
minify: false,
|
||||
extend: isAddon,
|
||||
extend: isMap || isAddon,
|
||||
})
|
||||
@@ -0,0 +1,453 @@
|
||||
// Generated by `pnpm run generate:maps` from Natural Earth (public domain,
|
||||
// https://www.naturalearthdata.com). Do not edit by hand.
|
||||
|
||||
import type { VectorMapData } from '../src/vector-map'
|
||||
|
||||
export const world: VectorMapData = {
|
||||
width: 1000,
|
||||
height: 489,
|
||||
projection: { type: 'miller', scale: 159.155, translate: [500, 316.038] },
|
||||
regions: {
|
||||
AE: { name: 'United Arab Emirates', path: 'M643.3 247.4l.5-.2 .1 .8 2.1-.4 2.3 0 1.7 .1 1.9-2 2.1-1.9 1.8-1.8 .5 1 .4 2.4-1.5 0-.2 1.9 .5 .4-1.3 .6 0 1.2-.8 1.2 0 1.2-.6 .6-8.4-1.5-1-3z' },
|
||||
AF: {
|
||||
name: 'Afghanistan',
|
||||
path: 'M684.8 207.2l1.5 0 2.1 .7 .9 .4 2-1 .9 .6 .9-1.5 1.7 .1 .4-.5 .3-1.3 1.2-1.1 1.5 .7-.3 1 .8 .2-.2 2.6 1.1 1.1 .9-.7 1.3-.3 1.7-1.4 1.9 .2 2.9 0 .5 .9-1.6 .4-1.5 .6-3.1 .4-3 .6-1.6 1.4 .6 1.3 .3 1.6-1.4 1.3 .2 1.2-.8 1.2-2.6-.1 1 2-1.7 .8-1.2 1.9 .1 1.8-1 .9-1.1-.3-2.1 .4-.3 .9-2.1 0-1.5 1.7-.1 2.6-3.6 1.3-1.9-.3-.6 .7-1.7-.4-2.8 .4-4.6-1.5 2.5-2.8-.2-2-2.1-.5-.2-1.9-.9-2.5 1.1-1.7-1.2-.5 .8-2.2 1.1-4 2.9 1.2 2.1-.4 .5-1.4 2.2-.5 1.6-1 .6-2.5 2.3-.6 .4-1.2 1.3 .9z',
|
||||
},
|
||||
AL: { name: 'Albania', path: 'M558.4 195.9l-.1 .9-.9 .4-.1 1.1-1.3 1.6-.5-.2-.1-.8-1.5-1.1-.2-1.5 .2-2.3 .4-1-.5-.5-.2-1.1 1.2-1.7 .2 .7 .8-.3 .5 .9 .7 .3 .2 1.2-.4 1.2 .4 1.4z' },
|
||||
AM: { name: 'Armenia', path: 'M629.2 202.7l-1 .1-1.2-1.9 .1-.5-1.3 0-.8-.9-.6 .1-1.1-1-2-.8 .2-1.6-.4-1.1 3.8-.6 .6 .9 1.1 .6-.6 .8 1.5 1.1-.8 1.1 1.2 .9 1.2 .5z' },
|
||||
AO: {
|
||||
name: 'Angola',
|
||||
path: 'M536.1 329.3l-1 .6-.5 .7-.1 1.2-.7 .3-.7-2.1 1.1-1.2 .9-.4zM534.2 333l1.2-.4 .8 .1 1-.4 8.2 .1 .6 2.1 .8 1.6 .7 .9 1 1.5 1.9-.2 .9-.4 1.5 .4 .4-.7 .7-1.7 1.8-.1 .1-.4 1.4-.1-.2 1.1 3.4-.1 0 1.8 .6 1.1-.4 1.6 .2 1.8 .9 1-.2 3.4 .7-.3 1.2 .1 1.8-.5 1.2 .2 .3 .9-.3 1.3 .5 1.4-.4 1 .2 1-5.8 0-.1 9 1.9 2.3 1.8 1.8-5.1 1.2-6.7-.4-2-1.4-11.2 .1-.4 .2-1.7-1.3-1.8-.1-1.7 .5-1.3 .6-.3-1.8 .4-2.5 1-2.6 .1-1.2 .9-2.6 .7-1.2 1.6-1.8 .9-1.3 .3-2-.2-1.6-.8-1-.8-1.7-.6-1.7 .1-.6 .9-1.1-.9-2.7-.5-1.9-1.4-1.8z',
|
||||
},
|
||||
AR: {
|
||||
name: 'Argentina',
|
||||
path: 'M309.3 477.5l1.1 1.8 1.4 2.8 3.6 2.3 3.9 1-1.2 1.9-2.7 .2-1.4-1.4-1.7-.1-2.9 0zM339.9 402.6l-.7 2.4-.7 3.2 0 3.1-.6 .6-.2 2.1-.2 1.6 3.5 2.7-.3 2.2 1.7 1.3-.1 1.6-2.7 4.1-4.1 1.8-5.6 .6-3.1-.3 .6 1.9-.5 2.5 .5 1.6-1.7 1.2-2.8 .5-2.7-1.2-1.1 .8 .4 3.3 1.9 1 1.5-1 .8 1.7-2.5 1.1-2.3 2.1-.4 3.4-.6 1.8-2.6 0-2.2 1.8-.8 2.6 2.7 2.5 2.7 .7-1 3.2-3.3 2-1.8 4.2-2.5 1.5-1.2 1.7 .9 3.8 1.9 2.2-1.2-.2-2.6-.6-6.7-.5-1.1-2.2 0-2.7-1.8 .2-1-1.3-.2-3.8 2.1-1.6 .9-2.3-.3-1.8 1.4-3 1-4.6-.3-2 1.3-.7-.3-1.2-1.3-.7 .9-1.5-1.3-1.2-.6-3.9 1.1-.7-.5-4 .7-3.4 .7-2.9 1.7-1.2-.9-3.1 0-3 2.1-2 0-2.7 1.6-3.1 0-2.8-.8-.6-1.2-5.3 1.7-3.2-.3-2.9 1-2.7 1.8-2.9 2-1.8-.8-1.2 .5-.9 0-5 3-1.4 .9-3.1-.3-.7 2.3-2.7 3.6 .8 1.7 2.1 1.1-2.4 3.1 .1 .5 .7 5.1 4.7 2.3 .5 3.3 2.2 2.9 1.1 .4 1.3-2.7 4.6 2.8 .8 3.1 .4 2.2-.5 2.5-2.2 .5-2.7 1.3-.5 1.4 1.7 0 2.4-2.4 1.6-1.8 1.2-3.2 2.9z',
|
||||
},
|
||||
AT: { name: 'Austria', path: 'M547.2 171l-.2 1.4-1.6 0 .5 .8-.9 2.3-.5 .6-2.5 .1-1.4 .7-2.2-.2-4-.9-.6-1.2-2.8 .6-.3 .6-1.7-.5-1.4-.1-1.3-.6 .5-.9-.1-.6 .8-.2 1.4 1 .4-.9 2.4 .1 2-.6 1.4 .1 .8 .7 .3-.6-.4-2.3 1-.4 1-1.7 2 1.2 1.6-1.5 1-.3 2.1 1.1 1.3-.2 1.3 .7-.2 .5z' },
|
||||
AU: {
|
||||
name: 'Australia',
|
||||
path: 'M910.2 436.1l1.7 .2 .2 3.9-.9 1.2-.3 2.7-1-.9-1.9 2.3-.6-.2-1.7-.1-1.7-2.8-.4-2.3-1.6-2.9 .1-1.5 1.8 .3 2.7 1.2 1.5-.5zM850.4 408.7l-2.9 1.6-2.4 .7-.6 1.6-1 1.3-2.4 .1-1.7 .3-2.5-.6-2 .3-1.9 .2-1.6 1.6-.8-.1-1.4 .9-1.4 1-2-.1-1.8 0-3-2-1.5-.6 .1-1.8 1.4-.5 .4-.7-.1-1.1 .4-2.1-.3-1.9-1.5-3-.5-1.8 .2-1.7-1.2-2 0-.9-1.3-1.2-.3-2.3-1.6-2.4-.4-1.3 1.3 1.3-1-2.7 1.4 .8 .8 1.2 0-1.5-1.4-2.4-.3-.9-.6-.9 .3-1.7 .6-.7 .3-1.5-.3-1.7 1.2-2.1 .2 2.2 1.2-2 2.2-.9 1.4-1.3 2.1-1 1.3-.3 .7 .4 2.2-1.1 1.7-.3 .4-.6 .8-.3 1.5 .1 2.9-.9 1.5-1.3 .7-1.5 1.7-1.5 .1-1.1 .1-1.6 1.9-2.4 1.2 2.5 1.2-.6-1-1.3 .8-1.4 1.3 .6 .3-2.2 1.5-1.4 .7-1.1 1.4-.5 0-.8 1.2 .4 .1-.8 1.2-.4 1.4-.3 2 1.3 1.6 1.6 1.7 .1 1.8 .2-.6-1.5 1.3-2.3 1.3-.7-.5-.7 1.2-1.7 1.7-1 1.4 .4 2.4-.5-.1-1.5-2-.9 1.5-.4 1.8 .7 1.5 1.1 2.3 .7 .8-.2 1.7 .8 1.7-.8 1 .3 .6-.6 1.3 1.4-.7 1.5-1.1 1.2-.9 .1 .3 1.1-.8 1.4-1 1.4 .2 .8 2.2 1.6 2.1 .9 1.5 1 2 1.7 .8 0 1.4 .7 .4 .9 2.7 .9 1.8-.9 .6-1.6 .5-1.2 .4-1.6 .8-2.3-.4-1.3 .2-.9-.3-1.6 .4-2.1 .5-.6-.4-.9 .6-1.5 .6-1.6 0-.8 1.1-1 .8 1.4 .2 1.7 .6 .4 .2 1.1 1 1.5 .2 1.6-.1 1 1 2.2 1.8-1 .9 1.2 1.3 1.1-.3 1.2 .6 2.5 .4 1.4 .7 .3 .8 2.5-.3 1.5 .9 1.9 3 1.5 2 1.4 1.9 1.3-.4 .7 1.6 1.8 1.1 3.1 1.1-.6 1.1 1.3 .7-.5 .5 3.1 1.9 1.8 1.3 1.1 2.2 2.4 .8 2.4 0 1.7-.1 1.9 1.3 2.5-.2 2.7-.5 1.4-.7 2.7 0 1.7-.5 2.2-1.2 2.8-2.1 1.6-1 2.4-.9 1.5-.8 2.7-1.1 1.6-.7 2.4-.4 2.2 .2 1-1.6 1.1-3.1 .1-2.6 1.3-1.3 1.3-1.7 1.4-2.3-1.5-1.7-.5 .5-1.7-1.6 .6-2.4 2.3-2.4-.8-1.6-.5-1.5-.3-2.7-.9-1.8-2-.5-2.4-.7-1.6-1.4-1.3-2.6-.4 .9-1.5-.7-2.4-1.3 2.2-2.5 .6 1.4-1.7 .5-1.8 1-1.6-.2-2.3-2.3 2.7-1.7 1-1.1 2.5-2.1-1.3 .1-1.6-1.8-2.3-1.4-1.1 .5-.8-3.6-1.8-1.9-.1-2.7-1.5-5 .3-3.6 1.1-3.1 1z',
|
||||
},
|
||||
AZ: {
|
||||
name: 'Azerbaijan',
|
||||
path: 'M628.9 192.5l.8 .1 1.9 2 1.2 .3 .5-.9 1.7-1.3 1.4 1.7 1.4 2.4 1.3 .1 .9 .9-2.3 .3-.5 2.5-.5 1.2-1 .7 .1 1.6-.7 .2-1.7-1.7 .9-1.6-.8-1-1 .3-3.3 2.4-.1-2.3-1.2-.5-1.2-.9 .8-1.1-1.5-1.1 .6-.8-1.1-.6-.6-.9 .7-.5 2.1 1 1.5 .2 .3-.4-1.3-1.8zM628.2 202.8l-1.9-.5-1.4-1.5-.5-1.2 .6-.1 .8 .9 1.3 0-.1 .5z',
|
||||
},
|
||||
BA: { name: 'Bosnia and Herzegovina', path: 'M551.6 189.9l-2.5-1.3-1.1-1.4-1-.8-1.3-1.2-.6-1.1-1.3-1.6 .5-1.4 1 .8 .6-.7 1.3-.1 2.4 .6 1.9-.1 1.3 .8 1 0-.7 1.5 1.3 1.3-.4 1.6-.6 .1-.5 .3-.9 .8z' },
|
||||
BD: { name: 'Bangladesh', path: 'M757.4 253.8l0 2.1-1-.4 .2 2.3-.8-1.5-.2-1.5-.5-1.4-1.2-1.7-2.5-.1 .2 1.2-.8 1.6-1.2-.6-.4 .6-.8-.4-1.1-.2-.4-2.4-1-2.2 .5-1.8-1.7-.8 .6-1.1 1.7-1.1-2-1.5 1-2.1 2.2 1.3 1.3 .2 .3 2 2.6 .4 2.6 0 1.6 .5-1.3 2.5-1.2 .2-.9 1.6 1.5 1.6 .5-1.9 .8 0z' },
|
||||
BE: { name: 'Belgium', path: 'M517.1 161.3l-.3 2.5-.7 .1-.3 2.1-2.5-1.7-1.4 .3-1.9-1.7-1.3-1.5-1.3 0-.4-1.3 2.2-.8 2 .3 2.6-.7 1.8 1.6z' },
|
||||
BF: { name: 'Burkina Faso', path: 'M485 287.1l-.2-1.6 .8-1.2-.1-.9 2.2-2.4 .4-1.9 .8-.7 1.3 .4 1.2-.6 .4-.7 2.1-1.3 .5-.9 2.6-1.2 1.6-.4 .7 .6 1.7 0-.2 1.3 .4 1.3 1.6 1.9 0 1.3 3.2 .7 0 1.9-.6 .9-1.4 .2-.5 1.3-1 .3-2.4-.1-1.3-.2-.9 .4-1.2-.2-4.9 .2 0 1.6 .3 2.1-1.9-.8-1.3 .2-.9 .7-1.3-.6-.5-1z' },
|
||||
BG: { name: 'Bulgaria', path: 'M562.9 184.5l.8 1.4 1.1-.2 2.1 .5 4.1 .2 1.4-.9 3.3-.8 2 1.2 1.6 .4-1.4 1.4-1 2.4 .9 1.9-2.4-.4-2.9 1 0 1.7-2.5 .3-2-1.2-2.2 .9-2-.1-.2-2.2-1.4-1 .4-.5-.3-.4 .5-1.1 1.1-1-1.4-1.5-.2-1.2z' },
|
||||
BI: { name: 'Burundi', path: 'M584.6 322.7l.2 1.1 .6 .7 0 .9-.7 .6-1 1.4-1.1 1-1.1 .1-.2-3.3-.7-1.3 1.7 .2 .9-1.5z' },
|
||||
BJ: { name: 'Benin', path: 'M507.5 298.6l-2.3 .4-.7-2 .1-6.4-.5-.6-.1-1.3-1-1-.9-.9 .4-1.4 1-.3 .5-1.3 1.4-.2 .6-.9 .9-.8 1 0 2.1 1.6-.1 .9 .6 1.7-.5 1.1 .3 .8-1.4 1.7-.8 .9-.5 1.8 0 1.7z' },
|
||||
BN: { name: 'Brunei Darussalam', path: 'M820.7 300.9l-.1 1.4-.2 1.7-1.3 0-.6 .9-1.3-1.4 1.1-1.1z' },
|
||||
BO: {
|
||||
name: 'Bolivia',
|
||||
path: 'M306.9 346.6l2 .2 1.5 0 .6-.9 2.4-1.1 1.5-1.1 3.6-.5-.3 2.1 .4 1.1-.3 1.9 3 2.5 3.2 .5 1 1.1 1.9 .5 1.2 .8 1.7 0 1.6 .8 .2 1.7 .5 .8 0 1.2-.8 .1 1.1 3.3 5.3 .1-.4 1.7 .3 1.1 1.5 .8 .7 1.8-.5 2.2-.8 1.3 .3 1.6-.9 .6 0-.8-2.6-1.5-2.6-.1-4.8 .9-1.4 2.5 0 1.6-1.1 3.5-.5-.7-3.1-.1-1.1 2.4-1.7-2.1-3.6-.8-2.3 2.7-2 .4-1.1-4-1.5-3.3 .9-2.8-1.5-1.2-.3-2.1-1.4-1.9 1.7-3.1-1.1-2.4 .6-1-.5-1 1.1-1.4 0-2.4 .2-2 .6-1z',
|
||||
},
|
||||
BR: {
|
||||
name: 'Brazil',
|
||||
path: 'M351.7 413.5l-.7-1.7 1.2-1.5-1.6-2.1-2.2-1.7-2.8-2-1.1 .1-2.8-2.3-1.8 .3 3.7-4.2 3.2-2.9 1.8-1.2 2.4-1.6 0-2.4-1.4-1.7-1.3 .5 .5-1.7 .4-1.7 0-1.6-1-.6-1.1 .5-1-.1-.3-1.2-.3-2.7-.5-.8-1.9-.8-1.1 .6-2.9-.6 .1-3.9-.8-1.7 .9-.6-.3-1.6 .8-1.3 .5-2.2-.7-1.8-1.5-.8-.3-1.1 .4-1.7-5.3-.1-1.1-3.3 .8-.1 0-1.2-.5-.8-.2-1.7-1.6-.8-1.7 0-1.2-.8-1.9-.5-1-1.1-3.2-.5-3-2.5 .3-1.9-.4-1.1 .3-2.1-3.6 .5-1.5 1.1-2.4 1.1-.6 .9-1.5 0-2-.2-1.6 .5-1.3-.4 .2-4.2-2.3 1.6-2.4 0-1.1-1.5-1.8-.2 .6-1.2-1.6-1.7-1.1-2.5 .7-.5 0-1.2 1.7-.8-.3-1.5 .7-1 .2-1.3 3.2-1.9 2.3-.5 .3-.4 2.6 .1 1.2-7.6 .1-1.2-.5-1.6-1.2-1 0-2.1 1.6-.4 .5 .3 .1-1.1-1.6-.3 0-1.7 5.4 0 .9-.9 .8 .9 .5 1.6 .5-.3 1.6 1.4 2.1-.2 .6-.8 2-.7 1.2-.4 .3-1.2 2-.8-.2-.6-2.3-.2-.4-1.7 .1-1.9-1.2-.7 .5-.3 2 .4 2.2 .7 .8-.7 2-.4 3.1-1.1 1.1-1-.4-.8 1.4-.1 .7 .6-.4 1.2 1 .4 .6 1.3-.8 1-.4 2.4 .7 1.4 .2 1.3 1.7 1.3 1.4 .1 .3-.5 .9-.1 1.2-.5 .9-.8 1.6 .3 .6-.1 1.6 .2 .2-.6-.5-.5 .3-.8 1.1 .2 1.4-.3 1.5 .6 1.3 .6 .8-.8 .6 .2 .4 .7 1.3-.2 1.1-1 .9-2.1 1.6-2.5 1-.1 .6 1.5 1.6 4.9 1.5 .4 .1 1.9-2.1 2.3 .8 .9 4.9 .4 .1 2.8 2.2-1.8 3.4 1 4.7 1.6 1.3 1.7-.4 1.5 3.2-.8 5.4 1.4 4.1-.1 4.2 2.3 3.5 3.1 2.1 .8 2.4 .2 1 .8 1 3.6 .4 1.7-1.1 4.6-1.4 1.8-3.9 3.9-1.8 3.2-2 2.5-.7 0-.8 2.1 .2 5.3-.8 4.4-.3 1.9-.9 1.1-.4 3.9-2.9 3.7-.4 3.1-2.3 1.2-.6 1.8-3.1 0-4.3 1.1-2 1.3-3.1 .9-3.3 2.3-2.3 2.9-.4 2.3 .4 1.6-.5 3-.6 1.5-1.9 1.7-3.1 5.3-2.5 2.5-1.9 1.4-1.2 2.9z',
|
||||
},
|
||||
BS: { name: 'Bahamas', path: 'M280.6 239.8l1.3-.2 1.9 .1 0 .7-3 .5zM283.9 239.1l2.2 1.3-.5 2.1-.5-.3 .1-1.6-1.3-1.2zM282.8 244.5l.8 .1 1 2.5 0 1.7-.7 .1-.7-1.7-1-.8z' },
|
||||
BT: { name: 'Bhutan', path: 'M754.7 236.9l1.1 .9-.2 1.9-2.2 .1-2.4-.2-1.7 .4-2.5-1.1-.1-.6 1.8-2.2 1.5-.8 2 .7 1.5 .1z' },
|
||||
BW: { name: 'Botswana', path: 'M581.8 378.4l-4 2.2-2.5 2.1-.9 2-.8 1.1-1.5 .2-.5 1.5-.3 .9-1.8 .7-2.2-.2-1.4-.8-1.1-.4-1.4 .7-.7 1.4-1.3 .9-1.4 1.4-2 .3-.6-1.1 .3-1.8-1.7-2.8-.7-.4 0-8.6 2.7-.1 .1-10.3 2.1-.1 4.2-1 1.1 1.2 1.8-1.1 .8-.1 1.6-.6 .5 .2 1 2.3 .6 .5 .9 1.7 3.1 3.2 1.2 .3 0 1 .8 1.8 2.2 .5z' },
|
||||
BY: {
|
||||
name: 'Belarus',
|
||||
path: 'M578.3 141l2.9 1 .4 1 1.4-.5 2.8 .9 .2 1.8-.6 1.1 1.8 2.5 1.1 .7-.2 .7 1.9 .7 .8 1-1.1 .8-2.2-.1-.5 .3 .6 1.3 .7 2.3-2.4 .3-.8 .8-.2 1.8-1.1-.3-2.5 .2-.8-.9-1 .6-1.1-.5-2.1-.1-3.1-.9-2.8-.2-2.2 0-1.5 1-1.3 .2-.1-1.7-.9-1.7 1.7-.8 0-1.5-.7-1.4-.2-1.7 2.7 .1 3-1.5 .7-2.1 2.3-1.3-.3-1.7 1.7-.7z',
|
||||
},
|
||||
BZ: { name: 'Belize', path: 'M252.4 266.1l0-.5 .3-.1 .5 .3 1-1.7 .5 0 0 .4 .6 0-.1 .8-.4 1.2 .2 .5-.3 1 .2 .3-.3 1.4-.6 .8-.5 .1-.5 .9-.9 0 .3-3.2z' },
|
||||
CA: {
|
||||
name: 'Canada',
|
||||
path: 'M158.8 167.9l-.4 0-5.4-3.6-2-1.6-5-1.5-1.5-3.2 .4-2.3-3.6-1.6-.5-3-3.3-2.8-.1-2 1.5-1.8 0-2.5-4.8-2.5-2.8-4.5-1.7-2.9-2.6-1.9-1.8-1.6-1.5-2.2-2.8 1.4-2.7 2.3-2.5-2.7-1.9-1.8-2.7-1.2-2.8-.1 .1-24.9 0-17.7 5.2 1.2 4.3 2.3 2.9 .5 2.5-2 3.3-1.6 4.2 .6 4.1-2.1 4.6-1.3 1.9 2.1 2-1.2 .7-2.3 1.9 .5 4.7 4.4 3.7-3.3 .4 3.7 3.4-.8 1-1.4 3.4 .3 4.2 2.1 6.5 1.7 3.8 .9 2.8-.3 3.7 2.4-3.9 2.4 5 1 7.5-.6 2.4-.8 3 2.9 3-2.4-2.9-2.1 1.8-1.6 3.4-.2 2.2-.5 2.3 1.1 2.8 2.6 3.1-.4 4.9 2.2 4.3-.8 4 .2-.3-3 2.5-.9 4.3 1.7 0 4.5 1.8-3.8 2.2 .1 1.2-4.8-2.9-3.1-3.3-2 .2-5.5 3.3-3.8 3.7 .9 2.8 2.2 3.8 5.7-2.5 2.5 5.2 1 0 4.9 3.7-3.8 3.3 3.2-.8 3.5 2.7 3.2 2.9-3.4 2-4.2 .1-5.3 4 .3 4.1 .8 3.7 2.4 .2 2.4-2.1 2.6 2 2.5-.4 2.3-5.4 3.3-3.9 .7-2.8-1.4-.9 2.3-2.7 3.9-.8 1.9-3.2 3.1-4 .3-2.2 1.8-.1 2.9-3.3 .5-3.4 3.5-3 4.8-1.1 3.3-.1 4.8 4.1 .7 1.2 3.8 1.3 3 3.9-.8 5.2 1.7 2.7 1.5 2 1.9 3.5 1.1 3 1.6 4.5 .2 3.1 .4-.5 3.3 .9 3.8 2 4.2 4.1 3.5 2.2-1.2 1.5-3.8-1.5-5.9-1.9-2.1 4.4-1.8 3.1-2.7 1.6-2.7-.2-2.7-1.9-3.4-3.4-3 3.3-4.3-1.2-3.8-1-6.7 2-.9 4.7 1.1 2.9 .4 2.3-1.1 2.6 1.5 3.4 2.4 .8 1.7 5 .3-.1 3.5 .9 5.3 2.6 .6 2 2.4 4-2.3 2.7-4.5 1.8-1.9 2.2 3.7 3.6 5.2 3.1 4.8-1.2 2.4 3.7 2.3 2.5 2.2 4.5 1 1.7 1.2 1.1 3.2 2.2 .5 1.1 1.5 .2 4.2-2 1.4-2 1.3-4.6 1.3-3.5 3-4.7 .6-5.9-.8-4.2 0-2.8 .2-2.4 2.6-3.5 1.6-4 4.7-3.2 3.3 2.3-.6 4.5-4.6 5.8-3 4.2-.4 2.4 1.8-2.6 2.4 .9 3.8 .9 2.6 3.6 1.7 4.6-.5 2.8-3.9 .2 2.6 1.8 1.2-3.5 2.3-6.1 2-2.8 1.4-3.1 2.5-2.1-.3-.1-2.9 4.8-2.8-4.4 .1-3.1 .4-1.8-1.9 0-4.8-1.2-1-1.9 .6-.9-.9-2.1 2.6-.9 2.7-1 1.6-1.2 .5-.8 .2-.3 .9-5.1 0-4.3 0-1.2 .6-3 2.5-.3 .2-.9 1.4-2.5 0-2.8 0-1.2 .5 .4 .7 .3 1-.1 .4-3.6 1.6-2.9 .5-3.2 1.8-.7 0-.9-.5-.4-.5 .1-.3 .6-1.2 1.3-1.8 .8-2-.5-3-.6-3.1-2.9-1.6 .3-.6-.4-.5-.7 0-.6-.5-.1-.8-.6 .3-.7-.1 .2-.3-.7-.4-.3-.9-2.1-1.1-2.3-1.2-2.7-1.4-2.6-1.2-2.5 1-.9 0-3.4-.9-2.3 .4-2.6-1.1-2.9-.5-1.9-.3-.9-.6-.5-1.9-.9 0 0 1.4-5.8 0-9.5 0-9.4 0-8.4 0-8.3 0-8.2 0-8.5 0-2.7 0-8.2 0zM266.7 115.2l2-2 3.9 0-.1 .9-3.2 2.3-2-.1zM278.4 65.9l-3.1-2.8 .2-1.9 1.3-.4 6.4 .6 4.7 2.9 .3 1.5-3-.1-3-.2-3 .8zM276.9 116.8l1.1-1.3 1.1 .1 .7 .8-1.1 2.3-1.2-.4-.7-1.2zM240 54.1l-1.5 2.2-4.1-.4-3.3-1.5 1.4-2.5 4-1.5 2.5 2zM239.3 39.6l-1.2 .2-5.2-.4-.8-1.7 5.6 .1 2 1.1zM231.2 32.1l3.4 2.1-.8 2.2-4.1 1.2-2.3-1.4-1.2-2.2-.2-2.6 3.6 .3zM255.1 57.4l-4.4-.7-7.4-1.8-1-3-.3-2.8-2.8-2.5-5.8-.7-3.2-1.8 1.1-2.4 5.7 .4 3.1 1.9 5.4-.1 2.4 1.9-.6 2.2 3.2 1.3 1.8 1.3 3.7 .3 4.1 .4 4.4-1.2 5.6-.5 4.5 .4 3 2.2 .6 2.3-1.7 1.4-4.1 1.2-3.6-.7-8 .9zM190.9 35.8l3.9 1-.9 1.7-5.2 1.7-4.1-1.9 2.3-1.9zM191.8 31.9l3.6 1.2-3.4 1.2-4.6 0 0-.9 2.9-1.8zM345.6 159.4l-1.5 2.4-1.9 3.1 1.8-1.2 1.9 .8-1 1.3 2.5 .9 1.3-.8 2.8 1.1-.9 2.6 1.9-.6 .4 1.9 .9 2.2-1.2 3.1-1.3 .1-1.8-.7 .6-2.8-.8-.5-3.2 3.1-1.6-.2 1.9-1.6-2.7-.9-2.9 .2-5.4-.1-.5-1 1.8-1.3-1.2-.9 2.3-2.2 2.9-5.8 1.7-2 2.4-1.3 1.3 .1zM267 103.4l3 1.6 3.2 1.4 .3 2.1 2-.4 2 1.5-2.5 1.4-4.3-1.1-1.6-1.9-2.7 2.3-4 2.3-.9-2.6-3.8 .4 2.4-2.2 .4-3.5 .9-4.1 2 .3 .6 2 1.4-.7zM281.2 68.3l2.6-2.1 6.2 2.7 3.8 2.4 .4 2.3 5.1-1.2 2.9 3.3 6.7 2 2.4 2 2.7 4.6-5.1 2.3 6.5 3.1 4.4 1 4 4.4 4.4 .3-.9 3.2-4.9 5.3-3.4-1.9-4.3-4.4-3.6 .6-.4 2.6 2.9 2.6 3.8 2.1 1.2 1.2 1.8 4.4-1 3.1-3.5-1.2-7-3.5 4 3.8 2.9 2.6 .4 1.5-7.5-1.7-6-2.5-3.4-2.1 1-1.3-4.1-2.3-4.1-2.1 .1 1.3-8.1 .7-2.3-1.5 1.8-3.4 5.2 0 5.8-.6-1-1.7 1-2.3 3.6-4.5-.8-2.1-1-1.6-4.3-2.3-5.6-1.7 1.8-1.2-3-3.1-2.4-.3-2.2-1.7-1.5 1.5-5 .7-10.2-1.2-5.8-1.4-4.5-.8-2.3-1.7 2.9-2.3-4-.1-.9-5.2 2.2-4.7 2.8-2.2 7.2-1.4-2.1 3.5 2.2 3.2 2.6-4.2 7-2.2 4.8 5.5-.4 3.4zM237.5 58.8l5.8 .2 5.3 1.3-4.2 4.8-3.3 1-3 3.9-3.1-.2-1.8-4.6 .1-2.6 1.4-2.3zM158.7 47.7l4.8-4.3 5.7-3.8 4.2 .1 3.8-.9-.4 4.6-2.1 2-2.6 .3-5.2 2.4-4.4 .9zM131.4 149.2l2.6-.3-.8 4.3 2.4 3.1-1.1-.1-1.7-1.7-1-1.7-1.4-1.2-.5-1.6 .2-1.2zM207 28.8l5.4 .8 7.5 2.3 2.2 2.9 1 2.5-4.5-.7-4.6-1.9-6.2-.3 2.7-1.8-3.3-1.4zM156.9 169.6l-1.4 .5-4.5-1.6-.9-1.3-2.5-1.2-.5-1.1-2.8-.6-1.1-2 .2-.8 3 .8 1.7 .5 2.6 .4 .9 1.2 1.4 1.8 2.8 1.4zM162.4 57.1l4 1.1 7.1 .3 2.7 1.6 2.9 2.3-3.5 1.3-6.8 3.7-3.4 3.7 0 2.2-7.3 2.5-1.5-2.3-6.4-2.7 1.2-2.2 1.9-3.8 2.4-3.5-2.7-3.4zM200.5 49.3l2.5-1 2.9 .3 .5 2.8-1.7 2.6-9.4 .9-7 2.4-4.3 .1-.3-1.8 5.8-2.5-12.6 .7-3.9-1 3.8-5.5 2.6-1.6 7.8 1.9 5 3.4 4.8 .4-3.9-5.4 2.5-2.2 2.9 .7 .9 2.8zM204.1 64.5l3.1 2.1 1.8 5.1 .8 3.6 4.7 2.5 5 2.4-.3 2.1-4.6 .4 1.8 1.9-.9 1.8-5.1-.8-4.7-1.3-3.3 .3-5.2 1.7-7 .7-5 .4-1.5-2.2-3.8-1.4-2.4 .6-3.4-3.9 1.8-.6 4.3-.8 3.9 .2 3.6-.8-5.3-1.2-6 .4-3.9-.1-1.5-1.9 6.5-2-4.3 .1-4.9-1.4 2.4-3.9 1.9-2.1 7.4-3.2 2.9 1-1.4 2.5 6.2-1.6 3.8 2.7 3.2-2.7 2.5 1.7 2.3 5.1 1.4-2.1-2-5.4 2.4-.8zM221 66.4l-3.1-3.4 3.3-2.6 3.3 1.1 5-.7 .7 1.6-2.6 2.5 4.2 2.3-.5 4.7-4.5 2-2.7-.5-1.9-1.9-6.9-4 0-1.7zM203.9 61.7l3.7-.2 2.1 1.2-2.4 3.5-4.4-3.8zM226.4 44.3l2.1 2.6 .1 3-1.3 4.1-4.5 .6-3-.9 0-3.2-4.5 .4-.2-4.4 3 .2 4.2-2 3.9 .3zM233.3 20.6l1.9-2 2.9-.5-1.3-1.5 6.5-.3 3.6 3.5 4.6 1.4 4.6 1.2 2.2 4.1 3.3 2.1-3.8 1.8-5.1 4.6-4.9 .4-5.8-.7-3-2.5 .1-2.2 2.2-1.7-5.1 0-3.1-2-1.7-2.9zM245.6 12.1l4.1-1.3 3.3-.2 5.4-1.1 4.1-2.6 3.4 .4 3 1.9 2.2-3.7 3.6-1.1 5-.8 8.5-.3 1.5 .8 8-1.2 6 .4 6 .5 7.4 .5 6 .9 5.1 1.9-.1 1.8Line truncated
|
||||
},
|
||||
CD: {
|
||||
name: 'Democratic Republic of the Congo',
|
||||
path: 'M581.5 328.5l.5 2.6-.3 1.5 .6 1.6 1.6 1.5 1.5 3.6-1.1-.3-3.7 .4-.8 .4-.8 1.8 .6 1.2-.4 3.3-.4 2.8 .8 .5 1.9 1.1 .8-.5 .2 3.1-2.1 0-1.2-1.6-1-1.2-2.1-.4-.6-1.5-1.7 .9-2.3-.4-.9-1.3-1.8-.2-1.3 .1-.1-.9-1-.1-1.2-.2-1.8 .5-1.2-.1-.7 .3 .2-3.4-.9-1-.2-1.8 .4-1.6-.6-1.1 0-1.8-3.4 .1 .2-1.1-1.4 .1-.1 .4-1.8 .1-.7 1.7-.4 .7-1.5-.4-.9 .4-1.9 .2-1-1.5-.7-.9-.8-1.6-.6-2.1-8.2-.1-1 .4-.8-.1-1.2 .4-.4-.9 .7-.3 .1-1.2 .5-.7 1-.6 .7 .3 1-1.1 1.5 .1 .2 .8 1 .5 1.6-1.8 1.7-1.3 .7-.9-.1-2.3 1.2-2.7 1.2-1.5 1.9-1.3 .3-.9 .1-1 .4-1-.1-1.5 .3-2.5 .6-1.7 .8-1.5 .2-1.7 .2-1.9 1.1-1.5 1.5-.8 2.3 .9 1.7 1 2.1 .3 2 .5 .9-1.6 .3-.3 1.3 .3 3.1-1.4 1.1 .6 .9-.1 .4-.6 1.1-.3 2 .3 1.8 .1 .9-.3 1.7 2.3 1.3 .3 .7-.4 1.3 .1 1.5-.6 .7 1.2 2.4 1.9-.1 3.2 1.1 .4-.9 1-1.1 .7-1 1.5-.6 1.3-.2 2.2-.6 1.1 0 2.1-.8 .7-.1 1.7-.4 .2-.3 1.5 .7 1.3z',
|
||||
},
|
||||
CF: {
|
||||
name: 'Central African Republic',
|
||||
path: 'M576 301.5l-.9 .3-1.8-.1-2-.3-1.1 .3-.4 .6-.9 .1-1.1-.6-3.1 1.4-1.3-.3-.3 .3-.9 1.6-2-.5-2.1-.3-1.7-1-2.3-.9-1.5 .8-1.1 1.5-.2 1.9-1.8-.2-1.9-.4-1.7 1.5-1.4 2.5-.3-.8-.1-1.2-1.3-.9-1-1.5-.3-1-1.3-1.4 .2-.8-.2-1.2 .2-2.2 .6-.5 1.4-2.8 2.3-.2 .6-.7 .4 0 .7 .6 3.5-1 1.2-1.1 1.4-1-.2-1 .7-.2 2.7 .1 2.6-1.3 2-3 1.5-1.2 1.7-.4 .3 1.2 1.6 1.7 0 1.2-.4 1.1 .2 .9 .9 .8 2.1 1.2 1.6 1.2 0 .9 1.9 1.4 1.1 1.2 .7 1.7 2.1 1.1z',
|
||||
},
|
||||
CG: {
|
||||
name: 'Republic of the Congo',
|
||||
path: 'M551.3 306.3l-.2 1.7-.8 1.5-.6 1.7-.3 2.5 .1 1.5-.4 1-.1 1-.3 .9-1.9 1.3-1.2 1.5-1.2 2.7 .1 2.3-.7 .9-1.7 1.3-1.6 1.8-1-.5-.2-.8-1.5-.1-1 1.1-.7-.3-1-.9-.9 .4-1.1 1.2-2.3-2.9 2.1-1.5-1-1.9 .9-.7 1.9-.3 .2-1.2 1.5 1.3 2.5 .1 .8-1.3 .4-1.9-.3-2.1-1.3-1.7 1.2-3.2-.7-.5-2.1 .2-.8-1.4 .2-1.3 3.5 .1 2.3 .8 2.2 .6 .2-1.5 1.4-2.5 1.7-1.5 1.9 .4z',
|
||||
},
|
||||
CH: { name: 'Switzerland', path: 'M526.7 173.1l.1 .6-.5 .9 1.3 .6 1.4 .1-.2 1.5-1.2 .6-2.1-.5-.6 1.4-1.3 .1-.5-.5-1.6 1.2-1.3 .1-1.2-.7-.9-1.5-1.4 .5 .1-1.6 2-2-.1-.8 1.3 .3 .7-.6 2.4 0 .6-.8z' },
|
||||
CI: {
|
||||
name: "Côte d'Ivoire",
|
||||
path: 'M477.7 287.6l.4-.3 .7 .5 2.2 0 .5-.8 .5 0 .8-.3 .4 1.2 .6-.4 1.2-.4 1.2 .6 .5 1 1.3 .6 .9-.7 1.3-.2 1.9 .8 .8 4-1.2 2.3-.7 3.2 1.2 2.4-.1 1.1-1.3 0-1.9-.6-1.8 .1-3.3 .5-1.9 .8-2.8 1-.5-.1 .2-2.3 .3-.3-.1-1.1-1.2-1.2-.9-.2-.8-.8 .6-1.2-.3-1.3 .2-.9 .4 0 .2-1.2-.3-.5 .3-.4 1-.3-.6-2.3-.7-1.1 .2-1z',
|
||||
},
|
||||
CL: {
|
||||
name: 'Chile',
|
||||
path: 'M309.3 477.5l.1 8.5 2.9 0 1.7 .1-.9 1.6-2.4 1.2-1.4-.1-1.6-.4-2-1.1-2.9-.6-3.5-2.1-2.9-2.1-3.8-4.2 2.3 .8 3.9 2.5 3.7 1.4 1.4-1.8 .9-2.6 2.6-1.5zM306.7 365.4l1.4 1.9 .3 2.1 1.5 1.2-.9 2.8 1.5 3.3 1.1 4 2-.4 .3 .7-.9 3.1-3 1.4 0 5-.5 .9 .8 1.2-2 1.8-1.8 2.9-1 2.7 .3 2.9-1.7 3.2 1.2 5.3 .8 .6 0 2.8-1.6 3.1 0 2.7-2.1 2 0 3 .9 3.1-1.7 1.2-.7 2.9-.7 3.4 .5 4-1.1 .7 .6 3.9 1.3 1.2-.9 1.5 1.3 .7 .3 1.2-1.3 .7 .3 2-1 4.6-1.4 3 .3 1.8-.9 2.3-2.1 1.6 .2 3.8 1 1.3 1.8-.2 0 2.7 1.1 2.2 6.7 .5 2.6 .6-2.4-.1-1.4 1-2.5 1.3-.4 3.5-1.2 .1-3.1-1.2-3.2-2.6-3.5-2.2-.9-2.3 .8-2.2-1.4-2.4-.3-6.2 1.2-3.4 2.9-2.7-4.2-1 2.6-3.1 1-5.7 3.1 1.2 1.4-7-1.9-.9-.8 4.2-1.8-.5 .9-4.8 .9-6.1 1.3-2.2-.8-3.2-.2-3.6 1.2-.1 1.7-5.1 1.9-5 1.2-4.7-.7-4.6 .8-2.5-.3-3.7 1.6-3.7 .5-5.8 .9-6.1 .9-6.5-.2-4.8-.6-4 1.4-.8z',
|
||||
},
|
||||
CM: {
|
||||
name: 'Cameroon',
|
||||
path: 'M540.3 280.1l1.1 1.8 .2 1.9-.1 1.9 1.5 2.5-1.6 0-.8 .2-1.2-.3-.6 1.3 1.6 1.7 1.2 .4 .4 1.2 .9 1.9-.5 .8-1.4 2.8-.6 .5-.2 2.2 .2 1.2-.2 .8 1.3 1.4 .3 1 1 1.5 1.3 .9 .1 1.2 .3 .8-.2 1.5-2.2-.6-2.3-.8-3.5-.1-.3-.1-1.7 .3-1.7-.3-1.3 .2-4.5-.1 .4-2.2-1.1-1.8-1.2-.5-.6-1.3-.7-.4 0-.7 .7-2 1.3-2.7 .9 0 1.6-1.6 1.1-.1 1.5 1.2 1.9-1 .3-1.1 .6-1.2 .4-1.4 1.5-1.1 .6-2 .6-.6 .4-1.5 .7-1.8 2.3-2.1 .2-1 .3-.5-1.1-1.1 .1-.9z',
|
||||
},
|
||||
CN: {
|
||||
name: 'China',
|
||||
path: 'M804.1 264.9l-2.3-.9-.1-2.4 1.4-1.3 3-.8 1.6 0 .7 1.1-1.3 1.3-.6 1.7zM722.9 190.9l-.2-1.9 1.9-.9-2.5-5.9 5.5-1.4 1.5-.8 2-6.2 5.5 1.2 1.5-1.6 .1-3.6 2.4-.3 2.1-2.4 1.1-.3 .7 2.5 2.3 1.9 4 1.3 1.9 2.8-1.1 4.1 1 1.5 3.3 .6 3.8 .5 3.3 2.1 1.7 .4 1.3 3.1 1.6 2 3.1-.1 5.7 .8 3.7-.5 2.8 .5 4.1 2.1 3.3 0 1.3 1 3.2-1.8 4.5-1.2 4.2-.1 3.2-1.2 2-1.8 1.9-1.1-.4-1.1-.9-1.3 1.5-2.3 1.5 .4 2.9 .7 2.7-1.9 4.3-1.3 2-2.3 2-1 4-.5 2.2 .4 .3-1.2-2.5-2.5-2.2-1.1-2.2 1.3-2.7-.5-1.6 .4-.7-1.4 2-3.6 1.3-2.7 3.3 1.3 4-2.3-.1-1.6 2.5-3.9 1.6-1.1-.1-2.1-1.5-.9 2.3-1.9 3.5-.6 3.7-.1 4.1 1.1 2.5 1.4 1.7 3.7 1 1.6 1 2.3 1 3.5 4.8 1.2 3.3 2.5 1.2 3.4 4.2 0 2.4-1.4 4.6-1.1-1.5 3.2-1.1 1.3-.9 3.8-1.9 3.4-3.4-.6-2.3 1.2 .7 2.9-.4 4-1.4 .1 0 1.7-1.8-2-1.1 1.9-4.3 1.5 .4 1.7-2.4-.1-1.3-1-1.9 2.3-3.1 1.8-2.2 2.1-3.9 .9-2 1.6-3 .8 1.4-1.5-.5-1.2 2.2-2.2-1.5-1.8-2.4 1.2-3.2 2.3-1.7 2.1-2.7 .2-1.4 1.5 1.4 2.2 2.3 .5 .1 1.4 2.2 1 3.1-2.3 2.5 1.2 1.8 .1 .4 1.7-3.9 .9-1.3 1.7-2.7 1.6-1.4 2.2 3 1.7 1.1 3.1 1.6 2.8 1.9 2.4 0 2.3-1.8 .8 .7 1.6 1.6 1-.4 2.4-.7 2.4-1.5 .3-2.1 3.2-2.2 3.9-2.6 3.6-3.8 2.7-3.9 2.5-3.1 .3-1.7 1.3-1-1-1.5 1.5-3.9 1.5-3 .4-.9 3.1-1.6 .1-.7-2.1 .7-1.1-3.7-.9-1.4 .4-2.8-.7-1.3-1.2 .5-1.7-2.6-.5-1.3-1.1-2.4 1.6-2.7 .3-2.2 0-1.5 .7-1.4 .4 .4 3.3-1.5 0-.2-.7-.1-1.2-2.1 .8-1.2-.5-2-1.1 .8-2.4-1.8-.6-.6-2.7-3 .5 .4-3.5 2.6-2.5 .1-2.4-.1-2.3-1.2-.7-.9-1.8-1.6 .2-3-.4 .9-1.3-1.3-1.9-2 1.3-2.3-.8-3.2 2-2.5 2.2-2.3 .4-1.2-.8-1.5-.1-2-.7-1.5 .8-1.8 2.2-.2-2.4-1.7 .7-3.3-.3-3.1-.7-2.3-1.3-2.1-.6-.9-1.5-1.6-.4-2.8-2-2.2-.9-1.2 .7-3.9-2.1-2.7-2-.8-3.4 2 .4 .1-1.5-1.1-1.6 .3-2.6-3-3.7-4.6-1.2-.8-2.5-2-1.5-.5-.9-.4-1.8 .1-1.3-1.7-.7-.9 .3-.7-3 .7-.7-.3-.8 2.6-1.5 1.9-.7 3 .5 1-2.2 3.6-.3 1-1.4 4.4-1.8z',
|
||||
},
|
||||
CO: {
|
||||
name: 'Colombia',
|
||||
path: 'M314.2 312.6l-.5 .3-.5-1.6-.8-.9-.9 .9-5.4 0 0 1.7 1.6 .3-.1 1.1-.5-.3-1.6 .4 0 2.1 1.2 1 .5 1.6-.1 1.2-1.2 7.6-1.4-1.5-.9-.1 1.8-2.8-2.1-1.3-1.7 .2-1-.4-1.5 .7-2.1-.3-1.6-3-1.3-.7-.9-1.3-1.8-1.3-.8 .3-1.2-.7-1.3-.9-.8 .4-2.4-.4-.6-1.2-.6 .1-2.7-1.6-.4-.9 1-.2-.1-1.4 .6-1 1.4-.2 1.2-1.7 1.1-1.5-1.1-.6 .6-1.6-.7-2.6 .6-.7-.4-2.4-1.1-1.5 .3-1.3 .9 .2 .5-.8-.6-1.7 .3-.4 1.5 .1 2-2 1.2-.3 0-.9 .5-2.4 1.6-1.3 1.8 0 .2-.6 2.2 .2 2.2-1.4 1-.6 1.4-1.4 1 .2 .7 .7-.5 1-1.8 .5-.7 1.4-1.1 .8-.8 1-.4 2-.7 1.6 1.4 .2 .4 1.3 .6 .6 .2 1.2-.3 1 .1 .6 .6 .2 .7 1 3.6-.3 1.6 .4 2 2.4 1.1-.3 2 .1 1.6-.3 .9 .5-.5 1.5-.6 .9-.2 2 .6 1.9 .8 .8 0 .6-1.4 1.4 1 .6 .8 1z',
|
||||
},
|
||||
CR: { name: 'Costa Rica', path: 'M270.7 289.4l-1.1 .2 0 1.2 .6 .4-.4 .3 .1 .5-.2 .6-.2 .5-1.5-.6-.5-.6 .3-.5-.1-.6-.8-.6-1.1-.6-.9-.4-.2-.8-.7-.5 .1 .8-.5 .7-.7-.8-.8-.2-.4-.6 0-.9 .4-.8-.8-.4 .6-.6 .4-.3 1.9 .7 .6-.4 .9 .3 .4 .5 .9 .2 .6-.6 .7 1.6 1.1 1.1z' },
|
||||
CU: { name: 'Cuba', path: 'M271.5 250.5l2.4 .2 2.2 0 2.6 1 1.1 1.1 2.6-.4 1 .7 2.3 1.8 1.7 1.4 .9-.1 1.7 .6-.2 .8 2.1 .1 2 1.2-.3 .7-1.8 .4-1.9 .1-1.9-.2-4 .3 1.9-1.6-1.2-.8-1.7-.2-1-.8-.7-1.7-1.5 .1-2.6-.8-.9-.6-3.6-.4-.9-.6 1-.7-2.7-.2-2 1.6-1.2 0-.4 .7-1.4 .3-1.1-.3 1.4-.9 .6-1 1.3-.7 1.4-.5 2.1-.3z' },
|
||||
CY: { name: 'Cyprus', path: 'M590.9 214.3l.5 .1 .8-.2 .5 0 .2 .2 .1 .3 .1-.1 .4 0 .6-.2 .3 .1 .1 .3-2.9 1.2-1.3-.4-.7-1.2z' },
|
||||
CZ: { name: 'Czech Republic', path: 'M541.7 160.2l1.3 1.2 2.1 .3-.2 1 1.5 .8 .5-1 1.9 .4 .2 1.2 2.1 .2 1.3 1.8-.9 0-.4 .6-.6 .2-.2 .8-.5 .2-.1 .3-1 .4-1.2-.1-.4 .8-1.3-.7-1.3 .2-2.1-1.1-1 .3-1.6 1.5-2-1.2-1.6-1.5-1.4-.9-.3-1.5-.5-1.1 2-.8 1.1-.9 1.9-.7 .7-.7 .8 .4z' },
|
||||
DE: {
|
||||
name: 'Germany',
|
||||
path: 'M539.2 150.3l.7 1.9-.8 1.1 1 1.3 .7 2-.2 1.3 1.1 2.3-1.2 .4-.8-.4-.7 .7-1.9 .7-1.1 .9-2 .8 .5 1.1 .3 1.5 1.4 .9 1.6 1.5-1 1.7-1 .4 .4 2.3-.3 .6-.8-.7-1.4-.1-2 .6-2.4-.1-.4 .9-1.4-1-.8 .2-3-1.1-.6 .8-2.4 0 .4-2.6 1.4-2.4-4-.7-1.3-.9 .1-1.6-.5-.8 .3-2.5-.5-3.8 1.7 0 .7-1.4 .7-3.5-.5-1.2 .5-.8 2.3-.2 .6 .8 1.8-1.9-.6-1.4-.1-2.2 2.1 .5 1.8-.6 0 1.5 2.8 .9 0 1.4 2.8-.8 1.6-1 3.1 1.5z',
|
||||
},
|
||||
DJ: { name: 'Djibouti', path: 'M617.6 281l1.2 .3 .9-.7 .6 .8-.1 1.2-1.5 .7 1.1 .8-1 1.5-.6-.5-.7 .2-1.5-.1-.1-.8-.2-.8 1-1.3z' },
|
||||
DK: { name: 'Denmark', path: 'M527.6 145.6l-1.8 .6-2.1-.5-1.1-2.1-.1-4 .4-1.1 .8-1.2 2.5-.3 1-1.1 2.2-1.1-.1 2.1-.8 1.3 .3 1.1 1.5 .6-.7 1.5-.8-.5-2 2.8zM534.4 141.2l.9 2-1.7 3.1-2.9-2.1-.4-1.7z' },
|
||||
DO: { name: 'Dominican Republic', path: 'M300.8 265.4l.1-.8-.7-.9 .6-.5 .2-1.1-.2-1.5 .3-.5 2.2 0 1.7 .7 .7 0 .5 1 1.5-.1-.1 .9 1.3 .1 1.3 1-1 1.2-1.3-.6-1.3 .1-.9-.1-.5 .5-1.1 .2-.4-.7-.9 .4-1.1 2-.7-.5z' },
|
||||
DZ: {
|
||||
name: 'Algeria',
|
||||
path: 'M475.9 238l0-.6 0-.2 0-3.5 4.5-2.3 2.8-.4 2.2-.8 1.1-1.6 3.2-1.2 .2-2.2 1.6-.3 1.2-1.2 3.7-.5 .5-1.2-.8-.6-.9-3.3-.2-1.9-1-2 2.6-1.8 3-.5 1.8-1.3 2.7-1 4.7-.6 4.6-.2 1.4 .5 2.6-1.3 3 0 1.1 .7 1.9-.2-.6 1.7 .5 3-.7 2.6-1.7 1.7 .2 2.4 2.3 1.8 0 .8 1.8 1.2 1.1 5.5 .9 2.7 .2 1.4-.5 2.5 .2 1.3-.4 1.7 .3 1.9-1.1 1.2 1.6 2.2 .1 1.2 1 1.7 1.3-.6 2.2 1.4 1.2 1.8-9.5 5.6-8 5.7-3.9 1.3-3.1 .3-.1-1.9-1.2-.4-1.8-.9-.6-1.3-9.4-6.4-9.4-6.4z',
|
||||
},
|
||||
EC: { name: 'Ecuador', path: 'M290.6 316.5l.4 2.1-.8 1.8-3.1 2.9-3.3 1.1-1.7 2.4-.5 1.9-1.6 1.1-1.2-1.4-1.1-.3-1.2 .2 0-1 .8-.6-.4-1.2 1.5-2.1-.6-1.2-1 1.3-1.7-1.2 .6-.8-.5-2.5 1-.4 .5-1.8 1-1.8-.2-1.1 1.5-.6 2-1.1 2.7 1.6 .6-.1 .6 1.2 2.4 .4 .8-.4 1.3 .9z' },
|
||||
EE: { name: 'Estonia', path: 'M577.7 127.7l.4 .7-1.9 2.4 .8 3.8-1.2 1.2-2.3 0-2.4-1.5-1.2-.4-2.4 .7 .4-2.4-1.1 .5-1.7-1.4-.3-2.4 3.5-1.1 3.5-.6 3.1 .6z' },
|
||||
EG: {
|
||||
name: 'Egypt',
|
||||
path: 'M602.4 253.9l-11 0-10.8 0-11.2 0 0-10.8 0-10.6-.8-2.5 .7-1.9-.4-1.3 1-1.4 3.7-.1 2.7 .8 2.7 .9 1.3 .5 2.2-1 1.1-.8 2.4-.3 2 .4 .8 1.5 .6-1 2.2 .7 2.2 .2 1.4-.8 1.5 4.5 .3 .8-.8 1.2-.6 2.3-.7 1.5-.7 .6-.9-1-1.3-1.4-1.9-4.3-.3 .3 1.1 3.2 1.7 3 2.1 4.7 1.1 1.6 .9 1.6 2.4 3.3-.5 .5 .1 1.9 3.2 2.6z',
|
||||
},
|
||||
EH: { name: 'Western Sahara', path: 'M475.9 237.2l0 .2 0 .6 0 4.5-9.1-.1 0 7.5-2.6 .3-.6 1.5 .5 4.2-10.9 0-.6 1 .1-1.3 .1 0 6.2-.2 .4-1.1 1.1-1.3 .9-4 3.9-3.2 1.3-3.7 .8-.2 1-2.4 2.3-.3 1 .4 1.3 0 .9-.7 1.7-.1-.1-1.6z' },
|
||||
ER: { name: 'Eritrea', path: 'M601.2 275.7l-.3-1.1 1.2-4.2 .3-1.9 .8-.9 2.1-.5 1.4-1.6 1.6 3.3 .8 2.6 1.5 1.4 3.8 2.7 1.5 1.6 1.5 1.7 .9 .9 1.4 .9-.9 .7-1.2-.3-.9-.9-1.1-1.7-1.3-.9-.7-.9-2.4-1.2-1.9 0-.7-.6-1.6 .7-1.7-1.3-.9 2.1z' },
|
||||
ES: {
|
||||
name: 'Spain',
|
||||
path: 'M479.3 208l-.2-1 1-1.2 .4-.9-1-1 .8-2.1-1.1-1.9 1.2-.3 .1-1.5 .4-.5 .1-2.6 1.3-.9-.8-1.7-1.6-.1-.5 .4-1.7 0-.7-1.6-1.1 .5-1 .8 .1-2.3-1.1-1.5 3.9-2.4 3.4 .6 3.8 0 2.9 .5 2.3-.1 4.5 .1 1.1 1.3 5.1 1.5 1-.7 3.2 1.5 3.2-.4 .1 1.9-2.6 2.2-3.5 .7-.3 1.1-1.7 1.8-1.1 2.7 1.1 1.9-1.6 1.4-.6 2.1-2.1 .6-2 2.5-3.5 0-2.6 0-1.8 1.1-1 1.2-1.4-.3-1-1-.8-1.9z',
|
||||
},
|
||||
ET: {
|
||||
name: 'Ethiopia',
|
||||
path: 'M632.7 293.8l-7.8 8.3-3.6 .2-2.5 1.9-1.8 .1-.7 .8-1.9 0-1.2-.9-2.5 1.2-.8 1.1-1.9-.2-.6-.3-.6 .1-.9-.1-3.5-2.3-2 0-.9-.9 0-1.6-1.4-.5-1.7-3-1.3-.7-.4-1.1-1.5-1.3-1.7-.2 1-1.6 1.5-.1 .4-.8-.1-2.6 .9-2.9 1.3-.8 .3-1.1 1.1-2.2 1.7-1.4 1.2-2.8 .4-2.4 3.2 .6 .9-2.1 1.7 1.3 1.6-.7 .7 .6 1.9 0 2.4 1.2 .7 .9 1.3 .9 1.1 1.7 .9 .9-.9 1.3-1 1.3 .2 .8 .1 .8 1.5 .1 .7-.2 .6 .5-.6 1 1 1.5 1.1 1.4 1 1 9.1 3.3z',
|
||||
},
|
||||
FI: {
|
||||
name: 'Finland',
|
||||
path: 'M579.4 84.9l-.4 3.4 4.3 3.2-2.6 3.5 3.2 5.3-1.8 3.9 2.5 3.3-1.2 2.9 4.1 3-1 2.2-2.6 2.5-5.9 5.4-5.1 .3-4.9 1.5-4.5 .9-1.6-2.3-2.7-1.4 .6-4.1-1.3-3.9 1.3-2.5 2.5-2.8 6.4-4.8 1.9-1-.3-1.9-3.9-2.2-.9-1.7-.1-7.3-4.3-3.2-3.8-2.4 1.7-1.3 3.1 2.6 3.6-.3 3 1.2 2.7-2.2 1.3-3.6 4.3-1.6 3.6 1.9z',
|
||||
},
|
||||
FJ: { name: 'Fiji', path: 'M1000 361l0 1.4-1.8 .7-1.7 .6-.4-1 1.4-.6 .9-.2zM994.8 365.2l.7-.5 .9 .8-.4 1.5-1.7 .4-1.6-.4-.2-1.2 1-1zM.6 360.9l-.4 1.4-.2 .1 0-1.4z' },
|
||||
FK: { name: 'Falkland Islands / Malvinas', path: 'M330 474.6l3.3-2.2 2.4 .9 1.7-1.5 2.2 1.7-.8 1.3-3.8 1.1-1.2-1.3-2.4 1.7z' },
|
||||
FR: {
|
||||
name: 'France',
|
||||
path: 'M356.5 304.5l-1.6 2.5-.9 2.1-1.1 1-1.3 .2-.4-.7-.6-.2-.8 .8-1.3-.6 .8-1.2 .2-1.2 .5-1.2-1.1-1.7-.2-1.9 1.4-2.4 1 .3 2 .7 2.9 2.3zM517.2 166.2l1.3 .9 4 .7-1.4 2.4-.4 2.6-.7 .6-1.3-.3 .1 .8-2 2-.1 1.6 1.4-.5 .9 1.5-.1 1 .8 1.2-1 1.1 .8 2.6 1.5 .5-.3 1.5-2.6 1.9-5.4-1-4.1 1.1-.3 2.1-3.2 .4-3.2-1.5-1 .7-5.1-1.5-1.1-1.3 1.5-2.1 .5-6.8-2.9-3.7-2-1.7-4.3-1.4-.3-2.6 3.6-.8 4.7 .9-.9-4 2.7 1.5 6.4-2.8 .9-3 2.4-.7 .4 1.3 1.3 0 1.3 1.5 1.9 1.7 1.4-.3 2.5 1.7 .6 .3zM524.3 189.9l1.8-1.2 .5 2.8-1 2.6-1.2-.7-.7-2.2z',
|
||||
},
|
||||
GA: { name: 'Gabon', path: 'M531.3 309.8l1.3-.2 1.7 .3 1.7-.3 .3 .1-.2 1.3 .8 1.4 2.1-.2 .7 .5-1.2 3.2 1.3 1.7 .3 2.1-.4 1.9-.8 1.3-2.5-.1-1.5-1.3-.2 1.2-1.9 .3-.9 .7 1 1.9-2.1 1.5-2.8-2.8-1.9-2.3-1.7-2.9 .1-.9 .6-.9 .7-2 .6-2.1 .9-.1 4 0z' },
|
||||
GB: {
|
||||
name: 'United Kingdom',
|
||||
path: 'M482.8 149.9l-2.1-.8-1.7 .1 .5-2.1-.5-2 2.3-.2 3 2.4zM491.4 151.7l.4-2.2-1.8-2.4-.1-.1-3.4-.6-.6-1.1 1-1.7-.9-1.1-1.5 1.9-.2-3.8-1.4-2 1-4.1 2.2-3.3 2.2 .3 3.4-.3-3 4.3 2.8-.5 3.1 0-.8 3.2-2.5 3.6 2.9 .2 .2 .4 2.5 4.6 1.9 .6 1.7 4.4 .8 1.4 3.4 .8-.4 2.4-1.4 1 1.1 2-2.5 1.9-3.7-.1-4.7 1-1.3-.7-1.8 1.7-2.6-.4-2 1.4-1.4-.7 4-3.9 2.5-.8-4.3-.6-.8-1.4 2.9-1.2-1.6-2 .6-2.5z',
|
||||
},
|
||||
GE: { name: 'Georgia', path: 'M611 187.2l.3-.4 2.4 .6 4.1 .6 3.7 1.6 .5 .6 1.7-.5 2.6 .7 .9 1.3 1.7 .8-.7 .5 1.3 1.8-.3 .4-1.5-.2-2.1-1-.7 .5-3.8 .6-2.7-1.7-3 .2 .4-1.4-.7-2.3-1.6-1.3-1.5-.3z' },
|
||||
GH: { name: 'Ghana', path: 'M500.1 285.3l-.2 .9 1.1 1.4 0 2.1 .3 2.2 .7 1-.6 2.5 .2 1.4 .7 1.8 .6 1-4.3 1.6-1.6 .9-2.5 .8-2.4-.7 .1-1.1-1.2-2.4 .7-3.2 1.2-2.3-.8-4-.3-2.1 0-1.6 4.9-.2 1.2 .2 .9-.4z' },
|
||||
GL: {
|
||||
name: 'Greenland',
|
||||
path: 'M370.1 7.1l9.3-4.1 9.8 .3 3.5-2.6 9.8-.7 22.2 .9 17.4 5.5-5.1 2.6-10.7 .3-14.9 .7 1.4 1.2 9.8-.7 8.4 2.3 5.4-2.1 2.3 2.4-3.1 3.9 7.1-2.5 13.5-2.6 8.3 1.3 1.6 2.9-11.3 4.6-1.6 1.5-8.9 1.1 6.4 .3-3.2 4.6-2.2 4 .1 6.7 3.3 3.8-4.4 .3-4.5 1.8 5.1 3.1 .7 4.8-3 .5 3.6 4.7-6.2 .4 3.2 2.2-.9 1.9-3.9 .8-3.9 .1 3.5 3.5 .1 2.4-5.5-2.2-1.5 1.4 3.8 1.3 3.6 3.2 1.1 4.1-5 .9-2.1-1.9-3.5-2.9 1 3.4-3.2 2.7 7.3 .2 3.8 .2-7.4 4.3-7.6 3.9-8.1 1.6-3.1 0-2.8 1.9-3.9 4.9-6 3.3-1.9 .2-3.7 1.1-4 1.1-2.4 2.8 0 3.1-1.4 2.9-4.5 3.5 1.1 3.3-1.3 3.6-1.4 4.1-3.9 .2-4.1-3.4-5.6 0-2.7-2.3-1.8-4.2-4.8-5.4-1.4-2.9-.4-4.1-3.9-4.2 1-3.4-1.8-1.6 2.7-5.6 4.2-1.8 1.1-2 .6-3.9-3.2 1.8-1.5 .7-2.5 .7-3.4-1.6-.2-3.4 1.1-2.6 2.6-.1 5.6 1.3-4.7-3.2-2.5-1.7-2.8 .7-2.3-1.3 3.1-4.8-1.7-2-2.2-3.7-3.3-5.8-3.6-2.1 .1-2.4-7.5-3.3-5.9-.4-7.4 .2-6.8 .5-3.2-1.9-4.8-3.6 7.3-1.8 5.5-.4-11.8-1.5-6.3-2.4 .4-2.4 10.5-2.9 10.2-3 1-2.3-7.5-2.2 2.5-2.6 9.6-4.5 4-.7-1.1-3 6.5-1.8 8.6-1 8.5-.1 3.1 2.1 7.3-3.7 6.7 2.5 3.9 .5 5.7 2.2-6.6-3.6z',
|
||||
},
|
||||
GM: { name: 'The Gambia', path: 'M453.6 278l3 0 .6-.7 .9-.1 1.1 .7 .9 .1 .9-.5 .5 .8-1.2 .6-1.2 0-1.2-.6-1 .6-.5 .1-.7 .4-2.5-.1z' },
|
||||
GN: {
|
||||
name: 'Guinea',
|
||||
path: 'M461.9 280.9l1.4 0 2 .7 .6-.1 .2-.3 1.5 .3 .4-.2 .2 1 .4 0 .7-.3 .5 0 .8 .8 1.2 .2 .7-.6 .9-.4 .7-.4 .5 .1 .7 .6 .3 .8 1.1 1.2-.5 .7-.1 .9 .5-.3 .4 .3-.2 .9 .9 .8-.6 .2-.2 1 .7 1.1 .6 2.3-1 .3-.3 .4 .3 .5-.2 1.2-.4 0-.8 0-.6 1.1-.8 0-.5-.6 .2-1.1-1.2-1.7-.7 .3-.6 0-.8 .2 0-1-.4-.8 .1-.8-.6-1.2-.8-1-2.2 0-.7 .6-.7 0-.5 .6-.3 .8-1.5 1.2-1.2-1.6-1.1-1.1-.7-.4-.7-.5-.3-1.3-.4-.6-.8-.5 1.2-1.3 .8 0 .8-.4 .6 0 .4-.4-.2-1 .3-.2z',
|
||||
},
|
||||
GQ: { name: 'Equatorial Guinea', path: 'M526.8 309.7l4.5 .1 0 3.3-4 0-.9 .1-.6-.4z' },
|
||||
GR: {
|
||||
name: 'Greece',
|
||||
path: 'M573 213.8l-.3 .9-4 .2 0-.5-3.4-.6 .5-1.3 1.6 1 2.1-.1 2.1 .2-.1 .5zM563.8 194.2l2 .1 2.2-.9 2 1.2 2.5-.3 0-1.7 1.4 .9-.9 2.1-.6 .3-1.7 0-1.5-.4-3.3 .9 1.9 1.8-1.4 .6-1.6 0-1.4-1.7-.5 .7 .6 2 1.4 1.5-1.1 .7 1.6 1.5 1.3 .9 .1 1.9-2.6-.9 .8 1.6-1.7 .4 1 2.8-1.8 0-2.3-1.3-1-2.6-.5-2.2-1.1-1.4-1.4-1.9-.2-.9 1.3-1.6 .1-1.1 .9-.4 .1-.9 1.8-.3 1.1-.7 1.5 0 .4-.5z',
|
||||
},
|
||||
GT: { name: 'Guatemala', path: 'M243.8 275.4l.1-.9 .3-.6-.4-.6 1.3-2.3 3.6 0 .1-.9-.5-.2-.3-.6-1-.7-1-1 1.2 0 0-1.6 2.6 0 2.6 .1 0 2.2-.3 3.2 .9 0 .9 .6 .2-.5 .8 .4-1.2 1.1-1.4 .8-.1 .5 .2 .6-.6 .7-.7 .2 .2 .3-.5 .3-1 .7-.1 .4-1.4-.4-1.7-.1-1.3-.6z' },
|
||||
GW: { name: 'Guinea-Bissau', path: 'M453.7 281.5l1.4-.5 1 .1 .7-.3 5.1 .1 0 1-.3 .2 .2 1-.4 .4-.6 0-.8 .4-.8 0-1.2 1.3-1.5-1.1-1.2-.2-.6-.8 0-.4-.8-.6z' },
|
||||
GY: { name: 'Guyana', path: 'M342.9 310.8l-.6 .1-1.6-.3-.9 .8-1.2 .5-.9 .1-.3 .5-1.4-.1-1.7-1.3-.2-1.3-.7-1.4 .4-2.4 .8-1-.6-1.3-1-.4 .4-1.2-.7-.6-1.4 .1-1.9-2.1 .8-.8-.1-1.3 1.7-.4 .7-.6-.9-1 .2-1 2.2-1.7 1.8 1.1 1.7 1.8 .1 1.4 1.1 .1 1.5 1.4 1.1 .9-.5 2.5-1.7 .8 .2 .6-.5 1.5 1.2 2 .9 0 .3 1.5z' },
|
||||
HN: {
|
||||
name: 'Honduras',
|
||||
path: 'M269 274.1l-.9-.1-.4 .4-1 .4-.7 0-.6 .3-.5-.1-.5-.4-.3 .1-.4 .6-.2 0-.1 .6-.9 .8-.6 .3-.2 .4-.9-.6-.6 .7-.5 0-.7 .1 .1 1.4-.4 0-.4 .7-.8 .1-.5-.9-.9-.3 .2-1.1-.4-.3-.5-.2-1.2 .3-.1-.3-.9-.5-.6-.6-.8-.2 .6-.7-.2-.6 .1-.5 1.4-.8 1.2-1.1 .3 .1 .6-.5 .8 0 .3 .2 .4-.1 1.3 .2 1.3-.1 .9-.3 .3-.3 .9 .2 .7 .1 .7 0 .5-.3 1.3 .4 .4 .1 .9 .5 .8 .7 1 .4z',
|
||||
},
|
||||
HR: { name: 'Croatia', path: 'M546 176.7l.9 .4 2.1 1.5 2.3 .7 1-.5 .7 1.3 .9 1-1.1 1.3-1.3-.8-1.9 .1-2.4-.6-1.3 .1-.6 .7-1-.8-.5 1.4 1.3 1.6 .6 1.1 1.3 1.2 1 .8 1.1 1.4 2.5 1.3-.3 .5-2.7-1.2-1.6-1.2-2.5-1-2.3-2.5 .5-.3-1.3-1.4 0-1.2-1.8-.5-.8 1.5-.9-1.2 .1-1.2 .1 0 1.9 .1 .5-.6 1 .6 1.1 0 0-.9 .9-.4 .3-1.4z' },
|
||||
HT: { name: 'Haiti', path: 'M300.8 260.6l.2 1.5-.2 1.1-.6 .5 .7 .9-.1 .8-1.8-.5-1.3 .2-1.7-.2-1.3 .5-1.5-.9 .2-.9 2.6 .4 2.1 .2 1-.6-1.3-1.3 0-1.1-1.7-.4 .6-.8 1.7 .1z' },
|
||||
HU: { name: 'Hungary', path: 'M561.3 169.9l1.6 1 .2 .9-1.7 .8-1.3 2.4-1.7 2.3-2.2 .7-1.8-.2-2.1 1-1 .5-2.3-.7-2.1-1.5-.9-.4-.5-1.2-.5 0 .9-2.3-.5-.8 1.6 0 .2-1.4 1.4 .9 1 .4 2.3-.4 .3-.8 1.1-.1 1.3-.5 .3 .2 1.3-.4 .7-.9 .9-.2 3 1.1z' },
|
||||
ID: {
|
||||
name: 'Indonesia',
|
||||
path: 'M891.7 323.3l0 9 .1 9.1-2.5-2.3-2.8-.5-.7 .8-3.5 .1 1.1-2.3 1.8-.8-.7-3-1.4-2.4-5.4-2.3-2.2-.3-4.2-2.5-.8 1.3-1.1 .3-.6-1.1 0-1.2-2.2-1.3 3-1 2 0-.2-.7-4.1 0-1.1-1.7-2.5-.5-1.1-1.4 3.7-.6 1.4-.9 4.5 1.1 .4 1 .8 4.5 2.9 1.7 2.3-3 3.2-1.6 2.4 0 2.4 .9 2.1 1zM847.1 340.8l.3 .6 .1 .8-1.8 2.1-2.4 .6-.4-.3 .3-1 1.2-1.7zM872.8 335.2l-.3-2.1 .5-1 .6-.9 .6 .8 0 1.3zM827.5 304.5l-1.6 2.6 2 2.6-.5 1.3 3.1 2.5-3.2 .4-1 1.9 .1 2.5-2.6 1.9-.1 2.7-1.1 4.3-.4-1-3.1 1.3-1.1-1.7-2-.2-1.4-.9-3.3 1-1-1.3-1.8 .1-2.3-.3-.4-3.7-1.4-.8-1.4-2.4-.4-2.4 .4-2.6 1.6-1.8 .5 1.8 1.9 1.6 1.8-.6 1.7 .2 1.7-1.4 1.3-.2 2.6 .8 2.3-.6 1.4-3.9 1.1-1 .9-3.1 3.2 0zM859.4 323.8l3 .8 1 2.2-2.3-1.2-2.3-.2-1.6 .2-1.9-.1 .6-1.6zM852.4 326.6l-1.9-.5-.5-1.2 2.8-.2 .7 1zM855.4 310l.2 1.5 1.6 .3 .3 1.1-.2 2.4-1.4-.3-.4 1.7 1.1 1.5-.8 .3-1.1-1.7-.8-3.6 .5-2.2zM841.5 313.6l3.2-.1 2.7-2 .5 .6-2.2 2.7-2.1 .6-2.7-.6-4.6 .2-2.5 .4-.4 2.1 2.5 2.5 1.5-1.3 5.2-1-.2 1.3-1.2-.4-1.2 1.7-2.5 1 2.7 3.6-.6 .9 2.5 3.3 0 1.8-1.5 .8-1.1-1 1.4-2.3-2.7 1.1-.7-.7 .3-1.1-2-1.7 .2-2.7-1.8 .9 .2 3.2 .1 4-1.7 .4-1.2-.8 .8-2.6-.5-2.7-1.1 0-.9-1.9 1.2-1.8 .4-2.2 1.3-4.2 .6-1.1 2.4-2.1 2.2 .8zM834.2 344.6l-3.7-1.9 2.6-.6 1.4 .9 1 .8-.2 .8zM837.1 339.8l1.8-.2 2.5-1-.4 1.5-4.2 .8-3.7-.3 0-1 2.2-.6zM828.5 339.3l1.7-.2 .7 1.2-3.2 .5-1.9 .4-1.5 0 .9-1.6 1.6 0 .7-1zM801.4 333.9l.3 1 5.4 .3 .6-1.2 5.1 1.4 1 1.8 4.2 .5 3.4 1.6-3.2 1.1-3-1.1-2.5 .1-2.9-.2-2.6-.6-3.2-1-2.1-.3-1.1 .4-5.1-1.2-.5-1.2-2.5-.2 1.9-2.7 3.4 .2 2.2 1.1zM789.9 319.1l.5 1.9 1 1.5 2 .3 1.3 1.7-.7 3.5-.1 4.3-3 .1-2.4-2.4-3.5-2.2-1.2-1.7-2.1-2.3-1.4-2.1-2.1-3.9-2.5-2.3-.8-2.4-1-2.1-2.5-1.8-1.5-2.4-2.1-1.5-2.9-3.1-.2-1.4 1.8 .1 4.3 .6 2.4 2.7 2.2 1.9 1.5 1.1 2.7 3 2.8 0 2.3 2 1.6 2.3 2.1 1.2-1.1 2.3 1.6 1z',
|
||||
},
|
||||
IE: { name: 'Ireland', path: 'M482.8 149.9l.4 2.7-2.1 3.4-4.9 2.1-3.9-.5 2.2-3.9-1.4-3.8 3.8-3 2.1-1.8 .5 2-.5 2.1 1.7-.1z' },
|
||||
IL: { name: 'Israel', path: 'M599.2 221.8l-.5 1-1-.4-.5 2 .6 .4-.7 .4-.1 .8 1.3-.4 .1 1.2-1.4 4.9-.3-.8-1.5-4.5 .8-1-.2-.2 .7-1.4 .6-2.3 .4-.8 .1 0 .9 0 .3-.6 .7 0 0 1.3z' },
|
||||
IN: {
|
||||
name: 'India',
|
||||
path: 'M770.4 235.4l.2 1.2-1 .5 .2 1.8-2-.5-3.6 2.1 .1 1.7-1.5 2.5-.2 1.4-1.2 2.4-2.2-.6-.1 3-.6 1 .3 1.2-1.4 .7-1.4-4.6-.8 0-.5 1.9-1.5-1.6 .9-1.6 1.2-.2 1.3-2.5-1.6-.5-2.6 0-2.6-.4-.3-2-1.3-.2-2.2-1.3-1 2.1 2 1.5-1.7 1.1-.6 1.1 1.7 .8-.5 1.8 1 2.2 .4 2.4-.4 1-1.9 0-3.4 .6 .2 2.2-1.5 1.7-4 2-3.1 3.3-2.1 1.8-2.8 1.9 0 1.3-1.4 .7-2.5 1.1-1.3 .1-.8 2.2 .6 3.7 .1 2.3-1.2 2.7 0 4.8-1.4 .1-1.3 2.1 .9 1-2.6 .8-.9 1.9-1.1 .8-2.6-2.6-1.3-4-1.1-2.8-1-1.3-1.4-2.7-.7-3.6-.5-1.7-2.5-4-1.2-5.5-.8-3.7 0-3.5-.5-2.7-4.1 1.8-1.9-.4-3.7-3.5 1.4-1.1-.9-1.1-3.2-2.5 1.8-2 6.1 0-.5-2.5-1.6-1.5-.3-2.3-1.8-1.3 3.1-3.2 3.2 .3 2.9-3.2 1.7-3.1 2.7-3 0-2.2 2.4-1.8-2.3-1.5-1-2.1-.9-2.8 1.3-1.3 4.2 .8 3.1-.5 2.7-2.7 3 3.7-.3 2.6 1.1 1.6-.1 1.5-2-.4 .8 3.4 2.7 2 3.9 2.1-1.8 1.4-1 2.8 2.7 1.1 2.6 1.5 3.6 1.7 3.8 .4 1.6 1.5 2.2 .3 3.3 .7 2.3-.1 .3-1.1-.3-1.9 .2-1.3 1.7-.7 .2 2.4 .1 .6 2.5 1.1 1.7-.4 2.4 .2 2.2-.1 .2-1.9-1.1-.9 2.3-.4 2.5-2.2 3.2-2 2.3 .8 2-1.3 1.3 1.9-.9 1.3z',
|
||||
},
|
||||
IQ: { name: 'Iraq', path: 'M608.9 223.5l-1.1-3.7 6.1-3.3 1.1-3.8-.3-2.3 1.5-.8 1.4-2 1.2-.5 3.3 .4 .9 .9 1.4-.6 1.8 3.8 1.8 1 .2 1.8-1.4 1.1-.6 2.4 1.9 3 3.4 1.7 1.4 2.3-.4 2.3 .8 0 .1 1.6 1.5 1.6-1.6-.2-1.9-.2-2 2.9-5.2-.3-7.8-6.1-4.2-2.1z' },
|
||||
IR: {
|
||||
name: 'Iran',
|
||||
path: 'M634.9 230.4l-1.5-1.6-.1-1.6-.8 0 .4-2.3-1.4-2.3-3.4-1.7-1.9-3 .6-2.4 1.4-1.1-.2-1.8-1.8-1-1.8-3.8-1.6-2.6 .6-1-.9-3.7 1.9-.9 .5 1.2 1.4 1.5 1.9 .5 1-.1 3.3-2.4 1-.3 .8 1-.9 1.6 1.7 1.7 .7-.2 .9 2.4 2.6 .7 1.9 1.6 4 .5 4.3-.8 .3-.8 2.4-.6 2-1.8 1.9 .1 1.2-.6 2 .3 3 1.6 2.2 .3 3.2 2.9 2.1 .1 .2 2.6-1.1 4-.8 2.2 1.2 .5-1.1 1.7 .9 2.5 .2 1.9 2.1 .5 .2 2-2.5 2.8 1.4 1.6 1.1 1.8 2.6 1.3 .1 2.7 1.3 .4 .3 1.4-4 1.6-1.1 3.4-5.2-.9-3-.7-3.2-.4-1.1-3.6-1.4-.5-2.1 .5-2.8 1.4-3.4-.9-2.8-2.3-2.7-.9-1.8-2.9-2.1-4-1.5 .5-1.8-1z',
|
||||
},
|
||||
IS: { name: 'Iceland', path: 'M459.7 97.3l-.6 3 3.1 3.1-3.6 3.4-8 3-2.4 .8-3.7-.6-7.7-1.4 2.7-2-6-2.2 4.9-.9-.1-1.3-5.9-1 1.9-3 4.2-.7 4.3 3.1 4.3-2.5 3.5 1.3 4.5-2.5z' },
|
||||
IT: {
|
||||
name: 'Italy',
|
||||
path: 'M529 175.3l1.7 .5 .3-.6 2.8-.6 .6 1.2 4 .9-.3 1.7 .6 1.5-2.2-.5-2.3 1.2 .2 1.7-.3 1 .9 1.7 2.6 1.7 1.4 2.8 3.1 2.7 2.1 0 .7 .7-.8 .7 2.5 1.2 2.1 1 2.3 1.7 .3 .6-.5 1.2-1.5-1.6-2.4-.5-1.2 2.1 2 1.2-.3 1.7-1.2 .2-1.5 2.8-1.1 .2 0-.9 .5-1.8 .6-.7-1-1.9-.9-1.6-1.1-.4-.9-1.4-1.7-.6-1.2-1.4-2.1-.2-2.2-1.5-2.5-2.1-1.9-2-.9-3.3-1.3-.4-2.3-1.1-1.3 .4-1.6 1.6-1.1 .3 .3-1.5-1.5-.5-.8-2.6 1-1.1-.8-1.2 .1-1 1.2 .7 1.3-.1 1.6-1.2 .5 .5 1.3-.1 .6-1.4 2.1 .5 1.2-.6zM541 204.7l2.1-.3-1 2.5 .4 1-.6 1.7-2.1-1.2-1.4-.4-3.9-1.6 .4-1.7 3.3 .3zM524.2 195.7l1.4-1 1.6 2.3-.3 4.3-1.3-.2-1.1 1.1-1.1-.8-.1-4-.6-1.9z',
|
||||
},
|
||||
JM: { name: 'Jamaica', path: 'M284.5 264.1l1.9 .3 1.5 .6 .4 .8-1.9 .1-.9 .5-1.5-.5-1.6-1 .3-.7 1.2-.2z' },
|
||||
JO: { name: 'Jordan', path: 'M598.7 222.8l.5-1 3.1 1.3 5.5-3.3 1.1 3.7-.6 .5-5.5 1.5 2.8 3.1-1 .5-.4 1-2.1 .5-.7 1.1-1.2 .9-3.1-.5-.1-.4 1.4-4.9-.1-1.2 .4-.9z' },
|
||||
JP: {
|
||||
name: 'Japan',
|
||||
path: 'M894.1 201.3l-2.5 3.3 0 3.3-1 2.5 .4 1.6-1.4 2.3-3.6 1.4-4.8 .2-4 3.6-1.9-1.2-.1-2.3-4.8 .7-3.3 1.4-3.2 .1 2.8 2.3-1.9 5.2-1.8 1.3-1.3-1.2 .7-2.7-1.8-.9-1.1-2.2 2.6-.9 1.5-2 2.7-1.6 2.1-2.2 5.5-.9 3 .6 2.9-5.6 1.8 1.5 4.1-3.2 1.6-1.2 1.7-4-.4-3.7 1.1-2.1 3-.6 1.5 4.6zM901.7 185.4l2-1.4 .6 3.8-4.1 .9-2.5 3.4-4.3-2.3-1.5 3.6-3.1 .1-.4-3.3 1.4-2.6 2.9-.2 .8-4.7 .9-2.7 3.2 3.6 2.2 1.1zM867.7 219.5l1.5-1.9 1.6 .4 1.2-1.3 2 .7 .4 1-1.6 1.9-1.2-1-1.4 .7-.7 1.9-1.8-.9z',
|
||||
},
|
||||
KE: { name: 'Kenya', path: 'M608.9 329l-4-2.7-.2-1.7-10.1-5.6-.4-.3-.1-3 .8-1.1 1.4-1.8 1-2.1-1.2-3.1-.3-1.4-1.3-2 1.7-1.6 1.9-1.9 1.4 .5 0 1.6 .9 .9 2 0 3.5 2.3 .9 .1 .6-.1 .6 .3 1.9 .2 .8-1.1 2.5-1.2 1.2 .9 1.9 0-2.5 3.2 .1 10.1 1.6 2.3-1.9 1.1-.7 1.2-1.1 .2-.4 1.9-.8 1.2-.6 1.8z' },
|
||||
KG: { name: 'Kyrgyzstan', path: 'M697.1 191.2l.6-1.5 1.9-.5 4.5 1.2 .5-2 1.5-.7 4 1.4 1-.4 4.6 .1 4.1 .4 1.4 1.2 1.7 .5-.3 .7-4.4 1.8-1 1.4-3.6 .3-1 2.2-3-.5-1.9 .7-2.6 1.5 .3 .8-.7 .7-5.3 .5-3.4-1.1-3 .3 .2-1.9 3 .6 1.1-1 2.1 .3 3.5-2.4-3.3-1.7-1.9 .8-2.1-1.3 2.3-2.1z' },
|
||||
KH: { name: 'Cambodia', path: 'M785 282l-.7-3.4 1.8-2.3 3.6-.6 2.6 .4 2.3 1.1 1.2-1.9 2.5 1 .6 1.9-.3 3.4-4.7 2.2 1.2 1.7-2.9 .2-2.4 1.1-2.3-.4-1.1-1.5z' },
|
||||
KP: {
|
||||
name: 'Dem. Rep. Korea',
|
||||
path: 'M862.9 190.7l.4 .6-1.1-.2-1.2 1.1-.8 1.2 .1 2.4-1.4 .7-.5 .6-1.1 .9-1.8 .6-1.2 .9-.1 1.4-.4 .3 1.2 .6 1.5 1.4-.4 .8-1.2 .2-1.9 .1-1.1 1.5-1.2-.1-.2 .3-1.4-.7-.3 .6-.8 .3-.1-.6-.7-.3-.8-.5 .8-1.4 .6-.4-.2-.6 .7-1.7-.2-.6-1.6-.3-1.3-.9 2.2-2.1 3.1-1.8 1.9-2.3 1.3 1 2.4 .1-.4-1.7 4.3-1.5 1.1-1.9z',
|
||||
},
|
||||
KR: { name: 'Republic of Korea', path: 'M850.5 206l.2-.3 1.2 .1 1.1-1.5 1.9-.1 1.2-.2 .4-.8 2.4 3.8 .7 2 0 3.7-1 1.7-2.5 .6-2.2 1.3-2.6 .3-.3-1.7 .6-2.4-1.3-3.3 2.1-.5z' },
|
||||
KW: { name: 'Kuwait', path: 'M633.3 230.2l.5 1.4-.2 .7 .9 2.2-2 .1-.7-1.4-2.4-.3 2-2.9z' },
|
||||
KZ: {
|
||||
name: 'Kazakhstan',
|
||||
path: 'M742.7 167.1l-2.1 2.4-2.4 .3-.1 3.6-1.5 1.6-5.5-1.2-2 6.2-1.5 .8-5.5 1.4 2.5 5.9-1.9 .9 .2 1.9-1.7-.5-1.4-1.2-4.1-.4-4.6-.1-1 .4-4-1.4-1.5 .7-.5 2-4.5-1.2-1.9 .5-.6 1.5-1.6 .6-3.6 2.3-1.3 2.4-1 0-.8-1.6-3.5-.1-.5-2.7-1.4 0 .2-3.4-3.3-2.5-4.8 .3-3.2 .5-2.7-3.1-2.3-1.3-4.3-2.4-.5-.3-7.1 2 .1 12.4-1.5 .2-1.9-2.6-1.9-.9-3.1 .7-1.3 1.1-.1-.8 .7-1.4-.6-1.2-3.2-1.2-1.2-3-1.6-.9-.1-1.1 2.7 .4 .1-2.6 2.4-.5 2.4 .5 .5-3.4-.5-2.1-2.7 .1-2.4-.8-3.2 1.5-2.6 .8-1.4-.6 .3-1.8-1.8-2.4-2.1 .1-2.3-2.4 1.6-2.7-.8-.7 2.2-4 2.8 2.1 .4-2.6 5.7-4 4.4-.1 6.1 2.5 3.3 1.5 2.9-1.5 4.4-.1 3.6 1.9 .8-1.1 3.9 .2 .7-1.8-4.5-2.5 2.6-1.8-.5-1.1 2.7-.9-2-2.6 1.3-1.3 10.4-1.4 1.3-.9 7-1.4 2.5-1.6 4.9 .8 .9 4 2.9-.9 3.6 1.3-.2 2 2.6-.2 7-3.6-1 1.2 3.5 3 6.2 9.4 1.5-1.9 3.8 2.1 4-.9 1.6 .6 1.3 2.1 1.9 .7 1.2 1.6 3.6-.5z',
|
||||
},
|
||||
LA: { name: 'Lao PDR', path: 'M798.3 276.3l-2.5-1-1.2 1.9-2.3-1.1 .9-1.3 .1-2.4-2.2-2.4-.2-2.9-2.1-2.3-2.1-.2-.6 1-1.6 .1-.9-.5-2.9 1.7 0-2.6 .6-3-1.8-.1-.2-1.8-1.2-.9 .6-1 2.4-1.9 .2 .7 1.5 0-.4-3.3 1.4-.4 1.6 2.3 1.3 2.6 3.4 .1 1.1 2.5-1.8 .7-.8 1.1 3.3 1.7 2.3 3.4 1.8 2.5 2.1 2 .7 2z' },
|
||||
LB: { name: 'Lebanon', path: 'M599.5 220.1l-.7 0-.3 .6-.9 0 1-2.6 1.3-2.2 .1-.1 1.2 .2 .5 1.2-1.5 1.2z' },
|
||||
LK: { name: 'Sri Lanka', path: 'M727.2 295.1l-.4 2.9-1.2 .8-2.4 .6-1.3-2.2-.5-4 1.2-4.5 2 1.5 1.2 2z' },
|
||||
LR: { name: 'Liberia', path: 'M476.6 294.6l-.2 .9 .3 1.3-.6 1.2 .8 .8 .9 .2 1.2 1.2 .1 1.1-.3 .3-.2 2.3-.8 0-2.8-1.3-2.5-2.1-2.4-1.5-1.9-1.8 .7-.9 .1-.8 1.3-1.6 1.3-1.3 .6 0 .7-.3 1.2 1.7-.2 1.1 .5 .6 .8 0 .6-1.1z' },
|
||||
LS: { name: 'Lesotho', path: 'M580.5 398.8l1 .9-.9 1.4-.5 1-1.5 .5-.5 1-1 .3-2.1-2.4 1.5-1.9 1.5-1.2 1.3-.6z' },
|
||||
LT: { name: 'Lithuania', path: 'M573.6 143.2l.3 1.7-2.3 1.3-.7 2.1-3 1.5-2.7-.1-.6-1.1-1.5-.5-.2-.9 .3-1.1-1.2-.6-2.9-.7-.6-3.2 3.2-1.3 4.6 .3 2.8-.4 .3 .8 1.5 .3z' },
|
||||
LU: { name: 'Luxembourg', path: 'M516.8 163.8l.5 .8-.1 1.6-.8 .1-.6-.3 .3-2.1z' },
|
||||
LV: { name: 'Latvia', path: 'M575.8 135.8l1.3 1 .3 1.9 .9 2.3-3 1.5-1.7 .7-2.7-1.9-1.5-.3-.3-.8-2.8 .4-4.6-.3-3.2 1.3 .1-3 1.3-2.5 2.7-1.4 2.2 3 2.2-.1 .5-3 2.4-.7 1.2 .4 2.4 1.5z' },
|
||||
LY: {
|
||||
name: 'Libya',
|
||||
path: 'M569.4 253.9l0 5.8-3.1 0-.1 1.3-11.1-5.6-11-5.6-2.8 1.6-2 1.1-1.6-1.6-4.4-1.3-1.2-1.8-2.2-1.4-1.3 .6-1-1.7-.1-1.2-1.6-2.2 1.1-1.2-.3-1.9 .4-1.7-.2-1.3 .5-2.5-.2-1.4-.9-2.7 1.4-.7 .2-1.3-.3-1.2 1.9-1.2 .9-1 1.4-.9 .1-2.4 3.3 1.1 1.1-.3 2.4 .5 3.6 1.4 1.3 2.8 2.5 .5 4 1.3 2.9 1.5 1.4-.7 1.3-1.5-.6-2.3 .8-1.5 2-1.4 1.9-.5 3.8 .7 .9 1.3 1.1 .1 .9 .5 2.7 .3 .7 1.1-1 1.4 .4 1.3-.7 1.9 .8 2.5 0 10.6z',
|
||||
},
|
||||
MA: {
|
||||
name: 'Morocco',
|
||||
path: 'M494 214.2l1 2 .2 1.9 .9 3.3 .8 .6-.5 1.2-3.7 .5-1.2 1.2-1.6 .3-.2 2.2-3.2 1.2-1.1 1.6-2.2 .8-2.8 .4-4.5 2.3 0 3.5-.4 0 .1 1.6-1.7 .1-.9 .7-1.3 0-1-.4-2.3 .3-1 2.4-.8 .2-1.3 3.7-3.9 3.2-.9 4-1.1 1.3-.4 1.1-6.2 .2-.1 0 .2-1.3 1-.8 .9-1.5-.2-1 1-2.1 1.5-1.9 1-.4 .7-1.8 .1-1.5 1-1.9 1.8-1.1 1.8-3 .1-.1 1.3-1.1 2.6-.3 2.2-2.1 1.4-.8 2.3-2.5-.7-3.8 1.1-2.7 .4-1.6 1.8-2.1 2.7-1.4 2.1-1.3 1.9-3.3 .8-1.9 2.1 0 1.6 1.4 2.7-.3 2.9 .7z',
|
||||
},
|
||||
MD: { name: 'Moldova', path: 'M573.9 170.6l.7-.5 1.9-.3 2 1.1 1.1 .1 1.3 1-.2 1.2 1 .5 .4 1.5 1 .9-.2 .5 .5 .4-.7 .2-1.7-.1-.2-.5-.6 .3 .2 .6-.8 1.2-.5 1.1-.7 .4-.5-1.6 .3-1.4-.1-1.6-1.6-2.1-.9-1.5-.8-1z' },
|
||||
ME: { name: 'Montenegro', path: 'M555.8 190.1l-.8 .3-.2-.7-1.2 1.7 .2 1.1-.6-.3-.7-1.1-1.2-.7 .3-.5 .4-1.9 .9-.8 .5-.3 .7 .6 .4 .5 .9 .3 1.1 .7-.2 .3z' },
|
||||
MG: {
|
||||
name: 'Madagascar',
|
||||
path: 'M637.6 350.9l.8 1.2 .6 1.8 .5 3.4 .7 1.4-.3 1.3-.5 .9-.9-1.7-.5 .8 .5 2.1-.2 1.3-.8 .6-.2 2.4-1.1 3.4-1.3 4-1.8 5.5-1 4-1.3 3.5-2.2 .7-2.5 1.2-1.6-.7-2.2-1.1-.7-1.6-.2-2.6-1-2.3-.2-2.1 .4-2.1 1.3-.5 0-1 1.4-2.2 .2-1.8-.6-1.4-.6-1.8-.2-2.6 1-1.6 .4-1.8 1.3-.1 1.6-.6 1-.5 1.2-.1 1.6-1.6 2.3-1.7 .8-1.5-.3-1.2 1.1 .4 1.6-2 0-1.7 1-1.3z',
|
||||
},
|
||||
MK: { name: 'North Macedonia', path: 'M562.2 191l1.4 1 .2 2.2-.6 .2-.4 .5-1.5 0-1.1 .7-1.8 .3-1.2-.8-.4-1.4 .4-1.2 .3 .1 .2-.7 1.6-.5 .6-.2 1-.2z' },
|
||||
ML: {
|
||||
name: 'Mali',
|
||||
path: 'M468 281.3l.1-.9-.2-1.1-1-.8-.6-1.6-.1-1.7 .9-.6 .5-1.6 .9-.1 1.9 .8 1.6-.6 1.1 .2 .4-.6 11.1-.1 .6-2-.4-.3-1.4-12.4-1.3-12.6 4.2-.1 9.4 6.4 9.4 6.4 .6 1.3 1.8 .9 1.2 .4 .1 1.9 3.1-.3 0 6.6-1.6 1.9-.2 1.7-2.5 .5-3.8 .2-1 1.1-1.8 .1-1.7 0-.7-.6-1.6 .4-2.6 1.2-.5 .9-2.1 1.3-.4 .7-1.2 .6-1.3-.4-.8 .7-.4 1.9-2.2 2.4 .1 .9-.8 1.2 .2 1.6-1.2 .4-.6 .4-.4-1.2-.8 .3-.5 0-.5 .8-2.2 0-.7-.5-.4 .3-.9-.8 .2-.9-.4-.3-.5 .3 .1-.9 .5-.7-1.1-1.2-.3-.8-.7-.6-.5-.1-.7 .4-.9 .4-.7 .6-1.2-.2-.8-.8-.5 0-.7 .3-.4 0z',
|
||||
},
|
||||
MM: {
|
||||
name: 'Myanmar',
|
||||
path: 'M778.1 258.5l-1.6 .7-1.6 1.3-2 .1-1.2 3.1-1.2 .5 1.3 2.5 1.8 2.1 1.1 1.9-1 2.5-.9 .5 .6 1.4 1.9 2.3 .3 1.6-.1 1.3 1.1 2.6-1.5 2.6-1.3 2.9-.3-2.1 .8-2.2-.9-1.6 .2-3.1-1.1-1.5-.9-3.4-.5-3.6-1.2-2.3-1.8 1.4-3.2 2-1.5-.2-1.8-.7 1-3.5-.6-2.7-2.2-3.3 .4-1.1-1.6-.3-2-2.4-.2-2.3 1 .4 0-2.1 1.4-.7-.3-1.2 .6-1 .1-3 2.2 .6 1.2-2.4 .2-1.4 1.5-2.5-.1-1.7 3.6-2.1 2 .5-.2-1.8 1-.5-.2-1.2 1.6-.2 .9 1.8 1.2 .7 .1 2.3-.1 2.4-2.6 2.5-.4 3.5 3-.5 .6 2.7 1.8 .6-.8 2.4 2 1.1 1.2 .5 2.1-.8 .1 1.2-2.4 1.9z',
|
||||
},
|
||||
MN: {
|
||||
name: 'Mongolia',
|
||||
path: 'M743.8 166.8l2.9-.6 5.3-3.1 4.2-1.8 2.4 1.2 2.9 0 1.9 1.7 2.8 .1 4 1 2.7-2.6-1.2-2.1 2.9-3.9 3.1 1.6 2.5 .4 3.3 1 .5 2.7 4 1.5 2.6-.6 3.5-.5 2.8 .5 2.7 1.7 1.7 1.9 2.6-.1 3.5 .6 2.5-.9 3.7-.6 4.1-2.5 1.6 .4 1.5 1.2 3.3-.3-1.3 2.7-2 3.6 .7 1.4 1.6-.4 2.7 .5 2.2-1.3 2.2 1.1 2.5 2.5-.3 1.2-2.2-.4-4 .5-2 1-2 2.3-4.3 1.3-2.7 1.9-2.9-.7-1.5-.4-1.5 2.3 .9 1.3 .4 1.1-1.9 1.1-2 1.8-3.2 1.2-4.2 .1-4.5 1.2-3.2 1.8-1.3-1-3.3 0-4.1-2.1-2.8-.5-3.7 .5-5.7-.8-3.1 .1-1.6-2-1.3-3.1-1.7-.4-3.3-2.1-3.8-.5-3.3-.6-1-1.5 1.1-4.1-1.9-2.8-4-1.3-2.3-1.9z',
|
||||
},
|
||||
MR: { name: 'Mauritania', path: 'M452.6 256.9l.6-1 10.9 0-.5-4.2 .6-1.5 2.6-.3 0-7.5 9.1 .1 0-4.5 10.4 7.2-4.2 .1 1.3 12.6 1.4 12.4 .4 .3-.6 2-11.1 .1-.4 .6-1.1-.2-1.6 .6-1.9-.8-.9 .1-.5 1.6-.9 .6-1.8-2-1.7-2.1-1.9-.7-1.3-.9-1.5 0-1.4 .7-1.4-.3-.9 .9-.3-1.5 .8-1.4 .3-2.7-.3-2.8-.3-1.5 .3-1.4-.7-1.4z' },
|
||||
MW: { name: 'Malawi', path: 'M591 341.8l2.7 .5 .6 .7 .9 1.4 .8 3.8-.8 2.1 .8 3.7 1-.1 1 1 1.1 2 .3 3.7-1.2 .6-.9 1.9-1.8-1.7-.2-2 .6-1.3-.2-1.2-1.1-.7-.7 .3-1.6-1.4-1.5-.7 .8-2.7 .9-.9-.5-2.4 .5-2.3 .5-.7-.7-2.4z' },
|
||||
MX: {
|
||||
name: 'Mexico',
|
||||
path: 'M174.6 222.4l3.2-.3 3.5-.3-.2 .6 4.2 1.5 6.3 2.2 5.5 0 2.2 0 0-1.3 4.8 0 1.1 1.1 1.4 .9 1.6 1.4 1 1.6 .6 1.7 1.5 .9 2.3 .9 1.7-2.4 2.3-.1 2 1.2 1.4 2.1 .9 1.8 1.7 1.7 .6 2.1 .7 1.4 2.2 .9 2 .7 1.1-.1-1.1 2.6-.5 2.1-.2 3.9-.3 1.4 .5 1.6 .9 1.5 .5 2.2 1.9 2.2 .6 1.6 1.1 1.4 3 .8 1.1 1.2 2.4-.8 2.2-.3 2-.5 1.8-.5 1.8-1.2 .6-1.7 .2-2.4 .5-.8 1.9-.8 2.9-.7 2.5 .1 1.7-.2 .7 .6-.1 1.4-1.5 1.7-.7 1.8 .5 .5-.4 1.2-.7 2.3-.7-.8-.6 .1-.5 0-1 1.7-.5-.3-.3 .1 0 .5-2.6-.1-2.6 0 0 1.6-1.2 0 1 1 1 .7 .3 .6 .5 .2-.1 .9-3.6 0-1.3 2.3 .4 .6-.3 .6-.1 .9-3.1-3.1-1.5-.9-2.2-.8-1.6 .3-2.2 1-1.4 .3-2-.7-2.1-.6-2.6-1.3-2-.4-3.2-1.3-2.3-1.4-.7-.8-1.6-.1-2.8-.9-1.2-1.3-2.9-1.7-1.4-1.8-.7-1.4 .9-.3-.3-.8 .7-.8 0-1-.9-1.3-.3-1.1-.9-1.5-2.5-2.9-2.8-2.3-1.3-1.9-2.4-1.2-.5-.7 .4-1.8-1.4-.7-1.6-1.5-.7-2.1-1.5-.2-1.6-1.6-1.3-1.5-.2-.9-1.5-2.3-.9-2.3 0-1.2-2-1.2-.9 .1-1.6-.8-.5 1.2 .5 1.5 .3 2.3 .9 1.2 2.1 2.1 .4 .7 .5 .2 .3 1.1 .5-.1 .6 2 .8 .7 .6 1.1 1.8 1.5 .9 2.8 .8 1.3 .8 1.4 .1 1.5 1.4 .1 1.1 1.3 1 1.4-.1 .5-1.2 1.1-.4-.1-.8-1.7-1.8-1.7-2-1.4-1.4-.8 .1-2.2-.4-1.6-1.4-.9-1.9-1.3-.3 .4-.7-.8-1.8-.7-1.6-1.8 .2-.2 1.1 .2 1.1-1.1 .1-1.4-2.2-2.2-1.6-.8-1-1.9-1-2-1.3-2.4z',
|
||||
},
|
||||
MY: {
|
||||
name: 'Malaysia',
|
||||
path: 'M778 298.1l.5-.5 2.3 1.2 .2 1.4 1.8-.3 .9-1.2 .7 .3 1.6 1.7 1.2 1.8 .1 1.9-.3 1.3 .3 .9 .2 1.7 1 .7 1.1 2.5-.1 .9-1.9 .2-2.7-2-3.3-2.2-.3-1.4-1.6-1.9-.4-2.3-1-1.5 .3-2.1zM827.5 304.5l-2.5-.4-3.2 0-.9 3.1-1.1 1-1.4 3.9-2.3 .6-2.6-.8-1.3 .2-1.7 1.4-1.7-.2-1.8 .6-1.9-1.6-.5-1.8 2.1 .9 2.1-.5 .6-2.4 1.1-.5 3.4-.6 2-2.2 1.3-1.7 1.3 1.4 .6-.9 1.3 0 .2-1.7 .1-1.4 2.1-1.9 1.4-2.2 1.2 0 1.4 1.4 .1 1.2 1.8 .8 2.4 .8-.2 1.1-1.9 .1 .5 1.4z',
|
||||
},
|
||||
MZ: {
|
||||
name: 'Mozambique',
|
||||
path: 'M596 348.2l2.1-.3 3.3 .8 .8-.3 1.9-.1 1-.8 1.6 0 3.1-1.1 2.2-1.6 .4 1.3-.1 2.8 .4 2.4 .1 4.4 .5 1.4-.9 2.1-1 1.9-1.8 1.8-2.5 1.1-3.2 1.4-3.1 3.1-1.1 .5-1.9 2-1.2 .7-.2 2.1 1.3 2.2 .6 1.7 0 .8 .5-.1-.1 2.9-.4 1.3 .6 .5-.4 1.2-1.2 1.1-2.3 1-3.3 1.6-1.2 1.1 .2 1.2 .7 .2-.2 1.6-2.1 0-.3-1.3-.4-1.4-.2-1 .5-3.3-.7-2.1-1.4-4.1 3-3.3 .7-2.1 .4-.3 .3-1.7-.4-.8 .1-2.2 .5-2 0-3.6-1.4-.9-1.3-.2-.6-.7-1.3-.6-2.3 0-.2-1-.3-2.1 8.5-2.3 1.6 1.4 .7-.3 1.1 .7 .2 1.2-.6 1.3 .2 2 1.8 1.7 .9-1.9 1.2-.6-.3-3.7-1.1-2-1-1-1 .1-.8-3.7z',
|
||||
},
|
||||
NA: {
|
||||
name: 'Namibia',
|
||||
path: 'M555.3 386.3l0 11-2.5 1.5-1.5 .2-1.8-.5-1.2-.3-.5-1.3-1.1-.8-1.3 1.5-2.1-2.3-1-2.1-.7-2.9-.6-2.2-1-4.5 0-3.5-.4-1.6-1.1-1.2-1.4-2.4-1.5-3.5-.6-1.8-2.2-2.8-.2-2.2 1.3-.6 1.7-.5 1.8 .1 1.7 1.3 .4-.2 11.2-.1 2 1.4 6.7 .4 5.1-1.2 2.3-.6 1.8 .1 1.1 .7 0 .2-1.6 .6-.8 .1-1.8 1.1-1.1-1.2-4.2 1-2.1 .1-.1 10.3-2.7 .1z',
|
||||
},
|
||||
NC: { name: 'New Caledonia', path: 'M960.5 375.5l2.3 1.8 1.4 1.3-1 .7-1.6-.8-1.9-1.3-1.8-1.5-1.9-2.1-.4-1 1.2 .1 1.6 1 1.2 .9z' },
|
||||
NE: {
|
||||
name: 'Niger',
|
||||
path: 'M541.3 251.4l.6 4.6 1.1 .7 0 .9 1.2 1-.6 1.3-1.1 5.8-.1 3.7-3.6 2.7-1.2 3.8 1.2 1 0 1.8 1.7 .1-.2 1.3-.8 .2-.1 .9-.5 0-1.9-3-.7-.2-2.1 1.6-2.2-.8-1.5-.2-.8 .4-1.6-.1-1.6 1.2-1.5 .1-3.3-1.4-1.3 .7-1.5-.1-1-1.1-2.8-1-3 .3-.7 .6-.4 1.7-.8 1.1-.2 2.5-2.1-1.6-1 0-.9 .8 0-1.9-3.2-.7 0-1.3-1.6-1.9-.4-1.3 .2-1.3 1.8-.1 1-1.1 3.8-.2 2.5-.5 .2-1.7 1.6-1.9 0-6.6 3.9-1.3 8-5.7 9.5-5.6 4.4 1.3 1.6 1.6z',
|
||||
},
|
||||
NG: {
|
||||
name: 'Nigeria',
|
||||
path: 'M507.5 298.6l.1-4.5 0-1.7 .5-1.8 .8-.9 1.4-1.7-.3-.8 .5-1.1-.6-1.7 .1-.9 .2-2.5 .8-1.1 .4-1.7 .7-.6 3-.3 2.8 1 1 1.1 1.5 .1 1.3-.7 3.3 1.4 1.5-.1 1.6-1.2 1.6 .1 .8-.4 1.5 .2 2.2 .8 2.1-1.6 .7 .2 1.9 3 .5 0 1.1 1.1-.3 .5-.2 1-2.3 2.1-.7 1.8-.4 1.5-.6 .6-.6 2-1.5 1.1-.4 1.4-.6 1.2-.3 1.1-1.9 1-1.5-1.2-1.1 .1-1.6 1.6-.9 0-1.3 2.7-.7 2-2.9 1-1-.2-1.1 .7-2.2-.1-1.5-1.7-.9-2.1-2-1.8-2.1 0z',
|
||||
},
|
||||
NI: {
|
||||
name: 'Nicaragua',
|
||||
path: 'M267.6 285.5l-.6 .6-.9-.2-.4-.5-.9-.3-.6 .4-1.9-.7-.4 .3-1-.9-1.2-1.1-.7-1-1.1-.8-1.4-1.3 .3-.5 .4 .5 .3-.2 .8-.1 .4-.7 .4 0-.1-1.4 .7-.1 .5 0 .6-.7 .9 .6 .2-.4 .6-.3 .9-.8 .1-.6 .2 0 .4-.6 .3-.1 .5 .4 .5 .1 .6-.3 .7 0 1-.4 .4-.4 .9 .1-.2 .2-.1 .7 .2 1-.6 1-.3 1.1-.1 1.3 .2 .7 0 1.3-.4 .2-.3 1.2 .2 .8-.5 .7 .1 .8z',
|
||||
},
|
||||
NL: { name: 'Netherlands', path: 'M519.2 151.4l.5 1.2-.7 3.5-.7 1.4-1.7 0 .5 3.8-1.5-.8-1.8-1.6-2.6 .7-2-.3 1.4-1 2.5-5.5 3.8-1.5z' },
|
||||
NO: {
|
||||
name: 'Norway',
|
||||
path: 'M542.1 26.5l1-2.2 4.1-.2 3.5 2.2 9.1 4.6-6.9 2.4-1.6 4.5-2.4 1.1-1.3 4.9-3.4 .2-6-3.6 2.5-2.1-4.1-1.7-5.4-5.1-2.2-4.9 7.6-2.3 1.5 2.2zM586.4 82.5l-4.7 1.9-2.3 .5 1.2-3.5-3.6-1.9-4.3 1.6-1.3 3.6-2.7 2.2-3-1.2-3.6 .3-3.1-2.6-1.7 1.3-1.7 .2-.4 3.2-5.2-.8-.8 2.7-2.6-.1-1.9 3.4-2.7 5.2-4.3 6.4 1 1.5-1 1.8-2.8-.1-1.8 4.1 .2 5.8 1.8 2.1-.9 5-2.3 2.8-1.3 2.4-1.8-2.6-5.5 4.8-3.7 .9-3.9-2-1-4.4-.8-9.8 2.5-2.7 7.4-3.7 5.4-4.6 5.1-6.3 6.7-9 4.7-3.6 7.6-6.1 6.1-2.2 4.6 .3 4.2-4.2 5.1 .2 4.9-1 8.7 3.7-3.6 1.4zM576.1 24l-4.1 3.4-8 .8-8.2-1.1-.5-1.7-4-.1-3.1-2.9 8.6-1.8 4.1 1.5 2.8-1.9 7 1.6zM568.7 37.6l-6.2 2.4-4.9-1.3 1.9-1.6-1.7-1.9 5.8-1.2 1.1 2.3z',
|
||||
},
|
||||
NP: { name: 'Nepal', path: 'M744.8 236.6l-.2 1.3 .3 1.9-.3 1.1-2.3 .1-3.3-.7-2.2-.3-1.6-1.5-3.8-.4-3.6-1.7-2.6-1.5-2.7-1.1 1-2.8 1.8-1.4 1.2-.7 2.2 .9 2.8 2 1.6 .4 .9 1.5 2.1 .6 2.3 1.3 3.1 .7z' },
|
||||
NZ: {
|
||||
name: 'New Zealand',
|
||||
path: 'M991.3 433.6l-1 1.8-1.4 2.3-2.1 1.3-.5-.9-1.2-.5 1.6-2.7-.9-1.8-3-1.3 .1-1.2 2-1.1 .5-2.5-.1-2.1-1.2-2.1 .1-.6-1.3-1.3-2.2-2.8-1.2-2.2 1.1-.2 1.5 1.7 2.1 .8 .8 2.8 2 3.4 .1-2.2 1.3 .9 .4 2.4 2.2 1 1.9 .3 1.6-1.2 1.4 .3-.7 2.9-.8 1.9-2.2-.1-.7 1 .3 1.4zM971.3 445.3l2.4-1.8 1.6-1.8 1.3-2.4 1-.9 .4-1.8 2-1.6 .6 1.4 .6 1.4 2-1.3 .8 1.4 0 1.4-1 1.5-1.8 2.5-1.4 1.3 1 1.7-2.2 0-2.3 1.3-.8 2.2-1.6 3.5-2.1 1.6-1.4 1-2.6-.1-1.8-1.2-3-.2-.5-1.3 1.5-2.5 3.5-3.4 1.8-.7z',
|
||||
},
|
||||
OM: {
|
||||
name: 'Oman',
|
||||
path: 'M653.4 251.9l0-1.2 .8-1.2 0-1.2 1.3-.6-.5-.4 .2-1.9 1.5 0 1.2 2 1.6 1 2 .4 1.6 .6 1.3 1.6 .7 1 1 .4 0 .6-1 1.8-.4 .8-1.2 .9-1 2-1.3-.1-.6 .6-.4 1.5 .3 1.9-.2 .4-1.3 0-1.8 1.1-.2 1.4-.7 .6-1.7-.1-1.1 .8 0 1.1-1.3 .8-1.5-.3-1.9 1-1.3 .2-.9-2-2.2-4.8 8.4-2.9 1.8-5.8zM656.3 243l-.5-1 .8-1 .3 .3-.3 1.2z',
|
||||
},
|
||||
PA: {
|
||||
name: 'Panama',
|
||||
path: 'M285.1 291.9l-.3 .4 .6 1.7-.5 .8-.9-.2-.3 1.3-1-.8-.6-1.5 .7-.7-.7-.2-.5-.9-1.4-.8-1.2 .2-.6 .9-1.1 .7-.6 .1-.3 .6 1.4 1.5-.8 .4-.4 .4-1.3 .1-.5-1.6-.3 .5-.9-.2-.6-1.1-1.1-.2-.8-.3-1.2 0 0 .6-.4-.5 .2-.5 .2-.6-.1-.5 .4-.3-.6-.4 0-1.2 1.1-.2 1 1-.1 .6 1.2 .1 .2-.2 .8 .7 1.3-.2 1.2-.7 1.7-.6 1-.8 1.5 .1-.1 .3 1.5 .1 1.3 .5 .9 .8z',
|
||||
},
|
||||
PE: {
|
||||
name: 'Peru',
|
||||
path: 'M305.9 328l-2.6-.1-.3 .4-2.3 .5-3.2 1.9-.2 1.3-.7 1 .3 1.5-1.7 .8 0 1.2-.7 .5 1.1 2.5 1.6 1.7-.6 1.2 1.8 .2 1.1 1.5 2.4 0 2.3-1.6-.2 4.2 1.3 .4 1.6-.5 2.4 4.5-.6 1-.2 2 0 2.4-1.1 1.4 .5 1-.6 1 1.1 2.4-1.7 3.1-.8 1.4-1.4 .8-2.8-1.7-.2-1.2-5.5-2.8-5-3.1-2.1-1.8-1.2-2.3 .5-.8-2.4-3.7-2.7-5.2-2.6-5.6-1.2-1.3-.9-2-2.1-1.9-2-1.1 .9-1.2-1.3-2.7 .8-1.9 2.2-1.8 .4 1.2-.8 .6 0 1 1.2-.2 1.1 .3 1.2 1.4 1.6-1.1 .5-1.9 1.7-2.4 3.3-1.1 3.1-2.9 .8-1.8-.4-2.1 .8-.3 1.8 1.3 .9 1.3 1.3 .7 1.6 3 2.1 .3 1.5-.7 1 .4 1.7-.2 2.1 1.3-1.8 2.8 .9 .1z',
|
||||
},
|
||||
PG: {
|
||||
name: 'Papua New Guinea',
|
||||
path: 'M891.7 323.3l4.8 1.9 5.1 1.6 1.9 1.4 1.6 1.4 .4 1.6 4.6 1.8 .7 1.4-2.5 .3 .6 1.9 2.4 1.8 1.9 3 1.5-.1-.1 1.2 2.2 .5-.9 .6 3 1.1-.3 .8-1.9 .2-.6-.7-2.4-.3-2.8-.4-2.2-1.8-1.6-1.6-1.4-2.4-3.6-1.2-2.4 .8-1.7 .9 .4 2.1-2.2 .9-1.6-.4-2.8-.2-.1-9.1zM924 326.2l1.1 .9 .3 1.4-.9 .8-.5-1.7-.6-1-1.3-.9-1.6-1.2-2-.8 .8-.7 1.5 .8 .9 .6 1.2 .6zM920.3 332.3l-1.5 .7-1.5 .6-1.4 0-2.3-.8-1.6-.8 .2-.8 2.5 .4 1.5-.3 .5-1.3 .4-.1 .2 1.5 1.6-.2 .8-.9 1.5-1-.3-1.7 1.7 0 .6 .4-.1 1.6-.9 1.7-1.5 .2zM929.9 330.9l.8 .6 1.4 1.8 1.3 .9-.4 .8-.8 .3-1.2-1.1-1.2-1.8-.6-2.1 .4-.2z',
|
||||
},
|
||||
PH: {
|
||||
name: 'Philippines',
|
||||
path: 'M835.6 280.6l-1.4-2.2 2.4 .1 1 1-.8 2.5zM840.5 288.2l.7-.8 .3-1.7 1.6-.2-.5 1.9 2.1-2.7-.3 2.7-1 .9-.9 1.8-.8 .8-1.8-1.9zM851 292.6l.3 1.9 .2 1.5-1 2.6-1-2.9-1.3 1.5 .9 2-.8 1.3-3.2-1.6-.8-2 .8-1.3-1.7-1.4-.9 1.2-1.3-.1-2.1 1.5-.4-.8 1.1-2.3 1.7-.8 1.5-1.1 1 1.3 2.1-.8 .5-1.2 1.9-.1-.1-2.2 2.2 1.4 .3 1.4zM829.2 290.1l-3.7 2.6 1.3-1.9 2.1-1.7 1.6-2 1.5-2.8 .5 2.3-1.9 1.6zM839.8 264.9l-.4 1.1 .9 2.1-.7 2.4-1.6 .9-.5 2.3 .6 2.3 1.5 .3 1.2-.4 3.5 1.6-.3 1.6 .9 .6-.2 1.3-2.2-1.4-1-1.4-.7 1-1.8-1.7-2.5 .4-1.4-.6 .1-1.2 .9-.7-.8-.6-.4 1-1.4-1.7-.4-1.2-.1-2.7 1.1 .9 .3-4.4 .9-2.6 1.7 0 1.7 .8 .9-.8zM839 284.2l-.4-1.3 1.6 .8 1.8 0-.1 1.2-1.2 1.2-1.8 .8-.1-1.3zM848.6 282.1l.8 3.1-2.1-.7 0 .9 .7 1.8-1.3 .6-.1-2-.9-.1-.4-1.7 1.6 .2 0-1.1-1.7-2.1 2.7 0z',
|
||||
},
|
||||
PK: {
|
||||
name: 'Pakistan',
|
||||
path: 'M716.2 213.1l-2.7 2.7-3.1 .5-4.2-.8-1.3 1.3 .9 2.8 1 2.1 2.3 1.5-2.4 1.8 0 2.2-2.7 3-1.7 3.1-2.9 3.2-3.2-.3-3.1 3.2 1.8 1.3 .3 2.3 1.6 1.5 .5 2.5-6.1 0-1.8 2-2.1-.7-.8-2.2-2.1-2.2-5.1 .5-4.6 .1-3.9 .4 1.1-3.4 4-1.6-.3-1.4-1.3-.4-.1-2.7-2.6-1.3-1.1-1.8-1.4-1.6 4.6 1.5 2.8-.4 1.7 .4 .6-.7 1.9 .3 3.6-1.3 .1-2.6 1.5-1.7 2.1 0 .3-.9 2.1-.4 1.1 .3 1-.9-.1-1.8 1.2-1.9 1.7-.8-1-2 2.6 .1 .8-1.2-.2-1.2 1.4-1.3-.3-1.6-.6-1.3 1.6-1.4 3-.6 3.1-.4 1.5-.6 1.6-.4 2 1.5 .8 2.5z',
|
||||
},
|
||||
PL: {
|
||||
name: 'Poland',
|
||||
path: 'M565.2 149.7l.2 1.7 .7 1.4 0 1.5-1.7 .8 .9 1.7 .1 1.7 1.3 3.2-.2 1-1.4 .4-2.5 3.1 .7 1.6-.6-.2-2.7-1.4-2 .5-1.3-.4-1.6 .8-1.4-1.3-1.2 .5-.1-.2-1.3-1.8-2.1-.2-.2-1.2-1.9-.4-.5 1-1.5-.8 .2-1-2.1-.3-1.3-1.2-1.1-2.3 .2-1.3-.7-2-1-1.3 .8-1.1-.7-1.9 1.9-1.1 4.4-1.8 3.5-1.3 2.7 .7 .2 .9 2.7 .1 3.4 .4 5.1-.1 1.5 .5z',
|
||||
},
|
||||
PR: { name: 'Puerto Rico', path: 'M315.9 264l1.4 .3 .5 .5-.7 .8-2.1 0-1.6 .1-.2-1.3 .4-.4z' },
|
||||
PS: { name: 'Palestine', path: 'M598.3 225.6l-1.3 .4 .1-.8 .7-.4-.6-.4 .5-2 1 .4 0 1.9z' },
|
||||
PT: { name: 'Portugal', path: 'M474.9 192.4l1-.8 1.1-.5 .7 1.6 1.7 0 .5-.4 1.6 .1 .8 1.7-1.3 .9-.1 2.6-.4 .5-.1 1.5-1.2 .3 1.1 1.9-.8 2.1 1 1-.4 .9-1 1.2 .2 1-1.1 .9-1.5-.5-1.4 .4 .4-2.5-.3-2-1.2-.3-.7-1.2 .3-2.2 1.1-1.1 .2-1.4 .5-1.9 0-1.4-.6-1.2z' },
|
||||
PY: { name: 'Paraguay', path: 'M338.4 372.8l.8 1.7-.1 3.9 2.9 .6 1.1-.6 1.9 .8 .5 .8 .3 2.7 .3 1.2 1 .1 1.1-.5 1 .6 0 1.6-.4 1.7-.5 1.7-.5 2.7-2.5 2.2-2.2 .5-3.1-.4-2.8-.8 2.7-4.6-.4-1.3-2.9-1.1-3.3-2.2-2.3-.5-5.1-4.7 1.1-3.5 0-1.6 1.4-2.5 4.8-.9 2.6 .1 2.6 1.5z' },
|
||||
QA: { name: 'Qatar', path: 'M641.1 245.9l-.1-2.2 .7-1.5 .8-.4 .8 1 .1 1.7-.7 1.7-.7 .2z' },
|
||||
RO: {
|
||||
name: 'Romania',
|
||||
path: 'M578.4 180.2l1.3 .7 1.3-.6 1.2 .6 .1 .9-1.4 .7-.8-.3-.8 4.1-1.6-.4-2-1.2-3.3 .8-1.4 .9-4.1-.2-2.1-.5-1.1 .2-.8-1.4-.5-.6 .7-.6-.7-.4-.9 .8-1.6-1-.2-1.4-1.7-.8-.3-1.1-1.5-1.4 2.2-.7 1.7-2.3 1.3-2.4 1.7-.8 1.2-.7 1.7 .4 1.8 0 1.3 .9 .9-.6 2.1-.3 .7-.9 1.1 0 .9 .4 .8 1 .9 1.5 1.6 2.1 .1 1.6-.3 1.4z',
|
||||
},
|
||||
RS: {
|
||||
name: 'Serbia',
|
||||
path: 'M552.3 178.8l2.1-1 1.8 .2 1.5 1.4 .3 1.1 1.7 .8 .2 1.4 1.6 1 .9-.8 .7 .4-.7 .6 .5 .6-.6 .8 .2 1.2 1.4 1.5-1.1 1-.5 1.1 .3 .4-.4 .5-1.3 0-1 .2-.1-.2 .4-.4 .3-.8-.4 0-.5-.6-.5-.2-.4-.5-.5-.2-.4-.5-.5 .2-.4 1.1-.6 .2 .2-.3-1.1-.7-.9-.3-.4-.5-.7-.6 .6-.1 .4-1.6-1.3-1.3 .7-1.5-1 0 1.1-1.3-.9-1z',
|
||||
},
|
||||
RU: {
|
||||
name: 'Russian Federation',
|
||||
path: 'M996.5 74.8l3.5-2.2 0 3.5-3 .3zM636.4 177.1l-1.3 2-2.7 .6-2.7 3.5 2.5 3.3-.3 2.2 3.1 4-1.7 1.3-.5 .9-1.2-.3-1.9-2-.8-.1-1.7-.8-.9-1.3-2.6-.7-1.7 .5-.5-.6-3.7-1.6-4.1-.6-2.4-.6-.3 .4-3.6-2.8-3.1-1.3-2.4-2 2-.6 2.3-2.9-1.6-1.4 4.1-1.4 0-.8-2.5 .6 .1-1.6 1.4-1 2.7-.2 .4-1.2-.6-2 1.1-1.8 0-1.1-4.1-1.2-1.6 .1-1.7-1.7-2.2 .5-3.5-1.2 .1-.8-1-1.5-2.2-.2-.3-1.2 .7-.7-1.7-2.1-2.9 .3-.9-.2-.7 .9-1-.2-.7-2.3-.6-1.3 .5-.3 2.2 .1 1.1-.8-.8-1-1.9-.7 .2-.7-1.1-.7-1.8-2.5 .6-1.1-.2-1.8-2.8-.9-1.4 .5-.4-1-2.9-1-.9-2.3-.3-1.9-1.3-1 1.2-1.2-.8-3.8 1.9-2.4-.4-.7 3.2-2.3-2.9-1.9 5.9-5.4 2.6-2.5 1-2.2-4.1-3 1.2-2.9-2.5-3.3 1.8-3.9-3.2-5.3 2.6-3.5-4.3-3.2 .4-3.4 2.3-.5 4.7-1.9 2.9-1.8 4.5 3 7.6 1.2 10.5 5.4 2.2 2.3 .1 3.1-3 2.5-4.6 1.2-12.4-3.5-2 .6 4.5 3.3 .2 2.2 .2 4.6 3.5 1.3 2.2 1.2 .4-2.2-1.7-1.9 1.8-1.7 6.7 2.8 2.3-1.1-1.8-3.3 6.4-4.5 2.6 .2 2.6 1.7 1.6-3.2-2.3-2.8 1.3-2.8-2-3 7.8 1.5 1.6 2.7-3.6 .6 .1 2.6 2.1 1.6 4.3-1 .7-3 5.8-2.3 9.7-4.1 2.1 .2-2.7 3 3.4 .5 2-1.7 5.2-.1 4.1-2 3.2 2.9 3.2-3.2-2.9-2.8 1.4-1.7 8.2 1.5 3.8 1.6 10.1 5.5 1.9-2.5-2.9-2.6 0-1-3.4-.5 .9-2.4-1.5-3.9 0-1.6 5.1-4.6 1.8-4.8 2.1-1 7.3 1.4 .6 2.9-2.6 4.2 1.7 1.6 .9 3.5-.6 6.8 3 3-1.2 3.2-5.4 6.6 3.2 .7 1.1-1.7 3-1.2 .8-2.3 2.4-2.2-1.6-2.8 1.3-3.2-3.1-.4-.7-2.7 2.3-5-3.6-4.1 4.9-3.5-.6-3.7 1.4-.1 1.4 2.9-1.1 5 3 .9-1.3-3.7 4.7-2.1 5.8-.2 5.1 2.9-2.5-4.3-.3-5.7 4.9-1.1 6.7 .3 6-.7-2.3-2.9 3.2-3.6 3.2-.2 5.4-2.7 7.4-.8 .9-1.6 7.3-.5 2.3 1.3 6.2-3 5.1 .1 .8-2.5 2.6-2.5 6.6-2.5 4.7 2-3.8 1.4 6.3 .9 .8 2.9 2.5-1.4 8.1 0 6.3 2.8 2.2 2.2-.7 2.9-3 1.7-7.3 3-2.1 1.6 3.4 .8 4.1 1.4 2.5-1 1.5 3.4 1.2-1.4 4.4-.8 8.9 .9 .7 2.5 11.6 .7 .2-4 5.9 .9 4.4 0 4.5 2.8 1.3 3.4-1.7 2.1 3.5 4.1 4.4 2 2.7-5.3 4.4 2.3 4.8-1.4 5.3 1.6 2.1-1.4 4.5 .7-2-4.8 3.7-2.3 25.1 3.4 2.3 3.1 7.3 3.9 11.2-1 5.6 .8 2.3 2.1-.4 3.7 3.5 1.4 3.7-1 4.9-.2 5.2 1 5.3-.6 4.8 4.4 3.5-1.6-2.3-3.1 1.3-2.2 8.8 1.4 5.8-.3 8 2.3 3.9 2.2 0 18.6-3.6 2-3.6-.3 2.5 2.4 1.7 3.6 1.3 1.2 .3 1.8-.7 1.1-5.2-.9-7.8 3.2-2.5 .5-4.2 3-4 2.6-1.1 1.8-3.9-2.8-7.3 3.2-1.2-1.5-2.7 1.8-3.7-.6-.9 2.7-3.4 4 .1 1.6 3.2 .9-.4 5.8-2.5 .1-1.2 3.3 1.1 1.6-4.8 2-1 4.3-4.1 .9-.9 3.8-4 3.5-1-2.6-1.2-5.4-1.5-8.5 1.3-5.4 2.3-2.4 .2-1.9 4.3-.9 5-5.1 4.7-4.3 5-3.3 2.3-6-3.4 .3-1.7 3.5-7 4.7-2.3-5.2-7.2 1.4-6.9 7.1 2.3 2.5-6.2 1.1-4.3 .4 .2-3-4.3-.6-3.5 2-8.5-.7-9.1 1.2-9 7.9-10.6 9.2 4.3 .5 1.4 2.4 2.7 .8 1.8-1.9 3 .3 4 4.1 .1 3.2-2.2 3.7-.2 4.4-1.2 5.7-4.2 5.2-1 2.4-3.7 4-3.8 3.9-1.8 2.1-3.7 1.9-1.7 .1-1.8-1.7-3.7 2.5-.4 1.1-.4-.6 0-1.7 1.4-.1 .4-4-.7-2.9 2.3-1.2 3.4 .6 1.9-3.4 .9-3.8 1.1-1.3 1.5-3.2-4.6 1.1-2.4 1.4-4.2 0-1.2-3.4-3.3-2.5-4.8-1.2-1-3.5-1-2.3-1-1.6-1.7-3.7-2.5-1.4-4.1-1.1-3.7 .1-3.5 .6-2.3 1.9 1.5 .9 .1 2.1-1.6 1.1-2.5 3.9 .1 1.6-4 2.3-3.3-1.3-3.3 .3-1.5-1.2-1.6-.4-4.1 2.5-3.7 .6-2.5 .9-3.5-.6-2.6 .1-1.7-1.9-2.7-1.7-2.8-.5-3.5 .5-2.6 .6-4-1.5-.5-2.7-3.3-1-2.5-.4-3.1-1.6-2.9 3.9 1.2 2.1-2.7 2.6-4-1-2.8-.1-1.9-1.7-2.9 0-2.4-1.2-4.2 1.8-5.3 3.1-2.9 .6-1.1 .3-1.5-2.2-3.6 .5-1.2-1.6-1.9-.7-1.3-2.1-1.6-.6-4 .9-3.8-2.1-1.5 1.9-6.2-9.4-3.5-3 1-1.2-7 3.6-2.6 .2 .2-2-3.6-1.3-2.9 .9-.9-4-4.9-.8-2.5 1.6-7 1.4-1.3 .9-10.4 1.4-1.3 1.3 2 2.6-2.7 .9 .5 1.1-2.6 1.8 4.5 2.5-.7 1.8-3.9-.2-.8 1.1-3.6-1.9-4.4 .1-2.9 1.5-3.3-1.5-6.1-2.5-4.4 .1-5.7 4-.4 2.6-2.8-2.1-2.2 4 .8 .7-1.6 2.7 2.3 2.4 2.1-.1 1.8 2.4-.3 1.8zM760.5 17.8l6-1.5 5.4 3.3 6.4 6.2-.7 5.6-6.1 .8-7.7-1.8-4.6-2.4-2.1-4.5-3.8-1.3zM785.7 28.9l7 3.5-.8 2.5-15.7 2.3 5.1-8 2.3-.7zM885.6 47.6l7.4 .3 10 3-2.2 4.1-10.2-.1-4.6 1.3-5.5-3.6 1.5-3.9zM911.7 52.1l7 1.5-3.2 2.2-4.5-.5-5.1-2.2 .7-1.8zM888.5 62.9l2.6-2.1 3.5-.5 4 2.1 .3 1.4-4.2 0-5.7-.6zM624.6 20.6l5.4-1.1 4.2-.1 .6 1.7 1.6-1.5 2.6-1.1 4.1 1.4-1.1 1-3.7 .9-2.5 .4-.4 1.1-3.2 1-3-1.5 1.6-2zM563.1 148.1l-5.1 .1-3.4-.4 .6-1.7 3.9-1.3 2.9 .7 1.2 .6-.3 1.1zM648.6 60.9l6.7-4.8-.8-2.5 6.2-3 9.2-3.6 9.3-1.1 4.7-2.1 5.4-.8 2 2.3-1.9 1.8-9.9 2.8-8.4 2.7-8.7 5.2-4.1 5.3-4.4 5.1 .6 4.3 5.3 4.2-1.6 .4-9.1-.6-.7-2.3-5.1-1.4-.4-2.7 2.9-1.2-.1-2.8 5.5-4.6zM897 150.5l.9 3.7 0 3.6 1.1 3.7 2.8 6.5-4.1-1.2-1.7 5.1 2.7 3.6-.1 2.5-2.1-2.1-1.8 2.7-.5-3 .3-3.4-.3-3.8 .6-2.7 .1-4.9-1.6-3.6 .3-5.2 2.5-1.7-1.1-1.8 1.3-.5zM14.1 93.8l-.3 2.9 1.9 1.1-.6-3.3 7.5 .6 5.5 4.4-2.8 2-4.6 .4 0 4.5-1.1 .9-2.6-.2-2.1-1.5-3.7-1.3-.7-2-2.8-.7-3.1 .6-1.6-1.6 .6-1.7-3.3 1.1 1.3 2.1-1.6 1.9 0-18.6 6.8 3.7zM3.6 75.8l-3.6 .3 0-3.5 .4-.2 2.3 0 4 1.5-.2 .7zM592.9 178.5l.7-.8 2 .7 .9 .2 .3 .6 .5 .2 0 .3 1.3 .8 2.9-.2-.6 1.2-3 .6-3.8 2-1.5-.7 .6-1.6-3-1 .4-.7 2.7-1.1z',
|
||||
},
|
||||
RW: { name: 'Rwanda', path: 'M584.5 319.2l1.1 1.6-.2 1.6-.8 .3-1.4-.1-.9 1.5-1.7-.2 .3-1.5 .4-.2 .1-1.7 .8-.7 .6 .2z' },
|
||||
SA: {
|
||||
name: 'Saudi Arabia',
|
||||
path: 'M597.1 232.1l3.1 .5 1.2-.9 .7-1.1 2.1-.5 .4-1 1-.5-2.8-3.1 5.5-1.5 .6-.5 3.3 .9 4.2 2.1 7.8 6.1 5.2 .3 2.4 .3 .7 1.4 2-.1 1.1 2.6 1.3 .7 .5 1.1 1.9 1.2 .2 1.3-.3 .9 .4 1 .8 .9 .3 .9 .4 .8 .9 .5 .7-.2 .6 1.2 .1 .6 1 3 8.4 1.5 .6-.6 1.2 2-1.8 5.8-8.4 2.9-8 1.1-2.6 1.3-1.9 3-1.3 .5-.7-.9-1.1 .1-2.7-.3-.5-.3-3.2 .1-.8 .3-1.1-.8-.7 1.4 .3 1.2-1.3 .9-.3-1.2-.9-.9-.2-1.1-1.4-1-1.5-2.4-.8-2.4-1.9-2-1.2-.4-1.9-2.8-.3-2 .1-1.7-1.6-3.3-1.3-1.1-1.5-.7-.9-1.6 .2-.7-.8-1.5-.8-.7-1.1-2.2-1.7-2.4-1.4-2.1-1.4 0 .4-1.6 .2-1.1z',
|
||||
},
|
||||
SB: { name: 'Solomon Islands', path: 'M950.3 345.3l.8 .9-1.9 0-1.1-1.7 1.7 .7zM949.1 342.8l-.4 .5-2.1-2.4-.5-1.7 .9 0 1 2.2zM946.8 343.6l-1.1 0-1.7-.3-.6-.4 .2-1.1 1.9 .4 .9 .6zM943.4 338.4l.7 .9 .1 .5-2.2-1.2-1.5-1-1-.9 .4-.3 1.3 .7zM936.5 335.6l1.1 .9-.5 .1-1.3-.6-1.1-1.1 .1-.5z' },
|
||||
SD: {
|
||||
name: 'Sudan',
|
||||
path: 'M568.2 293.1l-2.1-1.2-.9-.8-.2-.9 .4-1.1 0-1.2-1.6-1.7-.3-1.2 0-.7-1-.8 0-1.7-.6-1.1-1 .2 .3-1 .7-1.2-.3-1.2 .9-.9-.5-.6 .7-1.8 1.3-2.1 2.4 .2-.2-11.3 .1-1.3 3.1 0 0-5.8 11.2 0 10.8 0 11 0 .9 2.9-.6 .5 .4 3 1 3.4 1.1 .7 1.5 1.1-1.4 1.6-2.1 .5-.8 .9-.3 1.9-1.2 4.2 .3 1.1-.4 2.4-1.2 2.8-1.7 1.4-1.1 2.2-.3 1.1-1.3 .8-.9 2.9 .1 2.6-.1-2.2-.3-.1 0-1.4-.3-.9-1.5-1.2-.3-2 .3-2.1-1.2-.2-.2 .7-1.7 .1 .7 .8 .2 1.7-1.5 1.6-1.4 2-1.4 .3-2.4-1.6-1 .5-.3 .9-1.4 .5-.1 .6-2.8 0-.4-.6-2-.1-1 .5-.8-.3-1.4-1.6-.5-.8-2 .4-.7 1.3-.7 2.5-1 .5-.8 .3z',
|
||||
},
|
||||
SE: {
|
||||
name: 'Sweden',
|
||||
path: 'M530.6 130.3l1.3-2.4 2.3-2.8 .9-5-1.8-2.1-.2-5.8 1.8-4.1 2.8 .1 1-1.8-1-1.5 4.3-6.4 2.7-5.2 1.9-3.4 2.6 .1 .8-2.7 5.2 .8 .4-3.2 1.7-.2 3.8 2.4 4.3 3.2 .1 7.3 .9 1.7-4.8 1.3-2.7 3.2 .5 2.8-4.5 3.5-5.3 3.8-2 6 1.9 3 2.7 2.3-2.6 4.7-2.9 .9-1 6.8-1.6 3.7-3.4-.4-1.5 3.1-3.2 .2-.9-3.7-2.4-4.5z',
|
||||
},
|
||||
SI: { name: 'Slovenia', path: 'M538.4 176.7l2.2 .2 1.4-.7 2.5-.1 .5-.6 .5 0 .5 1.2-2.2 .9-.3 1.4-.9 .4 0 .9-1.1 0-1-.6-.5 .6-1.9-.1 .6-.3-.6-1.5z' },
|
||||
SK: { name: 'Slovakia', path: 'M562.7 167.6l-.8 .9-.6 1.4-.5 .4-3-1.1-.9 .2-.7 .9-1.3 .4-.3-.2-1.3 .5-1.1 .1-.3 .8-2.3 .4-1-.4-1.4-.9-.3-1.2 .2-.5 .4-.8 1.2 .1 1-.4 .1-.3 .5-.2 .2-.8 .6-.2 .4-.6 .9 0 .1 .2 1.2-.5 1.4 1.3 1.6-.8 1.3 .4 2-.5z' },
|
||||
SL: { name: 'Sierra Leone', path: 'M463.2 291.2l1.5-1.2 .3-.8 .5-.6 .7 0 .7-.6 2.2 0 .8 1 .6 1.2-.1 .8 .4 .8 0 1 .8-.2-1.3 1.3-1.3 1.6-.1 .8-.7 .9-.7-.2-2-1.2-1.5-1.5-.5-1z' },
|
||||
SN: { name: 'Senegal', path: 'M453.6 278l-1.2-2.2-1.4-1 1.3-.5 1.3-2 .7-1.5 .9-.9 1.4 .3 1.4-.7 1.5 0 1.3 .9 1.9 .7 1.7 2.1 1.8 2 .1 1.7 .6 1.6 1 .8 .2 1.1-.1 .9-.4 .2-1.5-.3-.2 .3-.6 .1-2-.7-1.4 0-5.1-.1-.7 .3-1-.1-1.4 .5-.5-2.2 2.5 .1 .7-.4 .5-.1 1-.6 1.2 .6 1.2 0 1.2-.6-.5-.8-.9 .5-.9-.1-1.1-.7-.9 .1-.6 .7z' },
|
||||
SO: { name: 'Somalia', path: 'M615.5 320.7l-1.6-2.3-.1-10.1 2.5-3.2 .7-.8 1.8-.1 2.5-1.9 3.6-.2 7.8-8.3 2-2.4 1.2-1.7 0-1.5 0-2.8 .1-1.1 0-.1 .9 0 1.2-.5 1.5-.2 1.3-1 1.1 0 0 .8-.2 1.6 0 1.5-.6 1-.8 3-1.3 3.1-1.7 3.6-2.4 4.1-2.4 3.1-3.3 3.8-2.7 2.3-4.2 2.7-2.6 2.1-3 3.4-.7 1.5z' },
|
||||
SR: { name: 'Suriname', path: 'M348.5 309.6l-1.5-.6-1.4 .3-1.1-.2-.3 .8 .5 .5-.2 .6-1.6-.2-1.7-2.5-.3-1.5-.9 0-1.2-2 .5-1.5-.2-.6 1.7-.8 .5-2.5 3.3 .6 .3-.5 2.2-.2 3 .7-1.4 2.4 .2 1.9 1.1 1.7-.5 1.2-.2 1.2z' },
|
||||
SS: {
|
||||
name: 'South Sudan',
|
||||
path: 'M585.6 306.3l-2.4-1.9-.7-1.2-1.5 .6-1.3-.1-.7 .4-1.3-.3-1.7-2.3-.4-.9-2.1-1.1-.7-1.7-1.1-1.2-1.9-1.4 0-.9-1.6-1.2-1.8-1.1 .8-.3 1-.5 .7-2.5 .7-1.3 2-.4 .5 .8 1.4 1.6 .8 .3 1-.5 2 .1 .4 .6 2.8 0 .1-.6 1.4-.5 .3-.9 1-.5 2.4 1.6 1.4-.3 1.4-2 1.5-1.6-.2-1.7-.7-.8 1.7-.1 .2-.7 1.2 .2-.3 2.1 .3 2 1.5 1.2 .3 .9 0 1.4 .3 .1 .1 2.2-.4 .8-1.5 .1-1 1.6 1.7 .2 1.5 1.3 .4 1.1 1.3 .7 1.7 3-1.9 1.9-1.7 1.6-1.7 1.3-2 0-2.2 .7-1.8-.7z',
|
||||
},
|
||||
SV: { name: 'El Salvador', path: 'M251.8 275.7l.8 .2 .6 .6 .9 .5 .1 .3 1.2-.3 .5 .2 .4 .3-.2 1.1-.3 .7-1.6 0-1-.3-1.1-.6-1.6-.1-.8-.7 .1-.4 1-.7 .5-.3-.2-.3z' },
|
||||
SY: { name: 'Syria', path: 'M599.2 221.8l.3-.4 0-1.3 .7-1.7 1.5-1.2-.5-1.2-1.2-.2-.3-2.4 .7-1.3 .8-.7 .7-.7 .2-1.8 .9 .7 3-.9 1.5 .6 2.3 0 3.2-1.2 1.5 0 3.1-.5-1.4 2-1.5 .8 .3 2.3-1.1 3.8-6.1 3.3-5.5 3.3z' },
|
||||
SZ: { name: 'Kingdom of eSwatini', path: 'M589.1 392.1l-.6 1.3-1.6 .3-1.7-1.6 0-1 .8-1.1 .2-.9 .8-.2 1.4 .5 .4 1.4z' },
|
||||
TD: {
|
||||
name: 'Chad',
|
||||
path: 'M566.2 261l.2 11.3-2.4-.2-1.3 2.1-.7 1.8 .5 .6-.9 .9 .3 1.2-.7 1.2-.3 1 1-.2 .6 1.1 0 1.7 1 .8 0 .7-1.7 .4-1.5 1.2-2 3-2.6 1.3-2.7-.1-.7 .2 .2 1-1.4 1-1.2 1.1-3.5 1-.7-.6-.4 0-.6 .7-2.3 .2 .5-.8-.9-1.9-.4-1.2-1.2-.4-1.6-1.7 .6-1.3 1.2 .3 .8-.2 1.6 0-1.5-2.5 .1-1.9-.2-1.9-1.1-1.8 .2-1.3-1.7-.1 0-1.8-1.2-1 1.2-3.8 3.6-2.7 .1-3.7 1.1-5.8 .6-1.3-1.2-1 0-.9-1.1-.7-.6-4.6 2.8-1.6 11 5.6z',
|
||||
},
|
||||
TF: { name: 'French Southern and Antarctic Lands', path: 'M691.5 462.9l1.8 1.1 2.6 .4 .1 .7-.8 1.7-4.2 .2-.1-1.9 .4-1.5z' },
|
||||
TG: { name: 'Togo', path: 'M502.5 285.4l-.4 1.4 .9 .9 1 1 .1 1.3 .5 .6-.1 6.4 .7 2-2.3 .6-.6-1-.7-1.8-.2-1.4 .6-2.5-.7-1-.3-2.2 0-2.1-1.1-1.4 .2-.9z' },
|
||||
TH: {
|
||||
name: 'Thailand',
|
||||
path: 'M792.3 276.1l-2.6-.4-3.6 .6-1.8 2.3 .7 3.4-2.5-1.3-2.4 .1 .4-2.2-2.5 0-.2 3.1-1.5 4.1-.9 2.5 .2 2 1.8 .1 1.2 2.5 .5 2.5 1.5 1.6 1.7 .3 1.4 1.4-.9 1.2-1.8 .3-.2-1.4-2.3-1.2-.5 .5-1.1-1.1-.5-1.4-1.4-1.6-1.4-1.3-.4 1.6-.6-1.5 .3-1.8 .9-2.6 1.3-2.9 1.5-2.6-1.1-2.6 .1-1.3-.3-1.6-1.9-2.3-.6-1.4 .9-.5 1-2.5-1.1-1.9-1.8-2.1-1.3-2.5 1.2-.5 1.2-3.1 2-.1 1.6-1.3 1.6-.7 1.2 .9 .2 1.8 1.8 .1-.6 3 0 2.6 2.9-1.7 .9 .5 1.6-.1 .6-1 2.1 .2 2.1 2.3 .2 2.9 2.2 2.4-.1 2.4z',
|
||||
},
|
||||
TJ: { name: 'Tajikistan', path: 'M688.4 207.9l1.6-3.3-.6-2.4-2.1-.7 .8-1.5 2.3 .2 1.3-1.8 .9-2.1 3.7-.8-.6 1.5 .4 .9 1.2 0-1.1 1-3-.6-.2 1.9 3-.3 3.4 1.1 5.3-.5 .7 3 .9-.3 1.7 .7-.1 1.3 .4 1.8-2.9 0-1.9-.2-1.7 1.4-1.3 .3-.9 .7-1.1-1.1 .2-2.6-.8-.2 .3-1-1.5-.7-1.2 1.1-.3 1.3-.4 .5-1.7-.1-.9 1.5-.9-.6-2 1z' },
|
||||
TL: { name: 'Timor-Leste', path: 'M847.1 340.8l.4-.7 2.4-.6 1.9-.1 .9-.3 1 .3-1 .8-2.9 1.2-2.3 .8-.1-.8z' },
|
||||
TM: {
|
||||
name: 'Turkmenistan',
|
||||
path: 'M645.8 192.8l1.3-1.1 3.1-.7 1.9 .9 1.9 2.6 1.5-.2 3.1 0-.5-1.7 2.4-1.1 2.4-2 3.7 1.8 .3 2.7 1.1 .6 3-.1 .9 .6 1.4 3.4 3.1 2.2 1.9 1.6 2.9 1.6 3.7 1.3-.1 2-.9-.1-1.3-.9-.4 1.2-2.3 .6-.6 2.5-1.6 1-2.2 .5-.5 1.4-2.1 .4-2.9-1.2-.2-2.6-2.1-.1-3.2-2.9-2.2-.3-3-1.6-2-.3-1.2 .6-1.9-.1-2 1.8-2.4 .6-.5-2.2 .4-3.4-2.2-1.1 .7-2.3-1.8-.2 .6-2.7 2.6 .8 2.4-1.1-2-2-.8-1.9-2.2 .9-.3 2.4z',
|
||||
},
|
||||
TN: { name: 'Tunisia', path: 'M526.3 229.2l-1.1-5.5-1.8-1.2 0-.8-2.3-1.8-.2-2.4 1.7-1.7 .7-2.6-.5-3 .6-1.7 3-1.3 2 .4-.1 1.6 2.3-1.1 .2 .6-1.4 1.5 0 1.5 1 .8-.4 2.7-1.8 1.6 .5 1.7 1.5 .1 .7 1.4 1 .5-.1 2.4-1.4 .9-.9 1-1.9 1.2 .3 1.2-.2 1.3z' },
|
||||
TR: {
|
||||
name: 'Turkey',
|
||||
path: 'M624.4 207.8l-1.4 .6-.9-.9-3.3-.4-1.2 .5-3.1 .5-1.5 0-3.2 1.2-2.3 0-1.5-.6-3 .9-.9-.7-.2 1.8-.7 .7-.8 .7-1-1.4 1-1.2-1.6 .2-2.4-.7-1.9 1.8-4.2 .4-2.2-1.7-3-.1-.7 1.3-1.9 .4-2.7-1.7-3 0-1.7-3.1-2-1.8 1.4-2.5-1.8-1.6 3.1-3.1 4.3-.2 1.1-2.5 5.3 .5 3.4-2.2 3.2-.9 4.6-.1 4.8 2.4 4 1.2 3.3-.5 2.3 .3 3.3-1.7 3-.2 2.7 1.7 .4 1.1-.2 1.6 2 .8 1.1 1-1.9 .9 .9 3.7-.6 1zM572.5 192.6l2.9-1 2.4 .4 .3 1.3 2.4 1.1-.5 .8-3.3 .2-1.2 1-2.3 1.8-.9-1.6 .1-.7 .6-.3 .9-2.1z',
|
||||
},
|
||||
TT: { name: 'Trinidad and Tobago', path: 'M328.7 286l1.6-.3 .5 .1-.1 2.1-2.3 .3-.5-.3 .8-.8z' },
|
||||
TW: { name: 'Taiwan', path: 'M838.3 246.9l-1.7 4.7-1.2 2.4-1.5-2.4-.3-2.2 1.7-2.9 2.2-2.2 1.3 .8z' },
|
||||
TZ: {
|
||||
name: 'Tanzania',
|
||||
path: 'M594.2 318.7l.4 .3 10.1 5.6 .2 1.7 4 2.7-1.3 3.5 .2 1.6 1.8 1 0 .7-.7 1.7 .1 .8-.1 1.4 .9 1.7 1.2 2.8 1 .6-2.2 1.6-3.1 1.1-1.6 0-1 .8-1.9 .1-.8 .3-3.3-.8-2.1 .3-.8-3.8-.9-1.4-.6-.7-2.7-.5-1.6-.9-1.7-.5-1.2-.4-1.1-.7-1.5-3.6-1.6-1.5-.6-1.6 .3-1.5-.5-2.6 1.1-.1 1.1-1 1-1.4 .7-.6 0-.9-.6-.7-.2-1.1 .8-.3 .2-1.6-1.1-1.6 1-.3 3 0z',
|
||||
},
|
||||
UA: {
|
||||
name: 'Ukraine',
|
||||
path: 'M588.3 156.5l1 .2 .7-.9 .9 .2 2.9-.3 1.7 2.1-.7 .7 .3 1.2 2.2 .2 1 1.5-.1 .8 3.5 1.2 2.2-.5 1.7 1.7 1.6-.1 4.1 1.2 0 1.1-1.1 1.8 .6 2-.4 1.2-2.7 .2-1.4 1-.1 1.6-2.2 .3-1.9 1.1-2.6 .2-2.4 1.3 .2 1.9-.5-.2-.3-.6-.9-.2-2-.7-.7 .8-.4-.3-4.3-.9-.2-1.3-2.6 .4-1 1.9-2.2 2.6-1.2-.6-1.3 .6-1.3-.7 .7-.4 .5-1.1 .8-1.2-.2-.6 .6-.3 .2 .5 1.7 .1 .7-.2-.5-.4 .2-.5-1-.9-.4-1.5-1-.5 .2-1.2-1.3-1-1.1-.1-2-1.1-1.9 .3-.7 .5-1.1 0-.7 .9-2.1 .3-.9 .6-1.3-.9-1.8 0-1.7-.4-1.2 .7-.2-.9-1.6-1 .6-1.4 .8-.9 .6 .2-.7-1.6 2.5-3.1 1.4-.4 .2-1-1.3-3.2 1.3-.2 1.5-1 2.2 0 2.8 .2 3.1 .9 2.1 .1 1.1 .5 1-.6 .8 .9 2.5-.2 1.1 .3 .2-1.8 .8-.8z',
|
||||
},
|
||||
UG: { name: 'Uganda', path: 'M594.2 318.7l-5.7 .2-3 0-1 .3-1.7 .8-.6-.2 0-2.1 .6-1.1 .2-2.2 .6-1.3 1-1.5 1.1-.7 .9-1-1.1-.4 .1-3.2 1.2-.8 1.8 .7 2.2-.7 2 0 1.7-1.3 1.3 2 .3 1.4 1.2 3.1-1 2.1-1.4 1.8-.8 1.1z' },
|
||||
US: {
|
||||
name: 'United States',
|
||||
path: 'M158.8 167.9l7.9 0 8.2 0 2.7 0 8.5 0 8.2 0 8.3 0 8.4 0 9.4 0 9.5 0 5.8 0 0-1.4 .9 0 .5 1.9 .9 .6 1.9 .3 2.9 .5 2.6 1.1 2.3-.4 3.4 .9 .9 0 2.5-1 2.6 1.2 2.7 1.4 2.3 1.2 2.1 1.1 .3 .9 .7 .4-.2 .3 .7 .1 .6-.3 .1 .8 .6 .5 .7 0 .4 .5-.3 .6 2.9 1.6 .6 3.1 .5 3-.8 2-1.3 1.8-.6 1.2-.1 .3 .4 .5 .9 .5 .7 0 3.2-1.8 2.9-.5 3.6-1.6 .1-.4-.3-1-.4-.7 1.2-.5 2.8 0 2.5 0 .9-1.4 .3-.2 3-2.5 1.2-.6 4.3 0 5.1 0 .3-.9 .8-.2 1.2-.5 1-1.6 .9-2.7 2.1-2.6 .9 .9 1.9-.6 1.2 1 0 4.8 1.8 1.9 .5 1.1-3 1.7-2.8 1.2-3 1-1.4 2-.5 .7 0 1.8 .9 1.8 1.1 .1-.3-1.2 .9 .7-.2 1-1.9 .5-1.4-.1-2 .6-1.2 .2-1.6 .1-2.3 1 4-.6 .9 .6-3.9 1-1.8 0 .1-.4-.9 .9 .8 .2-.6 2.3-2 2.5-.2-.8-.6-.2-.9-.8 .6 1.7 .7 .6 0 1.2-.9 1.3-1.5 2.6-.3-.2 .9-2.1-1.5-1.3-.3-2.7-.5 1.4 .6 2.1-1.9-.5 2 1 .1 3.1 .8 .2 .3 1.1 .3 3.2-1.7 2.3-2.9 .9-1.8 1.9-1.4 .2-1.4 1.1-.4 1.1-3.1 2-1.5 1.4-1.3 1.9-.5 2.1 .5 2.1 1 2.6 1.2 2.2 0 1.3 1.3 3.5-.1 2-.1 1.1-.7 1.8-.8 .4-1.4-.4-.4-1.3-1.1-.6-1.4-2.6-1.3-2.3-.5-1.2 .6-2-.8-1.6-2.1-2.6-1.1-.4-2.8 1.4-.5-.2-1.4-1.4-1.7-.8-3.1 .4-2.5-.3-2.1 .2-1.2 .5 .5 .8 0 1.2 .6 .6-.6 .4-1-.4-1 .5-2-.1-2.1-1.6-2.4 .4-2.1-.7-1.7 .2-2.3 .7-2.6 2.3-2.7 1.3-1.5 1.4-.7 1.4 0 2 .1 1.5 .6 1-1.1 .1-2-.7-2.2-.9-.7-1.4-.6-2.1-1.7-1.7-.9-1.8-1.4-2.1-2-1.2-2.3 .1-1.7 2.4-2.3-.9-1.5-.9-.6-1.7-1-1.6-1.6-1.4-1.4-.9-1.1-1.1-4.8 0 0 1.3-2.2 0-5.5 0-6.3-2.2-4.2-1.5 .2-.6-3.5 .3-3.2 .3-.4-1.6-1.8-1.8-1.3-.4-.3-.9-1.6-.1-1-.9-2.6-.3-.7-.5-.3-1.7-2.7-3.2-2.3-4.4 .1-.8-1.2-1-2.2-2.7-.4-2.7-1.5-1.8 .7-2.7-.1-2.9-.9-2.5 1.1-3.2 .3-3.1 .3-3.1-.5-4.7-.8-3-.9-1.6 .4-.7 4 1.2 1.5 3.3 .7-.9-.5-2.9zM68.3 259.5l.5 .3 .5 .4 .7 1-.1 .1-1.1 .6-.9 .5-.4 .5-.7-.4 .1-.8-.4-1.1 .1-.3 .5-.5-.2-.6 .2-.2 .2 0zM66.7 257.5l-.3 .4-.9 .2-.5-.6-.3-.3 0-.1 .3-.3 1 .3zM64.6 256.3l-.1 .4-1.5-.1 .2-.4zM61 254.8l.3 .2 .8 .9-.2 .2-.2-.1-.9-.1-.4-.6-.1-.1zM57.3 253.3l.1 .7-.4 .3-.9-.5 .2-.3 .4-.2zM37.6 124l2.2 .3 .3 1.6-1.7 .7-1.9-.8-1.7-1.1zM74.4 133.9l1.8 .2 1.2 1.3-2.4 1.9-2.8 1.5-1.4-1-.4-1.9 2.5-1.4zM108.4 81.7l0 17.7-.1 24.9 2.8 .1 2.7 1.2 1.9 1.8 2.5 2.7 2.7-2.3 2.8-1.4 1.5 2.2 1.8 1.6 2.6 1.9 1.7 2.9 2.8 4.5 4.8 2.5 0 2.5-1.5 1.8-1.5-1.4-2.5-1.3-.8-3.4-3.5-3.2-1.5-3.8-2.7-.2-4.4-.1-3.3-1.2-5.7-4.2-2.7-.8-4.8-1.5-3.9 .4-5.4-2-3.4-1.7-3 .8 .5 2.9-1.5 .3-3.2 .9-2.5 1.4-3 .8-.4-2.4 1.2-4.1 3-1.3-.8-1-3.5 2.3-1.9 2.8-4 2.9 2 2-2.6 2.9-3 1.7-2.8 1.2-.7 1.8-4.3 2.1-.9 1.8-3.2 1.7-1.9-.3-2.6 1.1-2.9 1.3-2.3 1.3-4.7 1.1-.5-.7 3.1-1.8 2.7-1.2 2.9-2.1 3.5-.5 1.4-1.6 3.8-2.3 .6-.8 2.1-1.4 .5-3.1 1.4-2.4-3.2 1.2-.9-.7-1.5 1.5-1.8-2-.8 1.4-1-2-2.8 1.6-1.7 0-.3-2.4 .5-1.5-1.7-1.5-3.7 .8-2.3-2-1.9-1 0-2.3-2.1-1.8 1-2.5 2.3-2.4 1-2.2 2.2-.4 1.9 .7 2.3-2.1 2 .4 2.1-1.4-.5-2-1.6-.8 2.1-1.7-1.7 0-3 1-.8 1-2.2-1-3.9 .5-4.1-1.1-1.2-1.8-3.5-2.6 3.9-1.9 6.2-2.3 2.3 0-.4 2.3 5.9-.2-2.3-2.8-3.4-1.8-2-2.4-2.6-2-3.8-1.5 1.5-2.5 4.9-.2 3.6-2.2 .6-2.4 2.9-2.4 2.7-.6 5.2-2.2 2.6 .3 4.3-2.7 4.2 1.1 2 2.3 1.2-1 4.7 .3-.2 1.2 4.3 .8 2.8-.5 5.9 1.6 5.3 .5 2.1 .6 3.7-.8 4.3 1.5zM23 109.4l1.7 .8 1.7-.4 2.3 1.1 2.7 .6-.2 .5-2.1 .9-2.1-.9-1.1-.8-2.4 .2-.7-.4z',
|
||||
},
|
||||
UY: { name: 'Uruguay', path: 'M339.9 402.6l1.8-.3 2.8 2.3 1.1-.1 2.8 2 2.2 1.7 1.6 2.1-1.2 1.5 .7 1.7-1.2 2-3.1 1.7-2.1-.6-1.5 .3-2.5-1.3-1.9 .1-1.7-1.7 .2-2.1 .6-.6 0-3.1 .7-3.2z' },
|
||||
UZ: {
|
||||
name: 'Uzbekistan',
|
||||
path: 'M655.5 194.3l-.1-12.4 7.1-2 .5 .3 4.3 2.4 2.3 1.3 2.7 3.1 3.2-.5 4.8-.3 3.3 2.5-.2 3.4 1.4 0 .5 2.7 3.5 .1 .8 1.6 1 0 1.3-2.4 3.6-2.3 1.6-.6 .8 .3-2.3 2.1 2.1 1.3 1.9-.8 3.3 1.7-3.5 2.4-2.1-.3-1.2 0-.4-.9 .6-1.5-3.7 .8-.9 2.1-1.3 1.8-2.3-.2-.8 1.5 2.1 .7 .6 2.4-1.6 3.3-2.1-.7-1.5 0 .1-2-3.7-1.3-2.9-1.6-1.9-1.6-3.1-2.2-1.4-3.4-.9-.6-3 .1-1.1-.6-.3-2.7-3.7-1.8-2.4 2-2.4 1.1 .5 1.7z',
|
||||
},
|
||||
VE: {
|
||||
name: 'Venezuela',
|
||||
path: 'M331.3 301.6l.4 .8-1.1 1-3.1 1.1-2 .4-.8 .7-2.2-.7-2-.4-.5 .3 1.2 .7-.1 1.9 .4 1.7 2.3 .2 .2 .6-2 .8-.3 1.2-1.2 .4-2 .7-.6 .8-2.1 .2-1.6-1.4-.8-2.8-.8-1-1-.6 1.4-1.4 0-.6-.8-.8-.6-1.9 .2-2 .6-.9 .5-1.5-.9-.5-1.6 .3-2-.1-1.1 .3-2-2.4-1.6-.4-3.6 .3-.7-1-.6-.2-.1-.6 .3-1-.2-1.2-.6-.6-.4-1.3-1.4-.2 .7-1.6 .4-2 .8-1 1.1-.8 .7-1.4 1.8-.5-.1 .6-1.7 .4 1 1.2-.1 1.5-1.2 1.6 1 2.3 1.2-.2 .7-2-.9-1-.1-2.2 3.4-1.1-.4-1.3 1-.9 1 2 2 0 1.8 1.6 .1 .9 2.5 0 2.9-.3 1.6 1.3 2.1 .4 1.6-.9 0-.7 3.5-.2 3.3 0-2.4 .8 1 1.3 2.2 .2 2.1 1.4 .5 2.2 1.4 0 1.1 .6-2.2 1.7-.2 1 .9 1-.7 .6-1.7 .4 .1 1.3-.8 .8z',
|
||||
},
|
||||
VN: {
|
||||
name: 'Vietnam',
|
||||
path: 'M789.8 286.8l2.4-1.1 2.9-.2-1.2-1.7 4.7-2.2 .3-3.4-.6-1.9 .5-2.8-.7-2-2.1-2-1.8-2.5-2.3-3.4-3.3-1.7 .8-1.1 1.8-.7-1.1-2.5-3.4-.1-1.3-2.6-1.6-2.3 1.5-.7 2.2 0 2.7-.3 2.4-1.6 1.3 1.1 2.6 .5-.5 1.7 1.3 1.2 2.8 .7-3.7 2.5-2.3 2.8-.6 2 2.1 3 2.6 3.7 2.5 1.8 1.7 2.3 1.3 5.2-.4 5-2.3 1.8-3.2 1.8-2.2 2.4-3.5 2.6-1-1.8 .8-1.9z',
|
||||
},
|
||||
VU: { name: 'Vanuatu', path: 'M964.5 360.5l1.7 1.7-.9 .4-.9-1.3zM963.3 359.9l-.4-.8 0-2.1 1.3 .8 .4 2.3-.7-.3z' },
|
||||
XC: { name: 'Northern Cyprus', path: 'M590.9 214.3l.2-.1 .4-.7 2 0 2.5-.9-1.8 1.3 .2 .6-.3-.1-.6 .2-.4 0-.1 .1-.1-.3-.2-.2-.5 0-.8 .2z' },
|
||||
XK: { name: 'Kosovo', path: 'M557.2 192.5l-.2-1.2-.7-.3-.5-.9 .5-.8 .6-.2 .4-1.1 .5-.2 .4 .5 .5 .2 .4 .5 .5 .2 .5 .6 .4 0-.3 .8-.4 .4 .1 .2-.6 .2-1.6 .5-.2 .7z' },
|
||||
XS: { name: 'Somaliland', path: 'M636 284.2l0 .1-.1 1.1 0 2.8 0 1.5-1.2 1.7-2 2.4-2.3 0-9.1-3.3-1-1-1.1-1.4-1-1.5 .6-1 1-1.5 1 .5 .5 1.1 1.2 1.2 1.4 0 2.6-.7 3.1-.3 2.4-.9 1.4-.2 1-.5z' },
|
||||
YE: {
|
||||
name: 'Yemen',
|
||||
path: 'M644.4 262.6l2.2 4.8 .9 2-2 .7-.5 1.3-.1 1-2.8 1.2-4.4 1.3-2.5 2-1.2 .1-.8-.1-1.7 1.2-1.7 .5-2.4 .1-.7 .2-.6 .8-.7 .2-.4 .7-1.4-.1-.9 .4-1.9-.1-.7-1.7 0-1.5-.4-.9-.6-2.1-.8-1.1 .6-.2-.3-1.3 .4-.5-.2-1.3 1.3-.9-.3-1.2 .7-1.4 1.1 .8 .8-.3 3.2-.1 .5 .3 2.7 .3 1.1-.1 .7 .9 1.3-.5 1.9-3 2.6-1.3z',
|
||||
},
|
||||
ZA: {
|
||||
name: 'South Africa',
|
||||
path: 'M545.4 397.6l1.3-1.5 1.1 .8 .5 1.3 1.2 .3 1.8 .5 1.5-.2 2.5-1.5 0-11 .7 .4 1.7 2.8-.3 1.8 .6 1.1 2-.3 1.4-1.4 1.3-.9 .7-1.4 1.4-.7 1.1 .4 1.4 .8 2.2 .2 1.8-.7 .3-.9 .5-1.5 1.5-.2 .8-1.1 .9-2 2.5-2.1 4-2.2 1.1 0 1.3 .5 1-.3 1.4 .3 1.4 4.1 .7 2.1-.5 3.3 .2 1-1.4-.5-.8 .2-.2 .9-.8 1.1 0 1 1.7 1.6 1.6-.3 .6-1.3 2.1 0-.7 2.2-.3 2.5-.7 1.3-1.9 1.6-.6 .4-1.2 1.5-.7 1.6-1.6 2.2-3.2 3.2-1.9 1.8-2.1 1.4-2.9 1.2-1.4 .2-.4 .9-1.7-.5-1.4 .6-3-.6-1.6 .4-1.2-.2-2.9 1.3-2.3 .4-1.7 1.2-1.3 .1-1.2-1.1-.9-.1-1.2-1.4-.2 .5-.3-.9 0-1.8-.9-2.1 .9-.5-.1-2.4-1.8-2.9-1.4-2.5 0-.1zM580.5 398.8l-1.2-1-1.3 .6-1.5 1.2-1.5 1.9 2.1 2.4 1-.3 .5-1 1.5-.5 .5-1 .9-1.4z',
|
||||
},
|
||||
ZM: {
|
||||
name: 'Zambia',
|
||||
path: 'M585.4 339.3l1.1 .7 1.2 .4 1.7 .5 1.6 .9 1.3 1.2 .7 2.4-.5 .7-.5 2.3 .5 2.4-.9 .9-.8 2.7 1.5 .7-8.5 2.3 .3 2.1-2.1 .3-1.6 1.2-.3 1-1 .2-2.4 2.3-1.6 1.9-.9 .1-.9-.4-3.1-.3-.5-.2 0-.2-1.1-.7-1.8-.1-2.3 .6-1.8-1.8-1.9-2.3 .1-9 5.8 0-.2-1 .4-1-.5-1.4 .3-1.3-.3-.9 1 .1 .1 .9 1.3-.1 1.8 .2 .9 1.3 2.3 .4 1.7-.9 .6 1.5 2.1 .4 1 1.2 1.2 1.6 2.1 0-.2-3.1-.8 .5-1.9-1.1-.8-.5 .4-2.8 .4-3.3-.6-1.2 .8-1.8 .8-.4 3.7-.4z',
|
||||
},
|
||||
ZW: { name: 'Zimbabwe', path: 'M586.6 378.9l-1.4-.3-1 .3-1.3-.5-1.1 0-1.8-1.3-2.2-.5-.8-1.8 0-1-1.2-.3-3.1-3.2-.9-1.7-.6-.5-1-2.3 3.1 .3 .9 .4 .9-.1 1.6-1.9 2.4-2.3 1-.2 .3-1 1.6-1.2 2.1-.3 .2 1 2.3 0 1.3 .6 .6 .7 1.3 .2 1.4 .9 0 3.6-.5 2-.1 2.2 .4 .8-.3 1.7-.4 .3-.7 2.1z' },
|
||||
AD: { name: 'Andorra', path: 'M504.3 190.2h0', point: true },
|
||||
AG: { name: 'Antigua and Barbuda', path: 'M328.4 267.4h0', point: true },
|
||||
BB: { name: 'Barbados', path: 'M334.5 279.3h0', point: true },
|
||||
BH: { name: 'Bahrain', path: 'M640.4 242h0', point: true },
|
||||
CV: { name: 'Cabo Verde', path: 'M434.3 273.9h0', point: true },
|
||||
DM: { name: 'Dominica', path: 'M329.6 272.8h0', point: true },
|
||||
FM: { name: 'Federated States of Micronesia', path: 'M939.5 296.9h0', point: true },
|
||||
GD: { name: 'Grenada', path: 'M328.7 282.2h0', point: true },
|
||||
HK: { name: 'Hong Kong', path: 'M816.9 252.6h0', point: true },
|
||||
KI: { name: 'Kiribati', path: 'M62.8 311h0', point: true },
|
||||
KM: { name: 'Comoros', path: 'M620.3 348.8h0', point: true },
|
||||
KN: { name: 'Saint Kitts and Nevis', path: 'M325.7 267.4h0', point: true },
|
||||
LC: { name: 'Saint Lucia', path: 'M330.6 277.2h0', point: true },
|
||||
LI: { name: 'Liechtenstein', path: 'M526.6 174.6h0', point: true },
|
||||
MC: { name: 'Monaco', path: 'M520.6 186.2h0', point: true },
|
||||
MH: { name: 'Marshall Islands', path: 'M975.5 296.3h0', point: true },
|
||||
MO: { name: 'Macao', path: 'M815.4 253.6h0', point: true },
|
||||
MT: { name: 'Malta', path: 'M540.1 211.9h0', point: true },
|
||||
MU: { name: 'Mauritius', path: 'M659.9 373.2h0', point: true },
|
||||
MV: { name: 'Maldives', path: 'M704.2 304.4h0', point: true },
|
||||
NR: { name: 'Nauru', path: 'M963.7 317.5h0', point: true },
|
||||
PW: { name: 'Palau', path: 'M873.8 295.1h0', point: true },
|
||||
SC: { name: 'Seychelles', path: 'M654.1 329h0', point: true },
|
||||
SG: { name: 'Singapore', path: 'M788.4 312.2h0', point: true },
|
||||
SM: { name: 'San Marino', path: 'M534.6 185.5h0', point: true },
|
||||
ST: { name: 'São Tomé and Principe', path: 'M519.5 313.3h0', point: true },
|
||||
TO: { name: 'Tonga', path: 'M13.4 375.8h0', point: true },
|
||||
TV: { name: 'Tuvalu', path: 'M997.8 339.7h0', point: true },
|
||||
VA: { name: 'Vatican', path: 'M534.6 192.4h0', point: true },
|
||||
VC: { name: 'Saint Vincent and the Grenadines', path: 'M329.6 279.5h0', point: true },
|
||||
WS: { name: 'Samoa', path: 'M21 354.2h0', point: true },
|
||||
},
|
||||
}
|
||||
Vendored
+2
@@ -13,5 +13,7 @@ declare global {
|
||||
maplibregl?: import('./map').MapLibrary
|
||||
Sortable?: new (element: HTMLElement, options?: Record<string, unknown>) => import('./sortable').SortableInstance
|
||||
jQuery?: JQueryStaticLike
|
||||
// Filled by the map files of the VectorMap plugin (`dist/js/maps/*.js`)
|
||||
tablerVectorMaps?: Record<string, import('./vector-map').VectorMapData>
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,7 @@
|
||||
// The vector map ships as its own bundle, so pages without a map do not carry
|
||||
// it. Load it after `tabler.js`: the UMD build adds `VectorMap` to the `tabler`
|
||||
// global. The maps themselves are separate files in `dist/js/maps/`.
|
||||
import './src/vector-map'
|
||||
|
||||
export { default as VectorMap } from './src/vector-map'
|
||||
export type { VectorMapData, VectorMapLine, VectorMapMarker, VectorMapRegion, VectorMapTooltipItem } from './src/vector-map'
|
||||
@@ -0,0 +1,865 @@
|
||||
import { describe, it, expect, beforeAll, afterEach, vi } from 'vitest'
|
||||
import { clearFixture, getFixture } from '../helpers/fixture'
|
||||
import VectorMap from '../../src/vector-map'
|
||||
import type { VectorMapData } from '../../src/vector-map'
|
||||
import { world } from '../../maps/world'
|
||||
|
||||
const squares: VectorMapData = {
|
||||
width: 30,
|
||||
height: 10,
|
||||
projection: { type: 'miller', scale: 1, translate: [0, 0] },
|
||||
regions: {
|
||||
AA: { name: 'First', path: 'M0 0l10 0 0 10-10 0z' },
|
||||
BB: { name: 'Second', path: 'M10 0l10 0 0 10-10 0z' },
|
||||
CC: { name: 'Third', path: 'M20 0l10 0 0 10-10 0z' },
|
||||
},
|
||||
}
|
||||
|
||||
describe('VectorMap', () => {
|
||||
let fixtureEl: HTMLElement
|
||||
|
||||
beforeAll(() => {
|
||||
fixtureEl = getFixture()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
clearFixture()
|
||||
VectorMap.maps = {}
|
||||
delete window.tablerVectorMaps
|
||||
})
|
||||
|
||||
const el = (): HTMLElement => fixtureEl.querySelector('.vector-map')!
|
||||
const region = (code: string): SVGGeometryElement => el().querySelector<SVGGeometryElement>(`[data-region="${code}"]`)!
|
||||
const ratio = (code: string): string => region(code).style.getPropertyValue('--tblr-vector-map-value')
|
||||
|
||||
describe('NAME', () => {
|
||||
it('should return plugin name', () => {
|
||||
expect(VectorMap.NAME).toBe('vector-map')
|
||||
})
|
||||
})
|
||||
|
||||
describe('constructor', () => {
|
||||
it('should render one path per region of the map', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-map="squares"></div>'
|
||||
VectorMap.addMap('squares', squares)
|
||||
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('rendered.bs.vector-map', spy)
|
||||
new VectorMap(el())
|
||||
|
||||
const svg = el().querySelector('svg')!
|
||||
expect(svg.getAttribute('viewBox')).toBe('0 0 30 10')
|
||||
expect(svg.querySelectorAll('path.vector-map-region').length).toBe(3)
|
||||
expect(region('BB').getAttribute('d')).toBe(squares.regions.BB.path)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('should take the map as an object', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(el().querySelectorAll('path').length).toBe(3)
|
||||
})
|
||||
|
||||
it('should find a map loaded with a script tag', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-map="squares"></div>'
|
||||
window.tablerVectorMaps = { squares }
|
||||
|
||||
new VectorMap(el())
|
||||
|
||||
expect(el().querySelectorAll('path').length).toBe(3)
|
||||
})
|
||||
|
||||
it('should throw when the map is not loaded', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-map="nowhere"></div>'
|
||||
|
||||
expect(() => new VectorMap(el())).toThrowError('VECTOR-MAP: Map "nowhere" is not loaded.')
|
||||
})
|
||||
|
||||
it('should name the map for assistive technology when it has a label', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-label="Sales by country"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
const svg = el().querySelector('svg')!
|
||||
expect(svg.getAttribute('role')).toBe('img')
|
||||
expect(svg.getAttribute('aria-label')).toBe('Sales by country')
|
||||
expect(svg.hasAttribute('aria-hidden')).toBe(false)
|
||||
})
|
||||
|
||||
it('should hide the map from assistive technology without a label', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(el().querySelector('svg')!.getAttribute('aria-hidden')).toBe('true')
|
||||
})
|
||||
})
|
||||
|
||||
describe('values', () => {
|
||||
it('should shade regions by their place between the lowest and highest value', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-values='{"AA": 10, "BB": 20, "CC": 50}'></div>`
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(region('AA').getAttribute('data-value')).toBe('10')
|
||||
expect(ratio('AA')).toBe('0')
|
||||
expect(ratio('BB')).toBe('0.25')
|
||||
expect(ratio('CC')).toBe('1')
|
||||
})
|
||||
|
||||
it('should leave a region without a value untouched', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 1, ZZ: 5 } })
|
||||
|
||||
expect(region('BB').hasAttribute('data-value')).toBe(false)
|
||||
expect(ratio('BB')).toBe('')
|
||||
})
|
||||
|
||||
it('should use the forced range and clamp values outside of it', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-min="0" data-bs-max="100"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 25, BB: 150, CC: -10 } })
|
||||
|
||||
expect(ratio('AA')).toBe('0.25')
|
||||
expect(ratio('BB')).toBe('1')
|
||||
expect(ratio('CC')).toBe('0')
|
||||
})
|
||||
|
||||
it('should give the full colour when all values are equal', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 7, BB: 7 } })
|
||||
|
||||
expect(ratio('AA')).toBe('1')
|
||||
expect(ratio('BB')).toBe('1')
|
||||
})
|
||||
|
||||
it('should ignore values that are not a number', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-values='{"AA": 10, "BB": null, "CC": "many"}'></div>`
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(region('AA').hasAttribute('data-value')).toBe(true)
|
||||
expect(region('BB').hasAttribute('data-value')).toBe(false)
|
||||
expect(region('CC').hasAttribute('data-value')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('update', () => {
|
||||
it('should replace the values without drawing the map again', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-values='{"AA": 10, "BB": 20}'></div>`
|
||||
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
const svg = el().querySelector('svg')
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('updated.bs.vector-map', spy)
|
||||
|
||||
map.update({ BB: 1, CC: 3 })
|
||||
|
||||
expect(el().querySelector('svg')).toBe(svg)
|
||||
expect(region('AA').hasAttribute('data-value')).toBe(false)
|
||||
expect(ratio('AA')).toBe('')
|
||||
expect(ratio('BB')).toBe('0')
|
||||
expect(ratio('CC')).toBe('1')
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('colors', () => {
|
||||
const colorVar = (index: number): string => el().style.getPropertyValue(`--tblr-vector-map-color-${index}`)
|
||||
|
||||
it('should hand a scale of colors to the stylesheet', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-colors='["red", "yellow", "green"]'></div>`
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 1, BB: 2, CC: 3 } })
|
||||
|
||||
expect(el().classList.contains('vector-map-colors')).toBe(true)
|
||||
expect(el().style.getPropertyValue('--tblr-vector-map-colors')).toBe('3')
|
||||
expect(colorVar(1)).toBe('red')
|
||||
expect(colorVar(2)).toBe('yellow')
|
||||
expect(colorVar(3)).toBe('green')
|
||||
expect(colorVar(4)).toBe('')
|
||||
// The share of a region stays the same, only the stylesheet reads it differently
|
||||
expect(ratio('BB')).toBe('0.5')
|
||||
})
|
||||
|
||||
it('should keep the single color with fewer than two colors', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, colors: ['red'] })
|
||||
|
||||
expect(el().classList.contains('vector-map-colors')).toBe(false)
|
||||
expect(el().style.getPropertyValue('--tblr-vector-map-colors')).toBe('')
|
||||
expect(colorVar(1)).toBe('')
|
||||
})
|
||||
|
||||
it('should use the first five colors', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, colors: ['#111', '#222', '#333', '#444', '#555', '#666'] })
|
||||
|
||||
expect(el().style.getPropertyValue('--tblr-vector-map-colors')).toBe('5')
|
||||
expect(colorVar(5)).toBe('#555')
|
||||
expect(colorVar(6)).toBe('')
|
||||
})
|
||||
|
||||
it('should drop the scale when render() no longer has one, and on dispose', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-colors='["red", "green"]'></div>`
|
||||
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
el().removeAttribute('data-bs-colors')
|
||||
map.render()
|
||||
|
||||
expect(el().classList.contains('vector-map-colors')).toBe(false)
|
||||
expect(colorVar(1)).toBe('')
|
||||
|
||||
el().setAttribute('data-bs-colors', '["red", "green"]')
|
||||
map.render()
|
||||
expect(colorVar(2)).toBe('green')
|
||||
|
||||
map.dispose()
|
||||
expect(el().classList.contains('vector-map-colors')).toBe(false)
|
||||
expect(colorVar(2)).toBe('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('click', () => {
|
||||
it('should fire regionclick with the code, the name and the value of the region', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
new VectorMap(el(), { map: squares, values: { AA: 5 } })
|
||||
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('regionclick.bs.vector-map', spy)
|
||||
region('AA').dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
region('BB').dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
|
||||
expect(spy).toHaveBeenCalledTimes(2)
|
||||
expect(spy.mock.calls[0][0]).toMatchObject({ code: 'AA', name: 'First', value: 5, relatedTarget: region('AA') })
|
||||
expect(spy.mock.calls[1][0]).toMatchObject({ code: 'BB', name: 'Second' })
|
||||
expect('value' in spy.mock.calls[1][0]).toBe(false)
|
||||
})
|
||||
|
||||
it('should fire markerclick with the marker, and no regionclick', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
new VectorMap(el(), {
|
||||
map: squares,
|
||||
markers: [
|
||||
{ name: 'One', lat: 0, lng: 0 },
|
||||
{ name: 'Two', lat: 1, lng: 2 },
|
||||
],
|
||||
})
|
||||
|
||||
const markerSpy = vi.fn()
|
||||
const regionSpy = vi.fn()
|
||||
el().addEventListener('markerclick.bs.vector-map', markerSpy)
|
||||
el().addEventListener('regionclick.bs.vector-map', regionSpy)
|
||||
el()
|
||||
.querySelectorAll('.vector-map-marker-dot')[1]
|
||||
.dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
|
||||
expect(markerSpy.mock.calls[0][0]).toMatchObject({ name: 'Two', lat: 1, lng: 2 })
|
||||
expect(regionSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not take the click that ends a drag for a click on a region', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 300px" data-bs-zoom="true"></div>'
|
||||
new VectorMap(el(), { map: squares, zoomMax: 2 })
|
||||
el().dispatchEvent(new WheelEvent('wheel', { bubbles: true, cancelable: true, deltaY: -5000 }))
|
||||
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('regionclick.bs.vector-map', spy)
|
||||
const pointer = (type: string, x: number): void => {
|
||||
region('BB').dispatchEvent(new PointerEvent(type, { bubbles: true, pointerId: 1, pointerType: 'mouse', button: 0, clientX: x, clientY: 50 }))
|
||||
}
|
||||
|
||||
pointer('pointerdown', 100)
|
||||
pointer('pointermove', 60)
|
||||
pointer('pointerup', 60)
|
||||
region('BB').dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
|
||||
// A press that moves by a pixel or two is still a click
|
||||
const viewBox = el().querySelector('svg')!.getAttribute('viewBox')
|
||||
pointer('pointerdown', 100)
|
||||
pointer('pointermove', 102)
|
||||
pointer('pointerup', 102)
|
||||
region('BB').dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(el().querySelector('svg')!.getAttribute('viewBox')).toBe(viewBox)
|
||||
})
|
||||
})
|
||||
|
||||
describe('select', () => {
|
||||
const click = (code: string): void => {
|
||||
region(code).dispatchEvent(new MouseEvent('click', { bubbles: true }))
|
||||
}
|
||||
|
||||
const isSelected = (code: string): boolean => region(code).classList.contains('vector-map-region-selected')
|
||||
|
||||
it('should not select anything by default', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
const map = new VectorMap(el(), { map: squares, selected: ['AA'] })
|
||||
|
||||
click('BB')
|
||||
|
||||
expect(map.getSelected()).toEqual([])
|
||||
expect(isSelected('AA')).toBe(false)
|
||||
expect(el().classList.contains('vector-map-selectable')).toBe(false)
|
||||
})
|
||||
|
||||
it('should select one region at a time, and take it out on a second click', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-select="single"></div>'
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('selected.bs.vector-map', spy)
|
||||
|
||||
expect(el().classList.contains('vector-map-selectable')).toBe(true)
|
||||
|
||||
click('AA')
|
||||
expect(map.getSelected()).toEqual(['AA'])
|
||||
expect(isSelected('AA')).toBe(true)
|
||||
expect(spy.mock.calls[0][0]).toMatchObject({ selected: ['AA'], code: 'AA' })
|
||||
|
||||
click('BB')
|
||||
expect(map.getSelected()).toEqual(['BB'])
|
||||
expect(isSelected('AA')).toBe(false)
|
||||
|
||||
click('BB')
|
||||
expect(map.getSelected()).toEqual([])
|
||||
expect(spy).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
|
||||
it('should select several regions', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-select="multiple" data-bs-selected='["CC", "ZZ"]'></div>`
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(map.getSelected()).toEqual(['CC'])
|
||||
|
||||
click('AA')
|
||||
expect(map.getSelected()).toEqual(['CC', 'AA'])
|
||||
|
||||
click('CC')
|
||||
expect(map.getSelected()).toEqual(['AA'])
|
||||
expect(isSelected('CC')).toBe(false)
|
||||
})
|
||||
|
||||
it('should keep the first of several codes when one region can be selected', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
const map = new VectorMap(el(), { map: squares, select: 'single', selected: ['BB', 'CC'] })
|
||||
|
||||
expect(map.getSelected()).toEqual(['BB'])
|
||||
})
|
||||
|
||||
it('should not select when regionclick is prevented', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-select="single"></div>'
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
el().addEventListener('regionclick.bs.vector-map', (event) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
click('AA')
|
||||
|
||||
expect(map.getSelected()).toEqual([])
|
||||
})
|
||||
|
||||
it('should set the selection from code', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-select="multiple"></div>'
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
const spy = vi.fn()
|
||||
el().addEventListener('selected.bs.vector-map', spy)
|
||||
|
||||
map.setSelected(['AA', 'CC', 'nowhere'])
|
||||
expect(map.getSelected()).toEqual(['AA', 'CC'])
|
||||
expect(spy.mock.calls[0][0]).toMatchObject({ selected: ['AA', 'CC'] })
|
||||
|
||||
map.setSelected([])
|
||||
expect(isSelected('AA')).toBe(false)
|
||||
})
|
||||
|
||||
it('should draw a selected shape after the other shapes, under the markers', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-select="single"></div>'
|
||||
new VectorMap(el(), { map: squares, markers: [{ name: 'One', lat: 0, lng: 0 }] })
|
||||
|
||||
click('AA')
|
||||
|
||||
const children = [...el().querySelector('svg')!.children]
|
||||
expect(children.indexOf(region('AA'))).toBeGreaterThan(children.indexOf(region('CC')))
|
||||
expect(children.indexOf(region('AA'))).toBeLessThan(children.indexOf(el().querySelector('.vector-map-marker')!))
|
||||
})
|
||||
|
||||
it('should keep the selection over update() and render()', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-select="single"></div>'
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
|
||||
click('BB')
|
||||
map.update({ AA: 1 })
|
||||
map.render()
|
||||
|
||||
expect(map.getSelected()).toEqual(['BB'])
|
||||
expect(isSelected('BB')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('legend', () => {
|
||||
const legend = (): HTMLElement | null => el().querySelector<HTMLElement>('.vector-map-legend')
|
||||
const labels = (): string[] => [...el().querySelectorAll('.vector-map-legend-label')].map((label) => label.textContent ?? '')
|
||||
const steps = (): HTMLElement[] => [...el().querySelectorAll<HTMLElement>('.vector-map-legend-step')]
|
||||
|
||||
it('should not be there by default', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 1, BB: 2 } })
|
||||
|
||||
expect(legend()).toBeNull()
|
||||
})
|
||||
|
||||
it('should show the lowest and the highest value around a bar that runs over the whole scale', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-legend="true"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 10, BB: 20, CC: 1500 } })
|
||||
|
||||
expect(labels()).toEqual(['10', (1500).toLocaleString()])
|
||||
expect(steps().length).toBeGreaterThan(10)
|
||||
expect(steps()[0].style.getPropertyValue('--tblr-vector-map-value')).toBe('0')
|
||||
expect(steps().at(-1)!.style.getPropertyValue('--tblr-vector-map-value')).toBe('1')
|
||||
expect(el().querySelector('.vector-map-legend-scale')!.getAttribute('aria-hidden')).toBe('true')
|
||||
// The legend comes after the drawing
|
||||
expect(el().lastElementChild).toBe(legend())
|
||||
})
|
||||
|
||||
it('should use the forced range', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-legend="true" data-bs-min="0" data-bs-max="100"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 25 } })
|
||||
|
||||
expect(labels()).toEqual(['0', '100'])
|
||||
})
|
||||
|
||||
it('should format the labels with a function', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 5, BB: 80 }, legend: (value) => `${value}%` })
|
||||
|
||||
expect(labels()).toEqual(['5%', '80%'])
|
||||
})
|
||||
|
||||
it('should follow the values on update(), with one legend at all times', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-legend="true"></div>'
|
||||
|
||||
const map = new VectorMap(el(), { map: squares, values: { AA: 1, BB: 2 } })
|
||||
map.update({ AA: 3, CC: 9 })
|
||||
|
||||
expect(labels()).toEqual(['3', '9'])
|
||||
expect(el().querySelectorAll('.vector-map-legend').length).toBe(1)
|
||||
})
|
||||
|
||||
it('should stay away when the map has no values, and go on dispose', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-legend="true"></div>'
|
||||
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
expect(legend()).toBeNull()
|
||||
|
||||
map.update({ AA: 1 })
|
||||
expect(legend()).not.toBeNull()
|
||||
|
||||
map.dispose()
|
||||
expect(legend()).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('points', () => {
|
||||
const islands: VectorMapData = {
|
||||
...squares,
|
||||
regions: { ZZ: { name: 'Island', path: 'M15 5h0', point: true }, ...squares.regions },
|
||||
}
|
||||
|
||||
it('should draw a region that is a point as a dot with a ring, on top of the shapes', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: islands })
|
||||
|
||||
const point = region('ZZ')
|
||||
expect(point.tagName).toBe('g')
|
||||
expect(point.classList.contains('vector-map-region-point')).toBe(true)
|
||||
expect(point.querySelector('.vector-map-region-point-halo')!.getAttribute('d')).toBe('M15 5h0')
|
||||
expect(point.querySelector('.vector-map-region-point-dot')!.getAttribute('d')).toBe('M15 5h0')
|
||||
expect(el().querySelector('svg')!.lastElementChild).toBe(point)
|
||||
})
|
||||
|
||||
it('should give a point a value and a tooltip like any region', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: islands, values: { AA: 1, ZZ: 3 } })
|
||||
|
||||
expect(region('ZZ').getAttribute('data-value')).toBe('3')
|
||||
expect(ratio('ZZ')).toBe('1')
|
||||
|
||||
region('ZZ')
|
||||
.querySelector('.vector-map-region-point-dot')!
|
||||
.dispatchEvent(new PointerEvent('pointermove', { bubbles: true }))
|
||||
expect(el().querySelector('.vector-map-tooltip')!.textContent).toBe('Island: 3')
|
||||
})
|
||||
})
|
||||
|
||||
describe('markers', () => {
|
||||
it('should place a marker by its coordinates', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-markers='[{"name": "Null Island", "lat": 0, "lng": 0}]'></div>`
|
||||
|
||||
new VectorMap(el(), { map: world })
|
||||
|
||||
const marker = el().querySelector('.vector-map-marker')!
|
||||
expect(marker.getAttribute('data-marker')).toBe('Null Island')
|
||||
expect(marker.querySelector('.vector-map-marker-halo')!.getAttribute('d')).toBe('M500 316h0')
|
||||
expect(marker.querySelector('.vector-map-marker-dot')!.getAttribute('d')).toBe('M500 316h0')
|
||||
})
|
||||
|
||||
it('should put a marker inside the country it belongs to', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 500px"></div>'
|
||||
|
||||
new VectorMap(el(), { map: world, markers: [{ name: 'Warsaw', lat: 52.23, lng: 21.01 }] })
|
||||
|
||||
const [x, y] = el().querySelector('.vector-map-marker-dot')!.getAttribute('d')!.slice(1, -2).split(' ').map(Number)
|
||||
const svg = el().querySelector('svg')!
|
||||
const point = svg.createSVGPoint()
|
||||
point.x = x
|
||||
point.y = y
|
||||
expect(region('PL').isPointInFill(point)).toBe(true)
|
||||
expect(region('DE').isPointInFill(point)).toBe(false)
|
||||
})
|
||||
|
||||
it('should leave out a marker without real coordinates', () => {
|
||||
fixtureEl.innerHTML = `<div class="vector-map" data-bs-markers='[{"name": "A", "lat": 1, "lng": 2}, {"name": "B", "lat": "north"}, null]'></div>`
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
expect(el().querySelectorAll('.vector-map-marker').length).toBe(1)
|
||||
})
|
||||
|
||||
it('should draw a curve between two markers, under the markers', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), {
|
||||
map: world,
|
||||
markers: [
|
||||
{ name: 'A', lat: 0, lng: 0 },
|
||||
{ name: 'B', lat: 0, lng: 90 },
|
||||
],
|
||||
lines: [{ from: 'A', to: 'B' }],
|
||||
})
|
||||
|
||||
const line = el().querySelector('.vector-map-line')!
|
||||
expect(line.getAttribute('d')).toBe('M500 316Q625 266 750 316')
|
||||
expect(line.compareDocumentPosition(el().querySelector('.vector-map-marker')!) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should skip a line to a marker that does not exist', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, markers: [{ name: 'A', lat: 0, lng: 0 }], lines: [{ from: 'A', to: 'Nowhere' }] })
|
||||
|
||||
expect(el().querySelector('.vector-map-line')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('tooltip', () => {
|
||||
const tooltip = (): HTMLElement | null => el().querySelector<HTMLElement>('.vector-map-tooltip')
|
||||
const moveOver = (target: Element): void => {
|
||||
target.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, clientX: 10, clientY: 10 }))
|
||||
}
|
||||
|
||||
it('should show the name of the region under the pointer, with its value', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, values: { AA: 5 } })
|
||||
expect(tooltip()).toBeNull()
|
||||
|
||||
moveOver(region('AA'))
|
||||
expect(tooltip()!.textContent).toBe('First: 5')
|
||||
expect(tooltip()!.hidden).toBe(false)
|
||||
|
||||
moveOver(region('BB'))
|
||||
expect(tooltip()!.textContent).toBe('Second')
|
||||
expect(el().querySelectorAll('.vector-map-tooltip').length).toBe(1)
|
||||
})
|
||||
|
||||
it('should show the name of a marker', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares, markers: [{ name: 'Capital', lat: 0, lng: 0 }] })
|
||||
moveOver(el().querySelector('.vector-map-marker-dot')!)
|
||||
|
||||
expect(tooltip()!.textContent).toBe('Capital')
|
||||
})
|
||||
|
||||
it('should hide when the pointer leaves the map', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
moveOver(region('AA'))
|
||||
el().dispatchEvent(new PointerEvent('pointerleave'))
|
||||
|
||||
expect(tooltip()!.hidden).toBe(true)
|
||||
})
|
||||
|
||||
it('should not show when turned off', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" data-bs-tooltip="false"></div>'
|
||||
|
||||
new VectorMap(el(), { map: squares })
|
||||
moveOver(region('AA'))
|
||||
|
||||
expect(tooltip()).toBeNull()
|
||||
})
|
||||
|
||||
it('should take the text from a function, as plain text', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
new VectorMap(el(), {
|
||||
map: squares,
|
||||
values: { AA: 5 },
|
||||
tooltip: (item) => (item.type === 'region' && item.value !== undefined ? `<b>${item.code}</b> ${item.value} %` : ''),
|
||||
})
|
||||
|
||||
moveOver(region('AA'))
|
||||
expect(tooltip()!.textContent).toBe('<b>AA</b> 5 %')
|
||||
expect(tooltip()!.querySelector('b')).toBeNull()
|
||||
|
||||
moveOver(region('BB'))
|
||||
expect(tooltip()!.hidden).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('zoom', () => {
|
||||
const svg = (): SVGSVGElement => el().querySelector<SVGSVGElement>('.vector-map-svg')!
|
||||
const viewBox = (): number[] => svg().getAttribute('viewBox')!.split(' ').map(Number)
|
||||
const button = (action: string): HTMLButtonElement => el().querySelector<HTMLButtonElement>(`[data-bs-vector-map-action="${action}"]`)!
|
||||
const pointer = (type: string, x: number, y: number, pointerId = 1): void => {
|
||||
region('BB').dispatchEvent(new PointerEvent(type, { bubbles: true, pointerId, pointerType: 'mouse', button: 0, clientX: x, clientY: y }))
|
||||
}
|
||||
|
||||
const wheel = (deltaY: number, target: Element = region('BB')): WheelEvent => {
|
||||
const rect = target.getBoundingClientRect()
|
||||
const event = new WheelEvent('wheel', { bubbles: true, cancelable: true, deltaY, clientX: rect.left + rect.width / 2, clientY: rect.top + rect.height / 2 })
|
||||
target.dispatchEvent(event)
|
||||
return event
|
||||
}
|
||||
|
||||
const zoomable = (config = {}): VectorMap => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 300px" data-bs-zoom="true"></div>'
|
||||
return new VectorMap(el(), { map: squares, ...config })
|
||||
}
|
||||
|
||||
it('should not react to the wheel or add buttons by default', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 300px"></div>'
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
const event = wheel(-500)
|
||||
|
||||
expect(event.defaultPrevented).toBe(false)
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
expect(el().querySelector('.vector-map-controls')).toBeNull()
|
||||
expect(el().classList.contains('vector-map-zoomable')).toBe(false)
|
||||
})
|
||||
|
||||
it('should add labelled buttons, with zoom out disabled on the whole map', () => {
|
||||
zoomable({ zoomInLabel: 'Closer' })
|
||||
|
||||
expect(el().classList.contains('vector-map-zoomable')).toBe(true)
|
||||
expect(button('zoom-in').getAttribute('aria-label')).toBe('Closer')
|
||||
expect(button('zoom-out').getAttribute('aria-label')).toBe('Zoom out')
|
||||
expect(button('zoom-in').disabled).toBe(false)
|
||||
expect(button('zoom-out').disabled).toBe(true)
|
||||
})
|
||||
|
||||
it('should zoom with the wheel around the pointer and keep the page from scrolling', () => {
|
||||
zoomable()
|
||||
|
||||
// exp(500 * 0.002) is a little under 3 times
|
||||
const event = wheel(-500)
|
||||
|
||||
expect(event.defaultPrevented).toBe(true)
|
||||
const [x, y, width, height] = viewBox()
|
||||
expect(width).toBeCloseTo(30 / Math.E, 1)
|
||||
expect(height).toBeCloseTo(10 / Math.E, 1)
|
||||
// The middle of the map was under the pointer, so it is still in the middle
|
||||
expect(x + width / 2).toBeCloseTo(15, 0)
|
||||
expect(y + height / 2).toBeCloseTo(5, 0)
|
||||
expect(button('zoom-out').disabled).toBe(false)
|
||||
})
|
||||
|
||||
it('should leave the wheel alone with zoomOnScroll off', () => {
|
||||
zoomable({ zoomOnScroll: false })
|
||||
|
||||
expect(wheel(-500).defaultPrevented).toBe(false)
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
})
|
||||
|
||||
it('should stop at the largest zoom and at the whole map', () => {
|
||||
zoomable({ zoomMax: 2 })
|
||||
|
||||
wheel(-5000)
|
||||
expect(viewBox()[2]).toBe(15)
|
||||
expect(button('zoom-in').disabled).toBe(true)
|
||||
|
||||
wheel(5000)
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
})
|
||||
|
||||
it('should zoom in steps with the buttons', async () => {
|
||||
zoomable()
|
||||
|
||||
button('zoom-in').click()
|
||||
await vi.waitFor(() => {
|
||||
expect(viewBox()).toEqual([7.5, 2.5, 15, 5])
|
||||
})
|
||||
|
||||
button('zoom-out').click()
|
||||
await vi.waitFor(() => {
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
})
|
||||
})
|
||||
|
||||
it('should zoom in on a double click', async () => {
|
||||
zoomable()
|
||||
|
||||
region('AA').dispatchEvent(new MouseEvent('dblclick', { bubbles: true, clientX: el().getBoundingClientRect().left, clientY: el().getBoundingClientRect().top }))
|
||||
|
||||
// The top left corner was under the pointer, so it stays in the corner
|
||||
await vi.waitFor(() => {
|
||||
expect(viewBox()).toEqual([0, 0, 15, 5])
|
||||
})
|
||||
})
|
||||
|
||||
it('should go back to the whole map on reset', async () => {
|
||||
const map = zoomable()
|
||||
wheel(-500)
|
||||
|
||||
map.reset()
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
})
|
||||
})
|
||||
|
||||
it('should drag the map with a pointer, but never out of sight', () => {
|
||||
zoomable({ zoomMax: 2 })
|
||||
wheel(-5000)
|
||||
expect(viewBox()).toEqual([7.5, 2.5, 15, 5])
|
||||
|
||||
// 300px show 15 units, so 40px is 2 units
|
||||
pointer('pointerdown', 100, 50)
|
||||
pointer('pointermove', 60, 50)
|
||||
expect(viewBox()).toEqual([9.5, 2.5, 15, 5])
|
||||
expect(el().classList.contains('vector-map-dragging')).toBe(true)
|
||||
|
||||
pointer('pointermove', -1000, 50)
|
||||
expect(viewBox()).toEqual([15, 2.5, 15, 5])
|
||||
|
||||
pointer('pointerup', -1000, 50)
|
||||
expect(el().classList.contains('vector-map-dragging')).toBe(false)
|
||||
|
||||
pointer('pointermove', 0, 50)
|
||||
expect(viewBox()).toEqual([15, 2.5, 15, 5])
|
||||
})
|
||||
|
||||
it('should not drag a map that cannot be zoomed', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 300px"></div>'
|
||||
new VectorMap(el(), { map: squares })
|
||||
|
||||
pointer('pointerdown', 100, 50)
|
||||
pointer('pointermove', 60, 50)
|
||||
|
||||
expect(el().classList.contains('vector-map-dragging')).toBe(false)
|
||||
})
|
||||
|
||||
it('should zoom when two pointers move apart', () => {
|
||||
zoomable()
|
||||
const rect = el().getBoundingClientRect()
|
||||
const y = rect.top + 50
|
||||
|
||||
pointer('pointerdown', rect.left + 140, y, 1)
|
||||
pointer('pointerdown', rect.left + 160, y, 2)
|
||||
pointer('pointermove', rect.left + 180, y, 2)
|
||||
|
||||
// 20px between the fingers became 40px
|
||||
expect(viewBox()[2]).toBe(15)
|
||||
})
|
||||
|
||||
it('should start from the whole map again after render()', () => {
|
||||
const map = zoomable()
|
||||
wheel(-500)
|
||||
|
||||
map.render()
|
||||
|
||||
expect(viewBox()).toEqual([0, 0, 30, 10])
|
||||
expect(el().querySelectorAll('.vector-map-controls').length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('render', () => {
|
||||
it('should replace the previous drawing', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
const map = new VectorMap(el(), { map: squares })
|
||||
map.render()
|
||||
|
||||
expect(el().querySelectorAll('svg').length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('dispose', () => {
|
||||
it('should remove the drawing', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map"></div>'
|
||||
|
||||
const map = new VectorMap(el(), { map: squares, zoom: true })
|
||||
region('AA').dispatchEvent(new PointerEvent('pointermove', { bubbles: true }))
|
||||
map.dispose()
|
||||
|
||||
expect(el().querySelector('svg')).toBeNull()
|
||||
expect(el().querySelector('.vector-map-tooltip')).toBeNull()
|
||||
expect(el().querySelector('.vector-map-controls')).toBeNull()
|
||||
expect(el().classList.contains('vector-map-zoomable')).toBe(false)
|
||||
expect(VectorMap.getInstance(el())).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('world map', () => {
|
||||
it('should have countries by their ISO code, each with a shape', () => {
|
||||
expect(Object.keys(world.regions).length).toBeGreaterThan(170)
|
||||
expect(world.regions.PL.name).toBe('Poland')
|
||||
expect(world.regions.FR.name).toBe('France')
|
||||
expect(world.regions.AQ).toBeUndefined()
|
||||
|
||||
for (const [code, { path, point }] of Object.entries(world.regions)) {
|
||||
expect(code).toMatch(/^[A-Z]{2}$/)
|
||||
expect(path).toMatch(point ? /^M[\d. ]+h0$/ : /^M[-\d. ]+l[-\d. ]+z/)
|
||||
}
|
||||
})
|
||||
|
||||
it('should have the countries too small for a shape as points', () => {
|
||||
for (const code of ['AD', 'SM', 'MC', 'LI', 'VA', 'MT', 'SG', 'HK', 'MO']) {
|
||||
expect(world.regions[code].point).toBe(true)
|
||||
}
|
||||
|
||||
expect(world.regions.PL.point).toBeUndefined()
|
||||
// Dependencies are left out
|
||||
expect(world.regions.GI).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should draw inside its viewBox', () => {
|
||||
fixtureEl.innerHTML = '<div class="vector-map" style="width: 500px"></div>'
|
||||
|
||||
new VectorMap(el(), { map: world })
|
||||
|
||||
const svg = el().querySelector('svg')!
|
||||
// The shapes are rounded to one decimal place
|
||||
const box = svg.getBBox()
|
||||
expect(box.x).toBeGreaterThanOrEqual(-0.05)
|
||||
expect(box.y).toBeGreaterThanOrEqual(-0.05)
|
||||
expect(box.x + box.width).toBeLessThanOrEqual(world.width + 0.05)
|
||||
expect(box.y + box.height).toBeLessThanOrEqual(world.height + 0.05)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -55,6 +55,10 @@
|
||||
"js": ["dist/js/tom-select.base.min.js"],
|
||||
"css": ["dist/css/tom-select.bootstrap5.min.css"]
|
||||
},
|
||||
"vector-map": {
|
||||
"addon": "tabler-vector-map",
|
||||
"maps": ["world"]
|
||||
},
|
||||
"maplibre-gl": {
|
||||
"npm": "maplibre-gl",
|
||||
"addon": "tabler-map",
|
||||
|
||||
+29
-2
@@ -17,14 +17,17 @@
|
||||
"lint:scss:vars": "find-unused-sass-variables scss/ --ignoreFiles scss/_variables-deprecated.scss",
|
||||
"js": "pnpm run js:build && pnpm run js:min && pnpm run js:types",
|
||||
"js:types": "tsc -p tsconfig.types.json",
|
||||
"js:build": "concurrently \"pnpm run js:build:standalone\" \"pnpm run js:build:theme\" \"pnpm run js:build:map\"",
|
||||
"js:build": "concurrently \"pnpm run js:build:standalone\" \"pnpm run js:build:theme\" \"pnpm run js:build:map\" \"pnpm run js:build:vector-map\" \"pnpm run js:build:maps\"",
|
||||
"js:build:vector-map": "cross-env BASE_NAME=tabler-vector-map vite build --config .build/vite.config.mts",
|
||||
"js:build:maps": "cross-env BASE_NAME=maps/world vite build --config .build/vite.config.mts",
|
||||
"js:build:theme": "cross-env BASE_NAME=tabler-theme vite build --config .build/vite.config.mts",
|
||||
"js:build:map": "cross-env BASE_NAME=tabler-map vite build --config .build/vite.config.mts",
|
||||
"js:build:standalone": "cross-env BASE_NAME=tabler vite build --config .build/vite.config.mts",
|
||||
"js:min": "concurrently \"pnpm run js:min:standalone\" \"pnpm run js:min:theme\" \"pnpm run js:min:map\"",
|
||||
"js:min": "concurrently \"pnpm run js:min:standalone\" \"pnpm run js:min:theme\" \"pnpm run js:min:map\" \"pnpm run js:min:vector-map\"",
|
||||
"js:min:standalone": "concurrently \"terser dist/js/tabler.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler.js.map,filename=dist/js/tabler.min.js.map,url=tabler.min.js.map\\\" -o dist/js/tabler.min.js\" \"terser dist/js/tabler.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler.esm.js.map,filename=dist/js/tabler.esm.min.js.map,url=tabler.esm.min.js.map\\\" -o dist/js/tabler.esm.min.js\"",
|
||||
"js:min:theme": "concurrently \"terser dist/js/tabler-theme.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-theme.js.map,filename=dist/js/tabler-theme.min.js.map,url=tabler-theme.min.js.map\\\" -o dist/js/tabler-theme.min.js\" \"terser dist/js/tabler-theme.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-theme.esm.js.map,filename=dist/js/tabler-theme.esm.min.js.map,url=tabler-theme.esm.min.js.map\\\" -o dist/js/tabler-theme.esm.min.js\"",
|
||||
"js:min:map": "concurrently \"terser dist/js/tabler-map.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-map.js.map,filename=dist/js/tabler-map.min.js.map,url=tabler-map.min.js.map\\\" -o dist/js/tabler-map.min.js\" \"terser dist/js/tabler-map.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-map.esm.js.map,filename=dist/js/tabler-map.esm.min.js.map,url=tabler-map.esm.min.js.map\\\" -o dist/js/tabler-map.esm.min.js\"",
|
||||
"js:min:vector-map": "concurrently \"terser dist/js/tabler-vector-map.js --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-vector-map.js.map,filename=dist/js/tabler-vector-map.min.js.map,url=tabler-vector-map.min.js.map\\\" -o dist/js/tabler-vector-map.min.js\" \"terser dist/js/tabler-vector-map.esm.js --module --compress passes=2,ecma=2020 --ecma 2020 --mangle --source-map \\\"content=dist/js/tabler-vector-map.esm.js.map,filename=dist/js/tabler-vector-map.esm.min.js.map,url=tabler-vector-map.esm.min.js.map\\\" -o dist/js/tabler-vector-map.esm.min.js\"",
|
||||
"copy": "concurrently \"pnpm run copy:img\" \"pnpm run copy:libs\"",
|
||||
"copy:img": "tsx .build/copy-img.ts",
|
||||
"copy:libs": "tsx .build/copy-libs.ts",
|
||||
@@ -259,6 +262,30 @@
|
||||
{
|
||||
"path": "./dist/js/tabler-theme.esm.min.js",
|
||||
"maxSize": "800 B"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-vector-map.js",
|
||||
"maxSize": "13 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-vector-map.esm.js",
|
||||
"maxSize": "13 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-vector-map.min.js",
|
||||
"maxSize": "9 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler-vector-map.esm.min.js",
|
||||
"maxSize": "9 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/maps/world.js",
|
||||
"maxSize": "28 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/maps/world.esm.js",
|
||||
"maxSize": "28 kB"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
@forward 'ui/kbd';
|
||||
@forward 'ui/charts';
|
||||
@forward 'ui/sparkline';
|
||||
@forward 'ui/vector-map';
|
||||
@forward 'ui/offcanvas';
|
||||
@forward 'ui/chat';
|
||||
@forward 'ui/signature';
|
||||
|
||||
@@ -2422,6 +2422,29 @@ $sparkline-sizes: (
|
||||
) !default;
|
||||
// scss-docs-end sparkline-variables
|
||||
|
||||
// scss-docs-start vector-map-variables
|
||||
$vector-map-color: var(--primary) !default;
|
||||
$vector-map-region-fill: var(--border-color) !default;
|
||||
$vector-map-region-stroke: var(--bg-surface) !default;
|
||||
$vector-map-region-stroke-width: 1px !default;
|
||||
$vector-map-value-min: 0.1 !default;
|
||||
$vector-map-colors-max: 5 !default;
|
||||
$vector-map-point-size: 0.375rem !default;
|
||||
$vector-map-selected-stroke: var(--body-color) !default;
|
||||
$vector-map-selected-stroke-width: 2px !default;
|
||||
$vector-map-marker-size: 0.5rem !default;
|
||||
$vector-map-marker-color: var(--vector-map-color) !default;
|
||||
$vector-map-marker-halo-color: var(--bg-surface) !default;
|
||||
$vector-map-marker-halo-width: 2px !default;
|
||||
$vector-map-line-color: var(--secondary) !default;
|
||||
$vector-map-line-width: 1px !default;
|
||||
$vector-map-line-dash: 4px !default;
|
||||
$vector-map-line-duration: 1s !default;
|
||||
$vector-map-controls-offset: var(--spacer-2) !default;
|
||||
$vector-map-legend-width: 8rem !default;
|
||||
$vector-map-legend-height: 0.5rem !default;
|
||||
// scss-docs-end vector-map-variables
|
||||
|
||||
// Patterns
|
||||
$pattern-size: 0.5rem !default;
|
||||
$pattern-size-sm: 0.25rem !default;
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
// Vector map (inline SVG, rendered by js/src/vector-map.ts)
|
||||
@use '../config' as *;
|
||||
|
||||
@keyframes vector-map-line {
|
||||
to {
|
||||
stroke-dashoffset: calc(var(--vector-map-line-dash) * -2);
|
||||
}
|
||||
}
|
||||
|
||||
.vector-map {
|
||||
// scss-docs-start vector-map-css-vars
|
||||
--vector-map-color: #{$vector-map-color};
|
||||
--vector-map-region-fill: #{$vector-map-region-fill};
|
||||
--vector-map-region-stroke: #{$vector-map-region-stroke};
|
||||
--vector-map-region-stroke-width: #{$vector-map-region-stroke-width};
|
||||
--vector-map-value-min: #{$vector-map-value-min};
|
||||
--vector-map-point-size: #{$vector-map-point-size};
|
||||
--vector-map-selected-stroke: #{$vector-map-selected-stroke};
|
||||
--vector-map-selected-stroke-width: #{$vector-map-selected-stroke-width};
|
||||
--vector-map-marker-size: #{$vector-map-marker-size};
|
||||
--vector-map-marker-color: #{$vector-map-marker-color};
|
||||
--vector-map-marker-halo-color: #{$vector-map-marker-halo-color};
|
||||
--vector-map-marker-halo-width: #{$vector-map-marker-halo-width};
|
||||
--vector-map-line-color: #{$vector-map-line-color};
|
||||
--vector-map-line-width: #{$vector-map-line-width};
|
||||
--vector-map-line-dash: #{$vector-map-line-dash};
|
||||
--vector-map-line-duration: #{$vector-map-line-duration};
|
||||
--vector-map-controls-offset: #{$vector-map-controls-offset};
|
||||
--vector-map-legend-width: #{$vector-map-legend-width};
|
||||
--vector-map-legend-height: #{$vector-map-legend-height};
|
||||
// scss-docs-end vector-map-css-vars
|
||||
|
||||
position: relative;
|
||||
display: block;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.vector-map-svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vector-map-region {
|
||||
// The colour of the region, used as the fill of a shape and as the dot of a
|
||||
// region drawn as a point.
|
||||
--vector-map-region-color: var(--vector-map-region-fill);
|
||||
fill: var(--vector-map-region-color);
|
||||
stroke: var(--vector-map-region-stroke);
|
||||
stroke-linejoin: round;
|
||||
stroke-width: var(--vector-map-region-stroke-width);
|
||||
// The border keeps its width however large the map is drawn
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
|
||||
// `--vector-map-value` is the 0 to 1 share set by the plugin. The lowest value
|
||||
// still gets `--vector-map-value-min` of the colour, so it stands out from a
|
||||
// region with no value at all. A slice of the legend has a share too, and
|
||||
// gets its colour from the same rule.
|
||||
.vector-map-region[data-value],
|
||||
.vector-map-legend-step {
|
||||
--vector-map-region-color: color-mix(in oklab, var(--vector-map-color) calc((var(--vector-map-value-min) + var(--vector-map-value, 1) * (1 - var(--vector-map-value-min))) * 100%), var(--vector-map-region-fill));
|
||||
}
|
||||
|
||||
// Dashes that move from the start of the line to its end
|
||||
.vector-map-line {
|
||||
fill: none;
|
||||
stroke: var(--vector-map-line-color);
|
||||
stroke-dasharray: var(--vector-map-line-dash);
|
||||
stroke-width: var(--vector-map-line-width);
|
||||
vector-effect: non-scaling-stroke;
|
||||
animation: vector-map-line var(--vector-map-line-duration) linear infinite;
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Both parts of a marker, and of a region drawn as a point, are a line of no
|
||||
// length: its round caps make a dot as wide as the stroke, and the non-scaling
|
||||
// stroke keeps it that wide in pixels however large the map is drawn.
|
||||
.vector-map-region-point-halo,
|
||||
.vector-map-region-point-dot,
|
||||
.vector-map-marker-halo,
|
||||
.vector-map-marker-dot {
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
vector-effect: non-scaling-stroke;
|
||||
}
|
||||
|
||||
// A scale of several colours, from `--vector-map-color-1` for the lowest value
|
||||
// to the last one for the highest. `--vector-map-colors` says how many there
|
||||
// are. Every further colour is mixed over the result so far: not at all below
|
||||
// its part of the scale, more and more inside it, and fully above it, so each
|
||||
// part runs between two neighbours. A colour past the last one never gets a
|
||||
// share, which is why one rule serves any number of them.
|
||||
.vector-map-colors .vector-map-region[data-value],
|
||||
.vector-map-colors .vector-map-legend-step {
|
||||
$color: var(--vector-map-color-1, transparent);
|
||||
|
||||
@for $i from 2 through $vector-map-colors-max {
|
||||
$color: color-mix(in oklab, #{$color}, var(--vector-map-color-#{$i}, transparent) calc(clamp(0, var(--vector-map-value, 1) * (var(--vector-map-colors, 2) - 1) - #{$i - 2}, 1) * 100%));
|
||||
}
|
||||
|
||||
--vector-map-region-color: #{$color};
|
||||
}
|
||||
|
||||
// A country too small for a shape: a dot in the colour of the region, with the
|
||||
// ring of a marker around it. Without a value it says nothing and only adds
|
||||
// noise next to the markers, so it is left out.
|
||||
.vector-map-region-point:not([data-value]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vector-map-region-point-halo {
|
||||
stroke: var(--vector-map-marker-halo-color);
|
||||
stroke-width: calc(var(--vector-map-point-size) + var(--vector-map-marker-halo-width) * 2);
|
||||
}
|
||||
|
||||
.vector-map-region-point-dot {
|
||||
stroke: var(--vector-map-region-color);
|
||||
stroke-width: var(--vector-map-point-size);
|
||||
}
|
||||
|
||||
.vector-map-marker-halo {
|
||||
stroke: var(--vector-map-marker-halo-color);
|
||||
stroke-width: calc(var(--vector-map-marker-size) + var(--vector-map-marker-halo-width) * 2);
|
||||
}
|
||||
|
||||
.vector-map-marker-dot {
|
||||
stroke: var(--vector-map-marker-color);
|
||||
stroke-width: var(--vector-map-marker-size);
|
||||
}
|
||||
|
||||
// Follows the pointer, placed by the plugin with `left` and `top`
|
||||
.vector-map-tooltip {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
padding: $tooltip-padding-y $tooltip-padding-x;
|
||||
font-size: $tooltip-font-size;
|
||||
line-height: $line-height-base;
|
||||
color: $tooltip-color;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
background: $tooltip-bg;
|
||||
@include border-radius($tooltip-border-radius);
|
||||
|
||||
/* rtl:ignore */
|
||||
transform: translate(-50%, calc(-100% - #{$spacer-2}));
|
||||
}
|
||||
|
||||
// A map that can be magnified takes the drags and pinches for itself, so the
|
||||
// page does not scroll or zoom under the finger.
|
||||
.vector-map-zoomable .vector-map-svg {
|
||||
touch-action: none;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.vector-map-dragging .vector-map-svg {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.vector-map-controls {
|
||||
position: absolute;
|
||||
inset-block-start: var(--vector-map-controls-offset);
|
||||
inset-inline-end: var(--vector-map-controls-offset);
|
||||
z-index: 1;
|
||||
|
||||
.icon {
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-width: 2;
|
||||
}
|
||||
}
|
||||
|
||||
// The scale of the map as a bar, with the lowest and the highest value
|
||||
.vector-map-legend {
|
||||
display: flex;
|
||||
gap: $spacer-2;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: $spacer-2;
|
||||
font-size: $font-size-sm;
|
||||
font-variant-numeric: tabular-nums;
|
||||
line-height: $line-height-base;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.vector-map-legend-scale {
|
||||
display: flex;
|
||||
width: var(--vector-map-legend-width);
|
||||
height: var(--vector-map-legend-height);
|
||||
overflow: hidden;
|
||||
@include border-radius($border-radius-pill);
|
||||
}
|
||||
|
||||
.vector-map-legend-step {
|
||||
flex: 1;
|
||||
background: var(--vector-map-region-color);
|
||||
}
|
||||
|
||||
// Regions can be clicked to select them
|
||||
.vector-map-selectable .vector-map-region {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// A selected region gets an outline, and keeps the colour of its value
|
||||
.vector-map-region-selected {
|
||||
stroke: var(--vector-map-selected-stroke);
|
||||
stroke-width: var(--vector-map-selected-stroke-width);
|
||||
|
||||
.vector-map-region-point-halo {
|
||||
stroke: var(--vector-map-selected-stroke);
|
||||
}
|
||||
}
|
||||
@@ -8,5 +8,5 @@
|
||||
"rootDir": "js",
|
||||
"outDir": "dist/types"
|
||||
},
|
||||
"include": ["js/tabler.ts", "js/tabler-theme.ts", "js/tabler-map.ts", "js/src/**/*"]
|
||||
"include": ["js/tabler.ts", "js/tabler-theme.ts", "js/tabler-map.ts", "js/tabler-vector-map.ts", "js/maps/*.ts", "js/src/**/*"]
|
||||
}
|
||||
@@ -1,99 +1,367 @@
|
||||
---
|
||||
title: Vector map
|
||||
docs-libs: [jsvectormap]
|
||||
description: Interactive SVG maps with jsVectorMap, with a world map, markers and lines.
|
||||
summary: A vector map draws countries as SVG paths that can be styled and clicked. Tabler themes jsVectorMap to match the interface.
|
||||
related: [/ui/components/map]
|
||||
docs-libs: [vector-map]
|
||||
description: Draw a world map as inline SVG from data attributes. Shade countries by value, add markers and lines, show tooltips and let users zoom, with no map library.
|
||||
summary: A vector map draws countries as SVG paths, shaded by a value, with markers, lines, tooltips and zoom. Tabler renders it from data attributes, with no map library and no map provider.
|
||||
added-in: '1.7.0'
|
||||
related: [/ui/components/map, /ui/components/sparkline]
|
||||
source: core/scss/ui/_vector-map.scss
|
||||
css-vars: vector-map
|
||||
classnames:
|
||||
component:
|
||||
- class: vector-map
|
||||
desc: Box that holds the map, as wide as its parent
|
||||
style:
|
||||
- class: vector-map-colors
|
||||
desc: Shades the values with a scale of several colors, set by JavaScript for data-bs-colors
|
||||
part:
|
||||
- class: vector-map-svg
|
||||
desc: The rendered SVG, added by JavaScript
|
||||
- class: vector-map-region
|
||||
desc: One country or region, with its code in data-region
|
||||
- class: vector-map-region-point
|
||||
desc: A country too small for a shape, drawn as a dot when it has a value
|
||||
- class: vector-map-region-point-dot
|
||||
desc: The dot, in the color of the region
|
||||
- class: vector-map-region-point-halo
|
||||
desc: Ring around the dot, in the surface color
|
||||
- class: vector-map-marker
|
||||
desc: Group that holds the two parts of a marker
|
||||
- class: vector-map-marker-dot
|
||||
desc: The colored dot of a marker
|
||||
- class: vector-map-marker-halo
|
||||
desc: Ring around the dot, in the surface color
|
||||
- class: vector-map-line
|
||||
desc: Dashed curve between two markers
|
||||
- class: vector-map-tooltip
|
||||
desc: Label that follows the pointer
|
||||
- class: vector-map-controls
|
||||
desc: Zoom buttons in the corner of the map
|
||||
- class: vector-map-legend
|
||||
desc: The scale under the map, two numbers around a bar
|
||||
- class: vector-map-legend-label
|
||||
desc: A number at one end of the scale
|
||||
- class: vector-map-legend-scale
|
||||
desc: The bar of the legend
|
||||
- class: vector-map-legend-step
|
||||
desc: One slice of the bar, colored like a region with the same share
|
||||
---
|
||||
|
||||
import Example from '@components/Example.astro'
|
||||
import MapVector from '@shared/components/demo/MapVector.astro'
|
||||
import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
import Example from '@components/Example.astro';
|
||||
import CodeDocs from '@components/CodeDocs.astro';
|
||||
import { Code } from 'astro:components';
|
||||
import { site } from '@shared/lib/site.ts';
|
||||
|
||||
## Overview
|
||||
|
||||
A vector map draws countries and regions as SVG paths, so it stays sharp at any size and every region can be styled or clicked. Tabler uses [jsVectorMap](https://jvm-docs.vercel.app/), and themes it to match the rest of the interface.
|
||||
A vector map draws countries as SVG paths, so it stays sharp at any size. Use it to show a number per country, a few places, or routes between them.
|
||||
|
||||
The library ships the map data separately from the code. Load the map you need - the world map here - or the build will render an empty box.
|
||||
The component is Tabler's own. It needs no map library, no API key and no network request. The country shapes come from [Natural Earth](https://www.naturalearthdata.com/), which is public domain.
|
||||
|
||||
## Installation
|
||||
|
||||
Install jsVectorMap with npm:
|
||||
|
||||
<TabsPackage name="jsvectormap" />
|
||||
|
||||
Or include it from a CDN. You need three files: the stylesheet, the library, and the map data.
|
||||
The vector map is not part of `tabler.js`, so pages without a map do not load it. Add two files after `tabler.js`: the component and the map data.
|
||||
|
||||
<Code
|
||||
lang="html"
|
||||
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/libs/jsvectormap/dist/jsvectormap.css" />
|
||||
<script src="${site.cdnUrl}/dist/libs/jsvectormap/dist/jsvectormap.min.js"></script>
|
||||
<script src="${site.cdnUrl}/dist/libs/jsvectormap/dist/maps/world.js"></script>`}
|
||||
code={`<script src="${site.cdnUrl}/dist/js/tabler.min.js"></script>
|
||||
<script src="${site.cdnUrl}/dist/js/tabler-vector-map.min.js"></script>
|
||||
<script src="${site.cdnUrl}/dist/js/maps/world.js"></script>`}
|
||||
/>
|
||||
|
||||
Use `maps/world-merc.js` instead for the Mercator projection.
|
||||
The styles are part of `tabler.css`.
|
||||
|
||||
## Usage
|
||||
|
||||
Add an empty element with a height, then point jsVectorMap at it. The `map` option has to match the map file you loaded.
|
||||
|
||||
```html
|
||||
<div id="map-world" style="height: 20rem"></div>
|
||||
```
|
||||
With a bundler, import the component and the map, then register the map under a name:
|
||||
|
||||
```js
|
||||
new jsVectorMap({
|
||||
selector: '#map-world',
|
||||
map: 'world',
|
||||
import { VectorMap } from '@tabler/core/dist/js/tabler-vector-map.esm.js';
|
||||
import { world } from '@tabler/core/dist/js/maps/world.esm.js';
|
||||
|
||||
VectorMap.addMap('world', world);
|
||||
```
|
||||
|
||||
## Default markup
|
||||
|
||||
Add `class="vector-map"` and `data-bs-toggle="vector-map"` to an empty element. Tabler draws the map on page load. The map is as wide as its parent and keeps its own proportions, so it needs no height.
|
||||
|
||||
Set `data-bs-label` to a short text that says what the map shows. Without it the map is hidden from screen readers.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="World map"></div>
|
||||
</Example>
|
||||
|
||||
## Values
|
||||
|
||||
Pass a number per country in `data-bs-values`, as a JSON object. The keys are ISO 3166-1 alpha-2 codes, such as `PL` or `US`. The country with the highest value gets the full color and the others get a lighter shade.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="Visits by country" data-bs-values='{"US": 100, "CA": 62, "BR": 48, "GB": 71, "DE": 80, "FR": 66, "PL": 54, "IN": 90, "CN": 85, "JP": 59, "AU": 40, "ZA": 22, "EG": 18, "MX": 35, "AR": 27}'></div>
|
||||
</Example>
|
||||
|
||||
The shades are spread between the lowest and the highest value. Set `data-bs-min` and `data-bs-max` to use a fixed range instead, for example `0` and `100` for a percentage.
|
||||
|
||||
### Color
|
||||
|
||||
The map uses the primary color. Set `--tblr-vector-map-color` to change it.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="Growth by country" data-bs-min="0" data-bs-values='{"US": 4, "CA": 7, "BR": 9, "DE": 3, "PL": 8, "IN": 10, "CN": 6, "AU": 5}' style="--tblr-vector-map-color: var(--tblr-green)"></div>
|
||||
</Example>
|
||||
|
||||
### Color scale
|
||||
|
||||
One color shows how much. A scale of several colors also shows good and bad, or cold and hot. Pass two to five colors in `data-bs-colors`, as a JSON array. The first color is for the lowest value and the last one for the highest. The values between them get a mix of the two nearest colors.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="Customer satisfaction by country" data-bs-min="0" data-bs-max="100" data-bs-colors='["var(--tblr-red)", "var(--tblr-yellow)", "var(--tblr-green)"]' data-bs-values='{"US": 82, "CA": 91, "MX": 48, "BR": 35, "AR": 22, "GB": 74, "DE": 96, "FR": 63, "ES": 55, "PL": 88, "RU": 12, "IN": 41, "CN": 58, "JP": 79, "AU": 100, "ZA": 28, "EG": 6, "NG": 17, "SA": 67, "ID": 45}'></div>
|
||||
</Example>
|
||||
|
||||
Any CSS color works, also a Tabler color such as `var(--tblr-red)`. The browser mixes the colors with `color-mix()`, so they follow the theme and you can change them later with CSS.
|
||||
|
||||
The plugin writes the colors to `--tblr-vector-map-color-1`, `--tblr-vector-map-color-2` and so on, and their number to `--tblr-vector-map-colors`. To set a scale without JavaScript options, add the `vector-map-colors` class and these properties yourself:
|
||||
|
||||
```html
|
||||
<div class="vector-map vector-map-colors" data-bs-toggle="vector-map" style="--tblr-vector-map-colors: 2; --tblr-vector-map-color-1: var(--tblr-blue); --tblr-vector-map-color-2: var(--tblr-red)"></div>
|
||||
```
|
||||
|
||||
With a scale, the lowest value gets the first color in full, so `--tblr-vector-map-value-min` is not used. Markers keep the color from `--tblr-vector-map-color`.
|
||||
|
||||
### Legend
|
||||
|
||||
Colors alone do not say how much. Add `data-bs-legend="true"` to show the scale under the map, as a bar between the lowest and the highest value. The bar uses the same colors as the map, also with a scale of several colors.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-legend="true" data-bs-label="Customer satisfaction by country" data-bs-min="0" data-bs-max="100" data-bs-colors='["var(--tblr-red)", "var(--tblr-yellow)", "var(--tblr-green)"]' data-bs-values='{"US": 82, "CA": 91, "MX": 48, "BR": 35, "AR": 22, "GB": 74, "DE": 96, "FR": 63, "ES": 55, "PL": 88, "RU": 12, "IN": 41, "CN": 58, "JP": 79, "AU": 100, "ZA": 28, "EG": 6, "NG": 17, "SA": 67, "ID": 45}'></div>
|
||||
</Example>
|
||||
|
||||
The two numbers are the range of the scale: `min` and `max` when you set them, the lowest and the highest value otherwise. Pass a function from JavaScript to add a unit or to format the numbers:
|
||||
|
||||
```js
|
||||
new tabler.VectorMap('#satisfaction', {
|
||||
values: { PL: 88, DE: 96 },
|
||||
legend: (value) => `${value}%`,
|
||||
});
|
||||
```
|
||||
|
||||
The map sizes itself from its container, so the container needs a height before the map is created. Call `updateSize()` on resize to keep it in step:
|
||||
|
||||
```js
|
||||
const map = new jsVectorMap({ selector: '#map-world', map: 'world' });
|
||||
|
||||
window.addEventListener('resize', () => map.updateSize());
|
||||
```
|
||||
|
||||
## Default map
|
||||
|
||||
The code for a world map with the default options:
|
||||
|
||||
<Example codeOnly>
|
||||
<MapVector mapId="empty" />
|
||||
</Example>
|
||||
|
||||
## Sample demo
|
||||
|
||||
The same map rendered on the page:
|
||||
|
||||
<Example>
|
||||
<MapVector mapId="world" />
|
||||
</Example>
|
||||
Set the size of the bar with `--tblr-vector-map-legend-width` and `--tblr-vector-map-legend-height`.
|
||||
|
||||
## Markers
|
||||
|
||||
Markers point out single locations, such as offices or customers:
|
||||
Markers point at single places, such as offices or customers. Pass them in `data-bs-markers` as a JSON array. Each marker has a `lat`, a `lng` and an optional `name`. A marker keeps its size when the map is resized or zoomed.
|
||||
|
||||
<Example>
|
||||
<MapVector mapId="world-markers" />
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="Our offices" data-bs-markers='[{"name": "Warsaw", "lat": 52.23, "lng": 21.01}, {"name": "New York", "lat": 40.71, "lng": -74.01}, {"name": "Tokyo", "lat": 35.68, "lng": 139.69}, {"name": "Sydney", "lat": -33.87, "lng": 151.21}]' style="--tblr-vector-map-color: var(--tblr-red)"></div>
|
||||
</Example>
|
||||
|
||||
## Lines
|
||||
|
||||
Lines connect locations, for a route or a link between two points:
|
||||
Lines join two markers, for a route or a connection. Pass them in `data-bs-lines` as a JSON array. `from` and `to` are the names of two markers. The dashes move from the start of the line to its end, and stand still for users who ask for reduced motion.
|
||||
|
||||
<Example>
|
||||
<MapVector mapId="world-lines" />
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-label="Flights from Warsaw" data-bs-markers='[{"name": "Warsaw", "lat": 52.23, "lng": 21.01}, {"name": "New York", "lat": 40.71, "lng": -74.01}, {"name": "Tokyo", "lat": 35.68, "lng": 139.69}, {"name": "Cape Town", "lat": -33.92, "lng": 18.42}]' data-bs-lines='[{"from": "Warsaw", "to": "New York"}, {"from": "Warsaw", "to": "Tokyo"}, {"from": "Warsaw", "to": "Cape Town"}]'></div>
|
||||
</Example>
|
||||
|
||||
## Zoom
|
||||
|
||||
Add `data-bs-zoom="true"` to let users look closer. The map gets two buttons, and reacts to the mouse wheel, a double click, a pinch and a drag.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-zoom="true" data-bs-label="Visits in Europe" data-bs-values='{"PL": 8, "DE": 6, "FR": 5, "ES": 3, "IT": 4, "GB": 7, "SE": 2, "UA": 3, "RO": 2, "CZ": 5}'></div>
|
||||
</Example>
|
||||
|
||||
While the pointer is over a zoomable map, the wheel zooms the map and does not scroll the page. Set `data-bs-zoom-on-scroll="false"` to keep the wheel for the page. On a touch screen a finger on the map moves the map, not the page, so leave some room around a large map.
|
||||
|
||||
## Selecting countries
|
||||
|
||||
Set `data-bs-select` to let users pick countries with a click. With `single` a click on another country moves the selection. With `multiple` every click adds a country. A click on a selected country takes it out again. Pass the countries that start selected in `data-bs-selected`.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-select="multiple" data-bs-selected='["PL", "FR", "BR"]' data-bs-label="Countries to compare"></div>
|
||||
</Example>
|
||||
|
||||
A selected country gets an outline and keeps the color of its value. Change the outline with `--tblr-vector-map-selected-stroke` and `--tblr-vector-map-selected-stroke-width`.
|
||||
|
||||
The map fires `selected.bs.vector-map` after every change. Read the selection from the event, or with `getSelected()`:
|
||||
|
||||
```js
|
||||
const element = document.getElementById('compare');
|
||||
|
||||
element.addEventListener('selected.bs.vector-map', (event) => {
|
||||
console.log(event.selected); // ['PL', 'FR', 'BR', 'DE']
|
||||
});
|
||||
|
||||
tabler.VectorMap.getInstance(element).setSelected(['US', 'CA']);
|
||||
```
|
||||
|
||||
## Clicks
|
||||
|
||||
The map fires `regionclick.bs.vector-map` when a country is clicked and `markerclick.bs.vector-map` when a marker is clicked, also when nothing can be selected. Use them to open a page or to filter a table. A drag on a zoomable map is not a click.
|
||||
|
||||
```js
|
||||
element.addEventListener('regionclick.bs.vector-map', (event) => {
|
||||
console.log(event.code, event.name, event.value); // 'PL', 'Poland', 54
|
||||
});
|
||||
|
||||
element.addEventListener('markerclick.bs.vector-map', (event) => {
|
||||
console.log(event.name, event.lat, event.lng);
|
||||
});
|
||||
```
|
||||
|
||||
Call `event.preventDefault()` in `regionclick.bs.vector-map` to keep that click from changing the selection.
|
||||
|
||||
## Tooltip
|
||||
|
||||
A tooltip shows the name of the country or marker under the pointer, with the value when the country has one. Set `data-bs-tooltip="false"` to turn it off.
|
||||
|
||||
Pass a function from JavaScript to write your own text. It gets the item under the pointer and returns a string. The string is shown as plain text. Return an empty string to show nothing.
|
||||
|
||||
```js
|
||||
new tabler.VectorMap('#visits', {
|
||||
values: { PL: 54, DE: 80 },
|
||||
tooltip: (item) => (item.type === 'region' && item.value !== undefined ? `${item.name}: ${item.value}%` : item.name),
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
Set options with data attributes or pass them to the constructor. For a data attribute, add `data-bs-` to the name and write it in kebab case, for example `data-bs-zoom-max`.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `map` | string, object | `'world'` | Name of a loaded map, or the map data itself. |
|
||||
| `values` | object | `{}` | A number per region code. |
|
||||
| `min` | number, null | `null` | Value that gets the lightest shade. The lowest value when `null`. |
|
||||
| `max` | number, null | `null` | Value that gets the full color. The highest value when `null`. |
|
||||
| `colors` | array | `[]` | Two to five colors of a scale, from the lowest value to the highest. |
|
||||
| `markers` | array | `[]` | Places as `{ name, lat, lng }`. |
|
||||
| `lines` | array | `[]` | Connections as `{ from, to }`, by marker name. |
|
||||
| `tooltip` | boolean, function | `true` | Shows a tooltip, or builds its text. |
|
||||
| `legend` | boolean, function | `false` | Shows the scale under the map, or formats its two numbers. |
|
||||
| `select` | string | `'none'` | Lets users select countries: `'none'`, `'single'` or `'multiple'`. |
|
||||
| `selected` | array | `[]` | Codes of the countries that start selected. |
|
||||
| `zoom` | boolean | `false` | Lets users zoom and drag the map. |
|
||||
| `zoomMax` | number | `8` | The largest magnification. |
|
||||
| `zoomOnScroll` | boolean | `true` | Zooms with the mouse wheel. Needs `zoom`. |
|
||||
| `zoomInLabel` | string | `'Zoom in'` | Accessible name of the zoom in button. |
|
||||
| `zoomOutLabel` | string | `'Zoom out'` | Accessible name of the zoom out button. |
|
||||
| `label` | string, null | `null` | Accessible name of the map. |
|
||||
|
||||
## JavaScript
|
||||
|
||||
Tabler wraps the element in a `VectorMap` component that works like the Bootstrap components: it is created once per element and stored on it. When the page is loaded, Tabler creates one for every element with `data-bs-toggle="vector-map"`. This is the code that runs:
|
||||
|
||||
<CodeDocs name="vector-map-init" file="core/js/src/vector-map.ts" />
|
||||
|
||||
Create the component yourself for an element added later, or to pass the data from code:
|
||||
|
||||
```js
|
||||
const visits = tabler.VectorMap.getOrCreateInstance(document.getElementById('visits'), {
|
||||
values: { PL: 54, DE: 80, FR: 66 },
|
||||
});
|
||||
```
|
||||
|
||||
Call `update()` with new values to shade the map again. The map is not drawn again, so this is cheap enough for live data:
|
||||
|
||||
```js
|
||||
visits.update({ PL: 61, DE: 77, FR: 70 });
|
||||
```
|
||||
|
||||
| Method | Description |
|
||||
| --- | --- |
|
||||
| `update(values)` | Shades the regions with new values. Fires `updated.bs.vector-map`. |
|
||||
| `render()` | Reads the attributes again and draws the map from the start. Fires `rendered.bs.vector-map`. |
|
||||
| `getSelected()` | Returns the codes of the selected countries. |
|
||||
| `setSelected(codes)` | Selects exactly these countries. Fires `selected.bs.vector-map`. |
|
||||
| `zoomIn()` | Zooms in one step, around the middle of the view. |
|
||||
| `zoomOut()` | Zooms out one step. |
|
||||
| `reset()` | Goes back to the whole map. |
|
||||
| `dispose()` | Removes the map, the buttons, the legend, the tooltip and the component from the element. |
|
||||
| `VectorMap.addMap(name, data)` | Static. Registers a map under a name. |
|
||||
| `getInstance(element)` | Static. Returns the component for the element, or `null`. |
|
||||
| `getOrCreateInstance(element, config)` | Static. Returns the component for the element and creates it when needed. |
|
||||
|
||||
| Event | Description |
|
||||
| --- | --- |
|
||||
| `rendered.bs.vector-map` | Fired on the element after every render. |
|
||||
| `updated.bs.vector-map` | Fired on the element after `update()`. |
|
||||
| `regionclick.bs.vector-map` | Fired when a country is clicked. Has `code`, `name`, `value` when the country has one, and the element in `relatedTarget`. Can be prevented. |
|
||||
| `markerclick.bs.vector-map` | Fired when a marker is clicked. Has `name`, `lat`, `lng` and the element in `relatedTarget`. |
|
||||
| `selected.bs.vector-map` | Fired after the selection changes. Has the codes in `selected`, and the clicked `code` when a click made the change. |
|
||||
|
||||
## Styling a single country
|
||||
|
||||
Every country has its code in `data-region`, so one rule can color it. Set `--tblr-vector-map-region-color`, which works for a shape and for the dot of a small country:
|
||||
|
||||
```css
|
||||
.vector-map [data-region='PL'] {
|
||||
--tblr-vector-map-region-color: var(--tblr-red);
|
||||
}
|
||||
```
|
||||
|
||||
## Custom properties
|
||||
|
||||
The map reads its colors and sizes from custom properties on the element. Change them for one map with a `style` attribute, or for a section with a class.
|
||||
|
||||
| Property | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `--tblr-vector-map-color` | `var(--tblr-primary)` | Color of the highest value, and of the markers. |
|
||||
| `--tblr-vector-map-region-fill` | `var(--tblr-border-color)` | Fill of a country with no value. |
|
||||
| `--tblr-vector-map-region-stroke` | `var(--tblr-bg-surface)` | Border between countries. |
|
||||
| `--tblr-vector-map-region-stroke-width` | `1px` | Width of the border. |
|
||||
| `--tblr-vector-map-value-min` | `0.1` | Share of the color the lowest value gets, from 0 to 1. |
|
||||
| `--tblr-vector-map-color-1` to `-5` | none | Colors of a scale, from the lowest value to the highest. |
|
||||
| `--tblr-vector-map-colors` | none | Number of colors in the scale. |
|
||||
| `--tblr-vector-map-point-size` | `0.375rem` | Diameter of the dot of a small country. |
|
||||
| `--tblr-vector-map-selected-stroke` | `var(--tblr-body-color)` | Outline of a selected country. |
|
||||
| `--tblr-vector-map-selected-stroke-width` | `2px` | Width of that outline. |
|
||||
| `--tblr-vector-map-marker-size` | `0.5rem` | Diameter of a marker. |
|
||||
| `--tblr-vector-map-marker-color` | `var(--tblr-vector-map-color)` | Color of a marker. |
|
||||
| `--tblr-vector-map-marker-halo-color` | `var(--tblr-bg-surface)` | Color of the ring around a marker and around the dot of a small country. |
|
||||
| `--tblr-vector-map-marker-halo-width` | `2px` | Width of the ring. |
|
||||
| `--tblr-vector-map-line-color` | `var(--tblr-secondary)` | Color of a line. |
|
||||
| `--tblr-vector-map-line-width` | `1px` | Width of a line. |
|
||||
| `--tblr-vector-map-line-dash` | `4px` | Length of a dash and of the gap after it. |
|
||||
| `--tblr-vector-map-line-duration` | `1s` | Time one dash takes to move to the place of the next. |
|
||||
| `--tblr-vector-map-legend-width` | `8rem` | Width of the bar of the legend. |
|
||||
| `--tblr-vector-map-legend-height` | `0.5rem` | Height of the bar. |
|
||||
| `--tblr-vector-map-controls-offset` | `var(--tblr-spacer-2)` | Distance of the zoom buttons from the corner. |
|
||||
|
||||
## The world map
|
||||
|
||||
The world map has 207 countries in the Miller projection, without Antarctica. Values for a code that is not on the map are skipped.
|
||||
|
||||
### Small countries
|
||||
|
||||
31 countries are too small to see as a shape on a map of the world, for example Andorra, San Marino, Malta or Singapore. The map shows such a country as a dot when it has a value. A dot works like any other country: it gets the same shade and has a tooltip. It keeps its size when the map is resized or zoomed.
|
||||
|
||||
<Example>
|
||||
<div class="vector-map" data-bs-toggle="vector-map" data-bs-zoom="true" data-bs-label="Visits from small countries" data-bs-values='{"AD": 4, "SM": 2, "MC": 5, "LI": 3, "VA": 1, "MT": 6, "SG": 9, "HK": 8, "BH": 5, "MU": 3}'></div>
|
||||
</Example>
|
||||
|
||||
The dots are the sovereign states that have no shape on the map, plus Hong Kong and Macao. Dependent territories, such as Gibraltar or Guam, are not on the map. Set the size of a dot with `--tblr-vector-map-point-size`.
|
||||
|
||||
A small country with no value is hidden, so a map with a few markers does not fill up with grey dots. To show all of them, add this rule:
|
||||
|
||||
```css
|
||||
.vector-map-region-point:not([data-value]) {
|
||||
display: inline;
|
||||
}
|
||||
```
|
||||
|
||||
Three territories have no ISO code. The map uses `XK` for Kosovo, `XC` for Northern Cyprus and `XS` for Somaliland. Borders follow the default view of Natural Earth.
|
||||
|
||||
## Accessibility
|
||||
|
||||
- A map is a picture built from paths, and a screen reader reads them as a list of shapes. Give the container `role="img"` and an `aria-label` that says what it shows.
|
||||
- The data behind the map has to be reachable another way. A table of the same values, next to or below the map, serves screen reader users and anyone printing the page.
|
||||
- Hovering a region is mouse-only. Do not put anything there that is not also available in the text version.
|
||||
- Colour scales are hard to read for many users. Add a legend with the actual numbers rather than color alone.
|
||||
- Do not make every region focusable. A world map would be hundreds of tab stops.
|
||||
- Set `data-bs-label`. The map is then an image with that name. The countries themselves are not read out one by one.
|
||||
- The data behind the map has to be reachable another way. Put a table of the same values next to or below the map. It serves screen reader users and anyone who prints the page.
|
||||
- The tooltip is for the pointer only. Do not put anything there that is not in the text version too.
|
||||
- Shades of one color are hard to tell apart for many users. Turn on the legend, and for exact numbers add a table.
|
||||
- Countries and markers can be clicked with a pointer only. They are not in the tab order, because a world map would be two hundred tab stops. When a click or a selection does something, offer the same choice in another control, such as a list of checkboxes or a select, and keep the two in step with `setSelected()`.
|
||||
- The zoom buttons work with the keyboard and have accessible names. Change the names with `data-bs-zoom-in-label` and `data-bs-zoom-out-label` when the page is not in English.
|
||||
|
||||
## Variables
|
||||
|
||||
<CodeDocs name="vector-map-variables" file="core/scss/_variables.scss" />
|
||||
|
||||
## Migration notes
|
||||
|
||||
Before 1.7 this page used [jsVectorMap](https://jvm-docs.vercel.app/). Its files are still in `dist/libs/jsvectormap` and its styles are still in `tabler-vendors.css`, so a page that uses it keeps working. The demo and the docs now use the component above.
|
||||
@@ -142,7 +142,7 @@ const editFilePath =
|
||||
|
||||
// docs-libs for this page. In dev, file names stay unchanged
|
||||
// (e.g. dist/plyr.min.js keeps .min).
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string };
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string; maps?: string[] };
|
||||
const libEntries = Object.entries(libs as Record<string, Lib>);
|
||||
const libUrl = (lib: Lib, file: string) =>
|
||||
isExternal(file)
|
||||
@@ -155,6 +155,7 @@ const docsLibAddons = libEntries.filter(([name]) => docsLibs.includes(name)).fla
|
||||
const docsLibModules = libEntries
|
||||
.filter(([name]) => docsLibs.includes(name))
|
||||
.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libUrl(lib, lib.module.file)}'; window.${lib.module.global} = lib`] : []));
|
||||
const docsLibMaps = libEntries.filter(([name]) => docsLibs.includes(name)).flatMap(([, lib]) => lib.maps ?? []);
|
||||
const docsLibJs = libEntries
|
||||
.filter(([name]) => docsLibs.includes(name))
|
||||
.flatMap(([, lib]) => (lib.js ?? []).map((file) => libUrl(lib, file)));
|
||||
@@ -527,6 +528,7 @@ const relatedPages = await Promise.all(
|
||||
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
||||
<script is:inline src="/dist/js/tabler.js" defer></script>
|
||||
{docsLibAddons.map((addon) => <script is:inline src={`/dist/js/${addon}.js`} defer />)}
|
||||
{docsLibMaps.map((map) => <script is:inline src={`/dist/js/maps/${map}.js`} defer />)}
|
||||
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
||||
|
||||
<PageScripts />
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"html-diff:baseline": "tsx .build/html-diff.ts baseline",
|
||||
"generate:tokens": "tsx .build/generate-tokens.ts",
|
||||
"generate:sri": "tsx .build/generate-sri.ts",
|
||||
"generate:maps": "tsx .build/generate-maps.ts",
|
||||
"import:icons": "tsx .build/import-icons.ts",
|
||||
"import:illustrations": "tsx .build/import-illustrations.ts",
|
||||
"import:flags": "tsx .build/import-flags.ts",
|
||||
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pretitle="Overview" pageMenu="dashboards.default" pageLibs={['apexcharts', 'jsvectormap']}>
|
||||
<DefaultLayout title="Dashboard" pretitle="Overview" pageMenu="dashboards.default" pageLibs={['apexcharts', 'vector-map']}>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Boxed layout" pretitle="Overview" pageMenu="layout.boxed" pageLibs={['apexcharts', 'jsvectormap']} layout="boxed">
|
||||
<DefaultLayout title="Dashboard" pageHeader="Boxed layout" pretitle="Overview" pageMenu="layout.boxed" pageLibs={['apexcharts', 'vector-map']} layout="boxed">
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Condensed layout" pretitle="Overview" pageMenu="layout.condensed" pageLibs={['apexcharts', 'jsvectormap']} navbarCondensed>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Condensed layout" pretitle="Overview" pageMenu="layout.condensed" pageLibs={['apexcharts', 'vector-map']} navbarCondensed>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Fluid vertical layout" pretitle="Overview" pageMenu="layout.fluid-vertical" pageLibs={['apexcharts', 'jsvectormap']} layout="fluid" navbarPosition="vertical">
|
||||
<DefaultLayout title="Dashboard" pageHeader="Fluid vertical layout" pretitle="Overview" pageMenu="layout.fluid-vertical" pageLibs={['apexcharts', 'vector-map']} layout="fluid" navbarPosition="vertical">
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Fluid layout" pretitle="Overview" pageMenu="layout.fluid" pageLibs={['apexcharts', 'jsvectormap']} layout="fluid">
|
||||
<DefaultLayout title="Dashboard" pageHeader="Fluid layout" pretitle="Overview" pageMenu="layout.fluid" pageLibs={['apexcharts', 'vector-map']} layout="fluid">
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Folded hover layout" pretitle="Overview" pageMenu="layout.folded-hover" pageLibs={['apexcharts', 'jsvectormap']} navbarPosition="vertical" sidebarMode="folded-hover">
|
||||
<DefaultLayout title="Dashboard" pageHeader="Folded hover layout" pretitle="Overview" pageMenu="layout.folded-hover" pageLibs={['apexcharts', 'vector-map']} navbarPosition="vertical" sidebarMode="folded-hover">
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Folded sidebar layout" pretitle="Overview" pageMenu="layout.folded" pageLibs={['apexcharts', 'jsvectormap']} navbarPosition="vertical" sidebarMode="folded">
|
||||
<DefaultLayout title="Dashboard" pageHeader="Folded sidebar layout" pretitle="Overview" pageMenu="layout.folded" pageLibs={['apexcharts', 'vector-map']} navbarPosition="vertical" sidebarMode="folded">
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Horizontal layout" pretitle="Overview" pageMenu="layout.horizontal" pageLibs={['apexcharts', 'jsvectormap']}>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Horizontal layout" pretitle="Overview" pageMenu="layout.horizontal" pageLibs={['apexcharts', 'vector-map']}>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar dark" pretitle="Overview" pageMenu="layout.navbar-dark" pageLibs={['apexcharts', 'jsvectormap']} navbarDark>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar dark" pretitle="Overview" pageMenu="layout.navbar-dark" pageLibs={['apexcharts', 'vector-map']} navbarDark>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar floating" pretitle="Overview" pageMenu="layout.navbar-floating" pageLibs={['apexcharts', 'jsvectormap']} navbarCondensed navbarFloating>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar floating" pretitle="Overview" pageMenu="layout.navbar-floating" pageLibs={['apexcharts', 'vector-map']} navbarCondensed navbarFloating>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar sticky" pretitle="Overview" pageMenu="layout.navbar-sticky" pageLibs={['apexcharts', 'jsvectormap']} navbarSticky>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Navbar sticky" pretitle="Overview" pageMenu="layout.navbar-sticky" pageLibs={['apexcharts', 'vector-map']} navbarSticky>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="RTL mode" pretitle="Overview" pageMenu="layout.rtl-mode" pageLibs={['apexcharts', 'jsvectormap']} rtl>
|
||||
<DefaultLayout title="RTL mode" pretitle="Overview" pageMenu="layout.rtl-mode" pageLibs={['apexcharts', 'vector-map']} rtl>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent rtl />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical floating layout" pretitle="Overview" pageMenu="layout.vertical-floating" pageLibs={['apexcharts', 'jsvectormap']} navbarPosition="vertical" navbarFloating>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical floating layout" pretitle="Overview" pageMenu="layout.vertical-floating" pageLibs={['apexcharts', 'vector-map']} navbarPosition="vertical" navbarFloating>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Right vertical layout" pretitle="Overview" pageMenu="layout.vertical-right" pageLibs={['apexcharts', 'jsvectormap']} navbarPosition="vertical" sidebarEnd>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Right vertical layout" pretitle="Overview" pageMenu="layout.vertical-right" pageLibs={['apexcharts', 'vector-map']} navbarPosition="vertical" sidebarEnd>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical transparent layout" pretitle="Overview" pageMenu="layout.vertical-transparent" pageLibs={['apexcharts', 'jsvectormap']} navbarPosition="vertical" navbarTransparent>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical transparent layout" pretitle="Overview" pageMenu="layout.vertical-transparent" pageLibs={['apexcharts', 'vector-map']} navbarPosition="vertical" navbarTransparent>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -4,7 +4,7 @@ import HomepageContent from '@shared/components/HomepageContent.astro'
|
||||
import HeaderActionsButtons from '@shared/components/layout/HeaderActionsButtons.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical layout" pretitle="Overview" pageLibs={['apexcharts', 'jsvectormap']} pageMenu="layout.vertical" navbarPosition="vertical" sidebarFoldToggle>
|
||||
<DefaultLayout title="Dashboard" pageHeader="Vertical layout" pretitle="Overview" pageLibs={['apexcharts', 'vector-map']} pageMenu="layout.vertical" navbarPosition="vertical" sidebarFoldToggle>
|
||||
<HeaderActionsButtons slot="page-header-actions" />
|
||||
<HomepageContent />
|
||||
</DefaultLayout>
|
||||
@@ -7,14 +7,14 @@ import CardTitle from '@ui/CardTitle.astro'
|
||||
import DocsLink from '@ui/DocsLink.astro'
|
||||
---
|
||||
|
||||
<DefaultLayout title="Vector Maps" pageMenu="plugins.maps-vector" pageLibs={['jsvectormap']}>
|
||||
<DefaultLayout title="Vector Maps" pageMenu="plugins.maps-vector" pageLibs={['vector-map']}>
|
||||
<DocsLink slot="page-header-actions" path="/ui/plugins/vector-map" />
|
||||
<div class="row row-cards">
|
||||
<div class="col-md-6">
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>World map</CardTitle>
|
||||
<MapVector mapId="world-merc" />
|
||||
<MapVector mapId="world" legend />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -34,5 +34,29 @@ import DocsLink from '@ui/DocsLink.astro'
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>Map with a color scale</CardTitle>
|
||||
<MapVector mapId="world-colors" />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>Map with selection</CardTitle>
|
||||
<MapVector mapId="world-select" />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>Map with zoom</CardTitle>
|
||||
<MapVector mapId="world-zoom" />
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</DefaultLayout>
|
||||
@@ -73,10 +73,11 @@ const themeAttributes = themeDataAttributes({ ...theme, 'navbar-position': navba
|
||||
// whatever core's own watcher last emitted, which is unminified.
|
||||
const min = import.meta.env.DEV ? '' : '.min'
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string; maps?: string[] }
|
||||
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
||||
const libHref = (lib: Lib, file: string) => `/dist/libs/${lib.npm}/${file}`
|
||||
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
||||
const libMaps = pageLibEntries.flatMap(([, lib]) => lib.maps ?? [])
|
||||
const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
// ES-module-only libraries: imported in a module script and exposed as a global (see BaseLayout)
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
@@ -184,6 +185,7 @@ const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import *
|
||||
{libModules.map((code) => <Fragment set:html={`<script type="module">${code}</script>`} />)}
|
||||
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`/dist/js/${addon}${min}.js`} defer />)}
|
||||
{libMaps.map((map) => <script is:inline src={`/dist/js/maps/${map}.js`} defer />)}
|
||||
|
||||
<PageScripts />
|
||||
|
||||
|
||||
@@ -45,10 +45,11 @@ const rtlSuffix = rtl ? '.rtl' : ''
|
||||
// build instead of hardcoding one variant.
|
||||
const min = import.meta.env.DEV ? '' : '.min'
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; module?: { file: string; global: string }; addon?: string; maps?: string[] }
|
||||
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
||||
const libHref = (lib: Lib, file: string) => `/dist/libs/${lib.npm}/${file}`
|
||||
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
||||
const libMaps = pageLibEntries.flatMap(([, lib]) => lib.maps ?? [])
|
||||
const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
// ES-module-only libraries: imported in a module script and exposed as a global (see BaseLayout)
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
@@ -175,6 +176,7 @@ const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import *
|
||||
{libModules.map((code) => <Fragment set:html={`<script type="module">${code}</script>`} />)}
|
||||
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`/dist/js/${addon}${min}.js`} defer />)}
|
||||
{libMaps.map((map) => <script is:inline src={`/dist/js/maps/${map}.js`} defer />)}
|
||||
|
||||
<!-- components that render via CaptureScript (e.g. Chart) queue their init script
|
||||
into shared/lib/page-scripts instead of inlining it where used; this drains it. -->
|
||||
|
||||
@@ -7,14 +7,14 @@ import Subheader from '@ui/Subheader.astro'
|
||||
import ScaleLegend from '@components/demo/ScaleLegend.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Map" columns={2} pageLibs={['jsvectormap']} cssPlugins={['flags']}>
|
||||
<ScreenshotLayout title="Map" columns={2} pageLibs={['vector-map']} cssPlugins={['flags']}>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<h3 class="card-title m-0">Locations</h3>
|
||||
<ScaleLegend class="ms-auto" />
|
||||
</div>
|
||||
<MapVector mapId="world" color="primary" ratio="21x9" />
|
||||
<MapVector mapId="world" />
|
||||
|
||||
<div class="row g-3 mt-1">
|
||||
<div class="col-4">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
// The vector map with markers and the dashed lines between them: places set
|
||||
// by latitude and longitude, joined by name.
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import MapVector from '@components/demo/MapVector.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Map routes" columns={2} pageLibs={['vector-map']}>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Connections</h3>
|
||||
<MapVector mapId="world-lines" />
|
||||
</div>
|
||||
</div>
|
||||
</ScreenshotLayout>
|
||||
@@ -26,7 +26,7 @@ const countries: { name: string; flag: FlagCountry; users: string; share: number
|
||||
<div class="row g-0">
|
||||
<div class="col-lg-7 border-end">
|
||||
<CardBody>
|
||||
<MapVector mapId="world" ratio="16x9" />
|
||||
<MapVector mapId="world" />
|
||||
</CardBody>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
|
||||
@@ -13,6 +13,6 @@ const map = 'world'
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{title && <CardTitle>{title}</CardTitle>}
|
||||
<MapVector mapId={map} color="primary" ratio="21x9" />
|
||||
<MapVector mapId={map} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,160 +1,50 @@
|
||||
---
|
||||
import mapsVector from '@data/maps-vector.json';
|
||||
import CaptureScript from '../CaptureScript.astro';
|
||||
import mapsVector from '@data/maps-vector.json'
|
||||
|
||||
interface MapData {
|
||||
title?: string;
|
||||
map: string;
|
||||
color?: string;
|
||||
filled?: boolean;
|
||||
zoom?: boolean;
|
||||
values?: Record<string, string>;
|
||||
markers?: { name: string; coords: string }[];
|
||||
lines?: { from: string; to: string }[];
|
||||
title?: string
|
||||
map: string
|
||||
color?: string
|
||||
zoom?: boolean
|
||||
colors?: string[]
|
||||
legend?: boolean
|
||||
select?: 'single' | 'multiple'
|
||||
selected?: string[]
|
||||
values?: Record<string, number>
|
||||
markers?: { name: string; lat: number; lng: number }[]
|
||||
lines?: { from: string; to: string }[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
mapId: string;
|
||||
color?: string;
|
||||
ratio?: string;
|
||||
mapId: string
|
||||
color?: string
|
||||
/** the scale as a bar under the map; defaults to what the map data says */
|
||||
legend?: boolean
|
||||
}
|
||||
|
||||
const { mapId, color: colorProp, ratio = '4x3' } = Astro.props;
|
||||
const { mapId, color: colorProp, legend: legendProp } = Astro.props
|
||||
|
||||
const data = (mapsVector as Record<string, MapData>)[mapId];
|
||||
const color = colorProp ?? data?.color ?? 'primary';
|
||||
|
||||
// scale1..scale10 — a 10-step color-mix ramp against var(--tblr-primary).
|
||||
const scale = Object.fromEntries(
|
||||
Array.from({ length: 10 }, (_, n) => [
|
||||
`scale${n + 1}`,
|
||||
`color-mix(in srgb, transparent, var(--tblr-primary) ${(n + 1) * 10}%)`,
|
||||
]),
|
||||
);
|
||||
|
||||
const markers = data?.markers?.map((marker) => ({
|
||||
coords: marker.coords.split(',').map((n) => Number(n.trim())),
|
||||
name: marker.name,
|
||||
}));
|
||||
|
||||
const mapKey = `map-${mapId}`;
|
||||
const mapSelector = `#map-${mapId}`;
|
||||
const mapLabel = data?.title ?? 'Map';
|
||||
|
||||
// jsVectorMap renders its own zoom +/- buttons inside this container when
|
||||
// zoom is enabled. `role="img"` flattens all descendants for assistive
|
||||
// tech, which would swallow those buttons — so only apply it when there's
|
||||
// no interactive chrome to hide.
|
||||
const hasZoomControls = Boolean(data?.zoom);
|
||||
|
||||
const mapOptions = data
|
||||
? {
|
||||
backgroundColor: 'transparent',
|
||||
regionStyle: {
|
||||
initial: {
|
||||
fill: 'var(--tblr-bg-surface-secondary)',
|
||||
stroke: data.filled ? '#fff' : 'var(--tblr-border-color)',
|
||||
strokeWidth: 1,
|
||||
},
|
||||
},
|
||||
zoomOnScroll: Boolean(data.zoom),
|
||||
zoomButtons: Boolean(data.zoom),
|
||||
...(data.values
|
||||
? { series: { regions: [{ attribute: 'fill', scale, values: data.values }] } }
|
||||
: {}),
|
||||
...(markers
|
||||
? {
|
||||
markers,
|
||||
markerStyle: {
|
||||
initial: {
|
||||
r: 4,
|
||||
stroke: '#fff',
|
||||
opacity: 1,
|
||||
strokeWidth: 3,
|
||||
strokeOpacity: 0.5,
|
||||
fill: `var(--tblr-${color})`,
|
||||
},
|
||||
hover: { fill: `var(--tblr-${color})`, stroke: `var(--tblr-${color})` },
|
||||
},
|
||||
markerLabelStyle: { initial: { fontSize: 10 } },
|
||||
}
|
||||
: {}),
|
||||
...(data.lines
|
||||
? {
|
||||
lines: data.lines,
|
||||
lineStyle: {
|
||||
strokeDasharray: '4 4',
|
||||
animation: true,
|
||||
stroke: 'rgba(98, 105, 118, .75)',
|
||||
strokeWidth: 0.5,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
: undefined;
|
||||
const data = (mapsVector as Record<string, MapData>)[mapId]
|
||||
const color = colorProp ?? data?.color ?? 'primary'
|
||||
const legend = legendProp ?? data?.legend ?? false
|
||||
---
|
||||
|
||||
{
|
||||
data && (
|
||||
<Fragment>
|
||||
<div class={`ratio ratio-${ratio}`}>
|
||||
<div>
|
||||
<div
|
||||
id={mapKey}
|
||||
class="w-100 h-100"
|
||||
role={hasZoomControls ? undefined : 'img'}
|
||||
aria-label={mapLabel}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<CaptureScript>
|
||||
<!-- BEGIN MAP VECTOR -->
|
||||
<script is:inline define:vars={{ mapKey, mapSelector, mapName: data.map, mapOptions }}>
|
||||
window.tabler_map_vector ??= {};
|
||||
|
||||
function createMapVector() {
|
||||
const map = (window.tabler_map_vector[mapKey] = new jsVectorMap({
|
||||
selector: mapSelector,
|
||||
map: mapName,
|
||||
...mapOptions,
|
||||
// labels.markers.render is a function, not JSON-serializable — added here
|
||||
// rather than baked into mapOptions.
|
||||
...(mapOptions.markers ? { labels: { markers: { render: (marker) => marker.name } } } : {}),
|
||||
}));
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
map.updateSize();
|
||||
});
|
||||
}
|
||||
|
||||
function initMapVector() {
|
||||
const container = document.querySelector(mapSelector);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
// jsVectorMap computes its initial scale from the container's layout
|
||||
// size. If the container is still 0x0 (e.g. layout hasn't settled
|
||||
// yet), that scale ends up 0, and a later resize divides by it,
|
||||
// producing a NaN transform. Wait for real dimensions first.
|
||||
if (container.offsetWidth && container.offsetHeight) {
|
||||
createMapVector();
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver((entries) => {
|
||||
if (entries[0].contentRect.width && entries[0].contentRect.height) {
|
||||
observer.disconnect();
|
||||
createMapVector();
|
||||
}
|
||||
});
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
document.readyState !== 'loading' ? initMapVector() : document.addEventListener('DOMContentLoaded', initMapVector, { once: true });
|
||||
</script>
|
||||
<!-- END MAP VECTOR -->
|
||||
</CaptureScript>
|
||||
</Fragment>
|
||||
)
|
||||
data && (
|
||||
<div
|
||||
class="vector-map"
|
||||
data-bs-toggle="vector-map"
|
||||
data-bs-map={data.map}
|
||||
data-bs-label={data.title}
|
||||
data-bs-zoom={data.zoom ? 'true' : undefined}
|
||||
data-bs-legend={legend ? 'true' : undefined}
|
||||
data-bs-select={data.select}
|
||||
data-bs-selected={data.selected && JSON.stringify(data.selected)}
|
||||
data-bs-colors={data.colors && JSON.stringify(data.colors)}
|
||||
data-bs-values={data.values && JSON.stringify(data.values)}
|
||||
data-bs-markers={data.markers && JSON.stringify(data.markers)}
|
||||
data-bs-lines={data.lines && JSON.stringify(data.lines)}
|
||||
style={color === 'primary' ? undefined : `--tblr-vector-map-color: var(--tblr-${color})`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
+436
-393
@@ -9,425 +9,245 @@
|
||||
"map": "world",
|
||||
"color": "primary",
|
||||
"values": {
|
||||
"AF": "scale2",
|
||||
"AL": "scale2",
|
||||
"DZ": "scale4",
|
||||
"AO": "scale3",
|
||||
"AG": "scale1",
|
||||
"AR": "scale5",
|
||||
"AM": "scale1",
|
||||
"AU": "scale7",
|
||||
"AT": "scale5",
|
||||
"AZ": "scale3",
|
||||
"BS": "scale1",
|
||||
"BH": "scale2",
|
||||
"BD": "scale4",
|
||||
"BB": "scale1",
|
||||
"BY": "scale3",
|
||||
"BE": "scale5",
|
||||
"BZ": "scale1",
|
||||
"BJ": "scale1",
|
||||
"BT": "scale1",
|
||||
"BO": "scale2",
|
||||
"BA": "scale2",
|
||||
"BW": "scale2",
|
||||
"BR": "scale8",
|
||||
"BN": "scale2",
|
||||
"BG": "scale2",
|
||||
"BF": "scale1",
|
||||
"BI": "scale1",
|
||||
"KH": "scale2",
|
||||
"CM": "scale2",
|
||||
"CA": "scale7",
|
||||
"CV": "scale1",
|
||||
"CF": "scale1",
|
||||
"TD": "scale1",
|
||||
"CL": "scale4",
|
||||
"CN": "scale9",
|
||||
"CO": "scale5",
|
||||
"KM": "scale1",
|
||||
"CD": "scale2",
|
||||
"CG": "scale2",
|
||||
"CR": "scale2",
|
||||
"CI": "scale2",
|
||||
"HR": "scale3",
|
||||
"CY": "scale2",
|
||||
"CZ": "scale4",
|
||||
"DK": "scale5",
|
||||
"DJ": "scale1",
|
||||
"DM": "scale1",
|
||||
"DO": "scale3",
|
||||
"EC": "scale3",
|
||||
"EG": "scale5",
|
||||
"SV": "scale2",
|
||||
"GQ": "scale2",
|
||||
"ER": "scale1",
|
||||
"EE": "scale2",
|
||||
"ET": "scale2",
|
||||
"FJ": "scale1",
|
||||
"FI": "scale5",
|
||||
"FR": "scale8",
|
||||
"GA": "scale2",
|
||||
"GM": "scale1",
|
||||
"GE": "scale2",
|
||||
"DE": "scale8",
|
||||
"GH": "scale2",
|
||||
"GR": "scale5",
|
||||
"GD": "scale1",
|
||||
"GT": "scale2",
|
||||
"GN": "scale1",
|
||||
"GW": "scale1",
|
||||
"GY": "scale1",
|
||||
"HT": "scale1",
|
||||
"HN": "scale2",
|
||||
"HK": "scale5",
|
||||
"HU": "scale4",
|
||||
"IS": "scale2",
|
||||
"IN": "scale7",
|
||||
"ID": "scale6",
|
||||
"IR": "scale5",
|
||||
"IQ": "scale3",
|
||||
"IE": "scale5",
|
||||
"IL": "scale5",
|
||||
"IT": "scale8",
|
||||
"JM": "scale2",
|
||||
"JP": "scale9",
|
||||
"JO": "scale2",
|
||||
"KZ": "scale4",
|
||||
"KE": "scale2",
|
||||
"KI": "scale1",
|
||||
"KR": "scale6",
|
||||
"KW": "scale4",
|
||||
"KG": "scale1",
|
||||
"LA": "scale1",
|
||||
"LV": "scale2",
|
||||
"LB": "scale2",
|
||||
"LS": "scale1",
|
||||
"LR": "scale1",
|
||||
"LY": "scale3",
|
||||
"LT": "scale2",
|
||||
"LU": "scale3",
|
||||
"MK": "scale1",
|
||||
"MG": "scale1",
|
||||
"MW": "scale1",
|
||||
"MY": "scale5",
|
||||
"MV": "scale1",
|
||||
"ML": "scale1",
|
||||
"MT": "scale1",
|
||||
"MR": "scale1",
|
||||
"MU": "scale1",
|
||||
"MX": "scale7",
|
||||
"MD": "scale1",
|
||||
"MN": "scale1",
|
||||
"ME": "scale1",
|
||||
"MA": "scale3",
|
||||
"MZ": "scale2",
|
||||
"MM": "scale2",
|
||||
"NA": "scale2",
|
||||
"NP": "scale2",
|
||||
"NL": "scale6",
|
||||
"NZ": "scale4",
|
||||
"NI": "scale1",
|
||||
"NE": "scale1",
|
||||
"NG": "scale5",
|
||||
"NO": "scale5",
|
||||
"OM": "scale3",
|
||||
"PK": "scale4",
|
||||
"PA": "scale2",
|
||||
"PG": "scale1",
|
||||
"PY": "scale2",
|
||||
"PE": "scale4",
|
||||
"PH": "scale4",
|
||||
"PL": "scale10",
|
||||
"PT": "scale5",
|
||||
"QA": "scale4",
|
||||
"RO": "scale4",
|
||||
"RU": "scale7",
|
||||
"RW": "scale1",
|
||||
"WS": "scale1",
|
||||
"ST": "scale1",
|
||||
"SA": "scale5",
|
||||
"SN": "scale2",
|
||||
"RS": "scale2",
|
||||
"SC": "scale1",
|
||||
"SL": "scale1",
|
||||
"SG": "scale5",
|
||||
"SK": "scale3",
|
||||
"SI": "scale2",
|
||||
"SB": "scale1",
|
||||
"ZA": "scale5",
|
||||
"ES": "scale7",
|
||||
"LK": "scale2",
|
||||
"KN": "scale1",
|
||||
"LC": "scale1",
|
||||
"VC": "scale1",
|
||||
"SD": "scale3",
|
||||
"SR": "scale1",
|
||||
"SZ": "scale1",
|
||||
"SE": "scale5",
|
||||
"CH": "scale6",
|
||||
"SY": "scale3",
|
||||
"TW": "scale5",
|
||||
"TJ": "scale1",
|
||||
"TZ": "scale2",
|
||||
"TH": "scale5",
|
||||
"TL": "scale1",
|
||||
"TG": "scale1",
|
||||
"TO": "scale1",
|
||||
"TT": "scale2",
|
||||
"TN": "scale2",
|
||||
"TR": "scale6",
|
||||
"TM": "scale1",
|
||||
"UG": "scale2",
|
||||
"UA": "scale4",
|
||||
"AE": "scale5",
|
||||
"GB": "scale8",
|
||||
"US": "scale10",
|
||||
"UY": "scale2",
|
||||
"UZ": "scale2",
|
||||
"VU": "scale1",
|
||||
"VE": "scale5",
|
||||
"VN": "scale4",
|
||||
"YE": "scale2",
|
||||
"ZM": "scale2",
|
||||
"ZW": "scale1"
|
||||
}
|
||||
},
|
||||
"world-merc": {
|
||||
"title": "World map",
|
||||
"map": "world_merc",
|
||||
"color": "primary",
|
||||
"values": {
|
||||
"AF": "scale2",
|
||||
"AL": "scale2",
|
||||
"DZ": "scale4",
|
||||
"AO": "scale3",
|
||||
"AG": "scale1",
|
||||
"AR": "scale5",
|
||||
"AM": "scale1",
|
||||
"AU": "scale7",
|
||||
"AT": "scale5",
|
||||
"AZ": "scale3",
|
||||
"BS": "scale1",
|
||||
"BH": "scale2",
|
||||
"BD": "scale4",
|
||||
"BB": "scale1",
|
||||
"BY": "scale3",
|
||||
"BE": "scale5",
|
||||
"BZ": "scale1",
|
||||
"BJ": "scale1",
|
||||
"BT": "scale1",
|
||||
"BO": "scale2",
|
||||
"BA": "scale2",
|
||||
"BW": "scale2",
|
||||
"BR": "scale8",
|
||||
"BN": "scale2",
|
||||
"BG": "scale2",
|
||||
"BF": "scale1",
|
||||
"BI": "scale1",
|
||||
"KH": "scale2",
|
||||
"CM": "scale2",
|
||||
"CA": "scale7",
|
||||
"CV": "scale1",
|
||||
"CF": "scale1",
|
||||
"TD": "scale1",
|
||||
"CL": "scale4",
|
||||
"CN": "scale9",
|
||||
"CO": "scale5",
|
||||
"KM": "scale1",
|
||||
"CD": "scale2",
|
||||
"CG": "scale2",
|
||||
"CR": "scale2",
|
||||
"CI": "scale2",
|
||||
"HR": "scale3",
|
||||
"CY": "scale2",
|
||||
"CZ": "scale4",
|
||||
"DK": "scale5",
|
||||
"DJ": "scale1",
|
||||
"DM": "scale1",
|
||||
"DO": "scale3",
|
||||
"EC": "scale3",
|
||||
"EG": "scale5",
|
||||
"SV": "scale2",
|
||||
"GQ": "scale2",
|
||||
"ER": "scale1",
|
||||
"EE": "scale2",
|
||||
"ET": "scale2",
|
||||
"FJ": "scale1",
|
||||
"FI": "scale5",
|
||||
"FR": "scale8",
|
||||
"GA": "scale2",
|
||||
"GM": "scale1",
|
||||
"GE": "scale2",
|
||||
"DE": "scale8",
|
||||
"GH": "scale2",
|
||||
"GR": "scale5",
|
||||
"GD": "scale1",
|
||||
"GT": "scale2",
|
||||
"GN": "scale1",
|
||||
"GW": "scale1",
|
||||
"GY": "scale1",
|
||||
"HT": "scale1",
|
||||
"HN": "scale2",
|
||||
"HK": "scale5",
|
||||
"HU": "scale4",
|
||||
"IS": "scale2",
|
||||
"IN": "scale7",
|
||||
"ID": "scale6",
|
||||
"IR": "scale5",
|
||||
"IQ": "scale3",
|
||||
"IE": "scale5",
|
||||
"IL": "scale5",
|
||||
"IT": "scale8",
|
||||
"JM": "scale2",
|
||||
"JP": "scale9",
|
||||
"JO": "scale2",
|
||||
"KZ": "scale4",
|
||||
"KE": "scale2",
|
||||
"KI": "scale1",
|
||||
"KR": "scale6",
|
||||
"KW": "scale4",
|
||||
"KG": "scale1",
|
||||
"LA": "scale1",
|
||||
"LV": "scale2",
|
||||
"LB": "scale2",
|
||||
"LS": "scale1",
|
||||
"LR": "scale1",
|
||||
"LY": "scale3",
|
||||
"LT": "scale2",
|
||||
"LU": "scale3",
|
||||
"MK": "scale1",
|
||||
"MG": "scale1",
|
||||
"MW": "scale1",
|
||||
"MY": "scale5",
|
||||
"MV": "scale1",
|
||||
"ML": "scale1",
|
||||
"MT": "scale1",
|
||||
"MR": "scale1",
|
||||
"MU": "scale1",
|
||||
"MX": "scale7",
|
||||
"MD": "scale1",
|
||||
"MN": "scale1",
|
||||
"ME": "scale1",
|
||||
"MA": "scale3",
|
||||
"MZ": "scale2",
|
||||
"MM": "scale2",
|
||||
"NA": "scale2",
|
||||
"NP": "scale2",
|
||||
"NL": "scale6",
|
||||
"NZ": "scale4",
|
||||
"NI": "scale1",
|
||||
"NE": "scale1",
|
||||
"NG": "scale5",
|
||||
"NO": "scale5",
|
||||
"OM": "scale3",
|
||||
"PK": "scale4",
|
||||
"PA": "scale2",
|
||||
"PG": "scale1",
|
||||
"PY": "scale2",
|
||||
"PE": "scale4",
|
||||
"PH": "scale4",
|
||||
"PL": "scale10",
|
||||
"PT": "scale5",
|
||||
"QA": "scale4",
|
||||
"RO": "scale4",
|
||||
"RU": "scale7",
|
||||
"RW": "scale1",
|
||||
"WS": "scale1",
|
||||
"ST": "scale1",
|
||||
"SA": "scale5",
|
||||
"SN": "scale2",
|
||||
"RS": "scale2",
|
||||
"SC": "scale1",
|
||||
"SL": "scale1",
|
||||
"SG": "scale5",
|
||||
"SK": "scale3",
|
||||
"SI": "scale2",
|
||||
"SB": "scale1",
|
||||
"ZA": "scale5",
|
||||
"ES": "scale7",
|
||||
"LK": "scale2",
|
||||
"KN": "scale1",
|
||||
"LC": "scale1",
|
||||
"VC": "scale1",
|
||||
"SD": "scale3",
|
||||
"SR": "scale1",
|
||||
"SZ": "scale1",
|
||||
"SE": "scale5",
|
||||
"CH": "scale6",
|
||||
"SY": "scale3",
|
||||
"TW": "scale5",
|
||||
"TJ": "scale1",
|
||||
"TZ": "scale2",
|
||||
"TH": "scale5",
|
||||
"TL": "scale1",
|
||||
"TG": "scale1",
|
||||
"TO": "scale1",
|
||||
"TT": "scale2",
|
||||
"TN": "scale2",
|
||||
"TR": "scale6",
|
||||
"TM": "scale1",
|
||||
"UG": "scale2",
|
||||
"UA": "scale4",
|
||||
"AE": "scale5",
|
||||
"GB": "scale8",
|
||||
"US": "scale10",
|
||||
"UY": "scale2",
|
||||
"UZ": "scale2",
|
||||
"VU": "scale1",
|
||||
"VE": "scale5",
|
||||
"VN": "scale4",
|
||||
"YE": "scale2",
|
||||
"ZM": "scale2",
|
||||
"ZW": "scale1"
|
||||
"AF": 2,
|
||||
"AL": 2,
|
||||
"DZ": 4,
|
||||
"AO": 3,
|
||||
"AG": 1,
|
||||
"AR": 5,
|
||||
"AM": 1,
|
||||
"AU": 7,
|
||||
"AT": 5,
|
||||
"AZ": 3,
|
||||
"BS": 1,
|
||||
"BH": 2,
|
||||
"BD": 4,
|
||||
"BB": 1,
|
||||
"BY": 3,
|
||||
"BE": 5,
|
||||
"BZ": 1,
|
||||
"BJ": 1,
|
||||
"BT": 1,
|
||||
"BO": 2,
|
||||
"BA": 2,
|
||||
"BW": 2,
|
||||
"BR": 8,
|
||||
"BN": 2,
|
||||
"BG": 2,
|
||||
"BF": 1,
|
||||
"BI": 1,
|
||||
"KH": 2,
|
||||
"CM": 2,
|
||||
"CA": 7,
|
||||
"CV": 1,
|
||||
"CF": 1,
|
||||
"TD": 1,
|
||||
"CL": 4,
|
||||
"CN": 9,
|
||||
"CO": 5,
|
||||
"KM": 1,
|
||||
"CD": 2,
|
||||
"CG": 2,
|
||||
"CR": 2,
|
||||
"CI": 2,
|
||||
"HR": 3,
|
||||
"CY": 2,
|
||||
"CZ": 4,
|
||||
"DK": 5,
|
||||
"DJ": 1,
|
||||
"DM": 1,
|
||||
"DO": 3,
|
||||
"EC": 3,
|
||||
"EG": 5,
|
||||
"SV": 2,
|
||||
"GQ": 2,
|
||||
"ER": 1,
|
||||
"EE": 2,
|
||||
"ET": 2,
|
||||
"FJ": 1,
|
||||
"FI": 5,
|
||||
"FR": 8,
|
||||
"GA": 2,
|
||||
"GM": 1,
|
||||
"GE": 2,
|
||||
"DE": 8,
|
||||
"GH": 2,
|
||||
"GR": 5,
|
||||
"GD": 1,
|
||||
"GT": 2,
|
||||
"GN": 1,
|
||||
"GW": 1,
|
||||
"GY": 1,
|
||||
"HT": 1,
|
||||
"HN": 2,
|
||||
"HK": 5,
|
||||
"HU": 4,
|
||||
"IS": 2,
|
||||
"IN": 7,
|
||||
"ID": 6,
|
||||
"IR": 5,
|
||||
"IQ": 3,
|
||||
"IE": 5,
|
||||
"IL": 5,
|
||||
"IT": 8,
|
||||
"JM": 2,
|
||||
"JP": 9,
|
||||
"JO": 2,
|
||||
"KZ": 4,
|
||||
"KE": 2,
|
||||
"KI": 1,
|
||||
"KR": 6,
|
||||
"KW": 4,
|
||||
"KG": 1,
|
||||
"LA": 1,
|
||||
"LV": 2,
|
||||
"LB": 2,
|
||||
"LS": 1,
|
||||
"LR": 1,
|
||||
"LY": 3,
|
||||
"LT": 2,
|
||||
"LU": 3,
|
||||
"MK": 1,
|
||||
"MG": 1,
|
||||
"MW": 1,
|
||||
"MY": 5,
|
||||
"MV": 1,
|
||||
"ML": 1,
|
||||
"MT": 1,
|
||||
"MR": 1,
|
||||
"MU": 1,
|
||||
"MX": 7,
|
||||
"MD": 1,
|
||||
"MN": 1,
|
||||
"ME": 1,
|
||||
"MA": 3,
|
||||
"MZ": 2,
|
||||
"MM": 2,
|
||||
"NA": 2,
|
||||
"NP": 2,
|
||||
"NL": 6,
|
||||
"NZ": 4,
|
||||
"NI": 1,
|
||||
"NE": 1,
|
||||
"NG": 5,
|
||||
"NO": 5,
|
||||
"OM": 3,
|
||||
"PK": 4,
|
||||
"PA": 2,
|
||||
"PG": 1,
|
||||
"PY": 2,
|
||||
"PE": 4,
|
||||
"PH": 4,
|
||||
"PL": 10,
|
||||
"PT": 5,
|
||||
"QA": 4,
|
||||
"RO": 4,
|
||||
"RU": 7,
|
||||
"RW": 1,
|
||||
"WS": 1,
|
||||
"ST": 1,
|
||||
"SA": 5,
|
||||
"SN": 2,
|
||||
"RS": 2,
|
||||
"SC": 1,
|
||||
"SL": 1,
|
||||
"SG": 5,
|
||||
"SK": 3,
|
||||
"SI": 2,
|
||||
"SB": 1,
|
||||
"ZA": 5,
|
||||
"ES": 7,
|
||||
"LK": 2,
|
||||
"KN": 1,
|
||||
"LC": 1,
|
||||
"VC": 1,
|
||||
"SD": 3,
|
||||
"SR": 1,
|
||||
"SZ": 1,
|
||||
"SE": 5,
|
||||
"CH": 6,
|
||||
"SY": 3,
|
||||
"TW": 5,
|
||||
"TJ": 1,
|
||||
"TZ": 2,
|
||||
"TH": 5,
|
||||
"TL": 1,
|
||||
"TG": 1,
|
||||
"TO": 1,
|
||||
"TT": 2,
|
||||
"TN": 2,
|
||||
"TR": 6,
|
||||
"TM": 1,
|
||||
"UG": 2,
|
||||
"UA": 4,
|
||||
"AE": 5,
|
||||
"GB": 8,
|
||||
"US": 10,
|
||||
"UY": 2,
|
||||
"UZ": 2,
|
||||
"VU": 1,
|
||||
"VE": 5,
|
||||
"VN": 4,
|
||||
"YE": 2,
|
||||
"ZM": 2,
|
||||
"ZW": 1
|
||||
}
|
||||
},
|
||||
"world-markers": {
|
||||
"title": "Map with markers",
|
||||
"map": "world_merc",
|
||||
"map": "world",
|
||||
"color": "red",
|
||||
"markers": [
|
||||
{
|
||||
"name": "Russia",
|
||||
"coords": "61.524, 105.3188"
|
||||
"lat": 61.524,
|
||||
"lng": 105.3188
|
||||
},
|
||||
{
|
||||
"name": "Canada",
|
||||
"coords": "56.1304, -106.3468"
|
||||
"lat": 56.1304,
|
||||
"lng": -106.3468
|
||||
},
|
||||
{
|
||||
"name": "Greenland",
|
||||
"coords": "71.7069, -42.6043"
|
||||
"lat": 71.7069,
|
||||
"lng": -42.6043
|
||||
},
|
||||
{
|
||||
"name": "Egypt",
|
||||
"coords": "26.8206, 30.8025"
|
||||
"lat": 26.8206,
|
||||
"lng": 30.8025
|
||||
},
|
||||
{
|
||||
"name": "Brazil",
|
||||
"coords": "-14.235, -51.9253"
|
||||
"lat": -14.235,
|
||||
"lng": -51.9253
|
||||
},
|
||||
{
|
||||
"name": "China",
|
||||
"coords": "35.8617, 104.1954"
|
||||
"lat": 35.8617,
|
||||
"lng": 104.1954
|
||||
},
|
||||
{
|
||||
"name": "United States",
|
||||
"coords": "37.0902, -95.7129"
|
||||
"lat": 37.0902,
|
||||
"lng": -95.7129
|
||||
},
|
||||
{
|
||||
"name": "Norway",
|
||||
"coords": "60.472024, 8.468946"
|
||||
"lat": 60.472024,
|
||||
"lng": 8.468946
|
||||
},
|
||||
{
|
||||
"name": "Ukraine",
|
||||
"coords": "48.379433, 31.16558"
|
||||
"lat": 48.379433,
|
||||
"lng": 31.16558
|
||||
}
|
||||
]
|
||||
},
|
||||
"world-lines": {
|
||||
"title": "Map with markers",
|
||||
"map": "world_merc",
|
||||
"title": "Map with markers and lines",
|
||||
"map": "world",
|
||||
"color": "primary",
|
||||
"lines": [
|
||||
{
|
||||
@@ -462,40 +282,263 @@
|
||||
"markers": [
|
||||
{
|
||||
"name": "Russia",
|
||||
"coords": "61.524, 105.3188"
|
||||
"lat": 61.524,
|
||||
"lng": 105.3188
|
||||
},
|
||||
{
|
||||
"name": "Canada",
|
||||
"coords": "56.1304, -106.3468"
|
||||
"lat": 56.1304,
|
||||
"lng": -106.3468
|
||||
},
|
||||
{
|
||||
"name": "Greenland",
|
||||
"coords": "71.7069, -42.6043"
|
||||
"lat": 71.7069,
|
||||
"lng": -42.6043
|
||||
},
|
||||
{
|
||||
"name": "Egypt",
|
||||
"coords": "26.8206, 30.8025"
|
||||
"lat": 26.8206,
|
||||
"lng": 30.8025
|
||||
},
|
||||
{
|
||||
"name": "Brazil",
|
||||
"coords": "-14.235, -51.9253"
|
||||
"lat": -14.235,
|
||||
"lng": -51.9253
|
||||
},
|
||||
{
|
||||
"name": "China",
|
||||
"coords": "35.8617, 104.1954"
|
||||
"lat": 35.8617,
|
||||
"lng": 104.1954
|
||||
},
|
||||
{
|
||||
"name": "United States",
|
||||
"coords": "37.0902, -95.7129"
|
||||
"lat": 37.0902,
|
||||
"lng": -95.7129
|
||||
},
|
||||
{
|
||||
"name": "Norway",
|
||||
"coords": "60.472024, 8.468946"
|
||||
"lat": 60.472024,
|
||||
"lng": 8.468946
|
||||
},
|
||||
{
|
||||
"name": "Ukraine",
|
||||
"coords": "48.379433, 31.16558"
|
||||
"lat": 48.379433,
|
||||
"lng": 31.16558
|
||||
}
|
||||
]
|
||||
},
|
||||
"world-zoom": {
|
||||
"title": "Map with zoom",
|
||||
"map": "world",
|
||||
"color": "green",
|
||||
"zoom": true,
|
||||
"values": {
|
||||
"PL": 8,
|
||||
"DE": 6,
|
||||
"FR": 5,
|
||||
"ES": 3,
|
||||
"IT": 4,
|
||||
"GB": 7,
|
||||
"SE": 2,
|
||||
"UA": 3,
|
||||
"RO": 2,
|
||||
"CZ": 5
|
||||
}
|
||||
},
|
||||
"world-colors": {
|
||||
"title": "Map with a color scale",
|
||||
"map": "world",
|
||||
"colors": ["var(--tblr-red)", "var(--tblr-yellow)", "var(--tblr-green)"],
|
||||
"values": {
|
||||
"AF": 2,
|
||||
"AL": 2,
|
||||
"DZ": 4,
|
||||
"AO": 3,
|
||||
"AG": 1,
|
||||
"AR": 5,
|
||||
"AM": 1,
|
||||
"AU": 7,
|
||||
"AT": 5,
|
||||
"AZ": 3,
|
||||
"BS": 1,
|
||||
"BH": 2,
|
||||
"BD": 4,
|
||||
"BB": 1,
|
||||
"BY": 3,
|
||||
"BE": 5,
|
||||
"BZ": 1,
|
||||
"BJ": 1,
|
||||
"BT": 1,
|
||||
"BO": 2,
|
||||
"BA": 2,
|
||||
"BW": 2,
|
||||
"BR": 8,
|
||||
"BN": 2,
|
||||
"BG": 2,
|
||||
"BF": 1,
|
||||
"BI": 1,
|
||||
"KH": 2,
|
||||
"CM": 2,
|
||||
"CA": 7,
|
||||
"CV": 1,
|
||||
"CF": 1,
|
||||
"TD": 1,
|
||||
"CL": 4,
|
||||
"CN": 9,
|
||||
"CO": 5,
|
||||
"KM": 1,
|
||||
"CD": 2,
|
||||
"CG": 2,
|
||||
"CR": 2,
|
||||
"CI": 2,
|
||||
"HR": 3,
|
||||
"CY": 2,
|
||||
"CZ": 4,
|
||||
"DK": 5,
|
||||
"DJ": 1,
|
||||
"DM": 1,
|
||||
"DO": 3,
|
||||
"EC": 3,
|
||||
"EG": 5,
|
||||
"SV": 2,
|
||||
"GQ": 2,
|
||||
"ER": 1,
|
||||
"EE": 2,
|
||||
"ET": 2,
|
||||
"FJ": 1,
|
||||
"FI": 5,
|
||||
"FR": 8,
|
||||
"GA": 2,
|
||||
"GM": 1,
|
||||
"GE": 2,
|
||||
"DE": 8,
|
||||
"GH": 2,
|
||||
"GR": 5,
|
||||
"GD": 1,
|
||||
"GT": 2,
|
||||
"GN": 1,
|
||||
"GW": 1,
|
||||
"GY": 1,
|
||||
"HT": 1,
|
||||
"HN": 2,
|
||||
"HK": 5,
|
||||
"HU": 4,
|
||||
"IS": 2,
|
||||
"IN": 7,
|
||||
"ID": 6,
|
||||
"IR": 5,
|
||||
"IQ": 3,
|
||||
"IE": 5,
|
||||
"IL": 5,
|
||||
"IT": 8,
|
||||
"JM": 2,
|
||||
"JP": 9,
|
||||
"JO": 2,
|
||||
"KZ": 4,
|
||||
"KE": 2,
|
||||
"KI": 1,
|
||||
"KR": 6,
|
||||
"KW": 4,
|
||||
"KG": 1,
|
||||
"LA": 1,
|
||||
"LV": 2,
|
||||
"LB": 2,
|
||||
"LS": 1,
|
||||
"LR": 1,
|
||||
"LY": 3,
|
||||
"LT": 2,
|
||||
"LU": 3,
|
||||
"MK": 1,
|
||||
"MG": 1,
|
||||
"MW": 1,
|
||||
"MY": 5,
|
||||
"MV": 1,
|
||||
"ML": 1,
|
||||
"MT": 1,
|
||||
"MR": 1,
|
||||
"MU": 1,
|
||||
"MX": 7,
|
||||
"MD": 1,
|
||||
"MN": 1,
|
||||
"ME": 1,
|
||||
"MA": 3,
|
||||
"MZ": 2,
|
||||
"MM": 2,
|
||||
"NA": 2,
|
||||
"NP": 2,
|
||||
"NL": 6,
|
||||
"NZ": 4,
|
||||
"NI": 1,
|
||||
"NE": 1,
|
||||
"NG": 5,
|
||||
"NO": 5,
|
||||
"OM": 3,
|
||||
"PK": 4,
|
||||
"PA": 2,
|
||||
"PG": 1,
|
||||
"PY": 2,
|
||||
"PE": 4,
|
||||
"PH": 4,
|
||||
"PL": 10,
|
||||
"PT": 5,
|
||||
"QA": 4,
|
||||
"RO": 4,
|
||||
"RU": 7,
|
||||
"RW": 1,
|
||||
"WS": 1,
|
||||
"ST": 1,
|
||||
"SA": 5,
|
||||
"SN": 2,
|
||||
"RS": 2,
|
||||
"SC": 1,
|
||||
"SL": 1,
|
||||
"SG": 5,
|
||||
"SK": 3,
|
||||
"SI": 2,
|
||||
"SB": 1,
|
||||
"ZA": 5,
|
||||
"ES": 7,
|
||||
"LK": 2,
|
||||
"KN": 1,
|
||||
"LC": 1,
|
||||
"VC": 1,
|
||||
"SD": 3,
|
||||
"SR": 1,
|
||||
"SZ": 1,
|
||||
"SE": 5,
|
||||
"CH": 6,
|
||||
"SY": 3,
|
||||
"TW": 5,
|
||||
"TJ": 1,
|
||||
"TZ": 2,
|
||||
"TH": 5,
|
||||
"TL": 1,
|
||||
"TG": 1,
|
||||
"TO": 1,
|
||||
"TT": 2,
|
||||
"TN": 2,
|
||||
"TR": 6,
|
||||
"TM": 1,
|
||||
"UG": 2,
|
||||
"UA": 4,
|
||||
"AE": 5,
|
||||
"GB": 8,
|
||||
"US": 10,
|
||||
"UY": 2,
|
||||
"UZ": 2,
|
||||
"VU": 1,
|
||||
"VE": 5,
|
||||
"VN": 4,
|
||||
"YE": 2,
|
||||
"ZM": 2,
|
||||
"ZW": 1
|
||||
},
|
||||
"legend": true
|
||||
},
|
||||
"world-select": {
|
||||
"title": "Map with selection",
|
||||
"map": "world",
|
||||
"select": "multiple",
|
||||
"selected": ["PL", "FR", "BR", "AU"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,13 @@
|
||||
"description": "Lightweight JavaScript library for creating interactive maps and data visualizations.",
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "Natural Earth",
|
||||
"lib": "vector-map",
|
||||
"url": "https://www.naturalearthdata.com/",
|
||||
"description": "Public domain map dataset, the source of the country shapes in the vector map.",
|
||||
"license": "Public Domain"
|
||||
},
|
||||
{
|
||||
"name": "List.js",
|
||||
"npm": "list.js",
|
||||
|
||||
@@ -9,7 +9,7 @@ import { themeDefaults, themePresets, sidebarOnlyKeys, navbarOnlyKeys, themeData
|
||||
|
||||
interface Props {
|
||||
title?: string | undefined
|
||||
/** Third-party libs from libs.json, e.g. ['apexcharts', 'jsvectormap'] */
|
||||
/** Third-party libs from libs.json, e.g. ['apexcharts', 'vector-map'] */
|
||||
pageLibs?: string[] | undefined
|
||||
/** Extra body classes, e.g. "layout-boxed" / "layout-fluid" */
|
||||
bodyClass?: string | undefined
|
||||
@@ -39,7 +39,7 @@ const isProduction = process.env.VERCEL_ENV === 'production'
|
||||
// RTL swaps tabler/plugin stylesheets for their .rtl.css variants (demo stays LTR)
|
||||
const rtlSuffix = rtl ? '.rtl' : ''
|
||||
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; head?: boolean; module?: { file: string; global: string }; addon?: string }
|
||||
type Lib = { npm?: string; js?: string[]; css?: string[]; head?: boolean; module?: { file: string; global: string }; addon?: string; maps?: string[] }
|
||||
const unknownLibs = pageLibs.filter((name) => !(name in libs))
|
||||
if (unknownLibs.length > 0) {
|
||||
throw new Error(`BaseLayout: unknown pageLibs ${unknownLibs.map((name) => `"${name}"`).join(', ')} — use a key from core/libs.json`)
|
||||
@@ -54,6 +54,8 @@ const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((fil
|
||||
const libModules = pageLibEntries.flatMap(([, lib]) => (lib.module ? [`import * as lib from '${libHref(lib, lib.module.file)}'\n window.${lib.module.global} = lib`] : []))
|
||||
// Tabler add-on bundles (dist/js) that a library needs, loaded after tabler.js
|
||||
const libAddons = pageLibEntries.flatMap(([, lib]) => (lib.addon ? [lib.addon] : []))
|
||||
// Map files of the vector map (dist/js/maps), which are plain data
|
||||
const libMaps = pageLibEntries.flatMap(([, lib]) => lib.maps ?? [])
|
||||
const libJsFiles = (head: boolean) => pageLibEntries.filter(([, lib]) => Boolean(lib.head) === head).flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
||||
---
|
||||
|
||||
@@ -140,6 +142,7 @@ const libJsFiles = (head: boolean) => pageLibEntries.filter(([, lib]) => Boolean
|
||||
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
||||
<script is:inline src={`${base}/dist/js/tabler${min}.js`} defer></script>
|
||||
{libAddons.map((addon) => <script is:inline src={`${base}/dist/js/${addon}${min}.js`} defer />)}
|
||||
{libMaps.map((map) => <script is:inline src={`${base}/dist/js/maps/${map}.js`} defer />)}
|
||||
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
||||
|
||||
<PageScripts />
|
||||
|
||||
Reference in new issue
Block a user