svgmap 2.20.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/index.cjs +317 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +317 -179
- package/dist/index.js.map +1 -1
- package/dist/svg-map.css +9 -0
- package/dist/svg-map.min.css +1 -1
- package/dist/svg-map.umd.js +317 -179
- package/dist/svg-map.umd.js.map +1 -1
- package/dist/svg-map.umd.min.js +1 -1
- package/dist/svgMap.css +9 -0
- package/dist/svgMap.js +317 -179
- package/dist/svgMap.js.map +1 -1
- package/dist/svgMap.min.css +1 -1
- package/dist/svgMap.min.js +1 -1
- package/package.json +4 -4
- package/src/js/core/svg-map.js +317 -179
- package/src/scss/map.scss +11 -0
package/dist/index.js
CHANGED
|
@@ -2373,7 +2373,34 @@ class svgMap {
|
|
|
2373
2373
|
showContinentSelector: false,
|
|
2374
2374
|
|
|
2375
2375
|
// Reset zoom on resize
|
|
2376
|
-
resetZoomOnResize: false
|
|
2376
|
+
resetZoomOnResize: false,
|
|
2377
|
+
|
|
2378
|
+
// Static pins: false | string[] | function(countryID, countryValues) => boolean
|
|
2379
|
+
staticPins: false,
|
|
2380
|
+
|
|
2381
|
+
// Default pin fill color
|
|
2382
|
+
pinColor: '#000000',
|
|
2383
|
+
|
|
2384
|
+
// Default pin stroke color and width (circle pins; width is in screen pixels with non-scaling stroke)
|
|
2385
|
+
pinStrokeColor: '#ffffff',
|
|
2386
|
+
pinStrokeWidth: 1.5,
|
|
2387
|
+
|
|
2388
|
+
// Default pin radius in SVG units (viewBox is 2000 × 1001)
|
|
2389
|
+
pinSize: 8,
|
|
2390
|
+
|
|
2391
|
+
// Custom pin element: function(countryID, countryValues) => SVGElement | null
|
|
2392
|
+
onGetPin: null,
|
|
2393
|
+
|
|
2394
|
+
// Image URL to use as a pin instead of the default circle (can also be set per-country via values[id].pinImage)
|
|
2395
|
+
pinImage: null,
|
|
2396
|
+
|
|
2397
|
+
// Width and height of the pin image in SVG units (viewBox is 2000 × 1001)
|
|
2398
|
+
pinImageWidth: 20,
|
|
2399
|
+
pinImageHeight: 20,
|
|
2400
|
+
|
|
2401
|
+
// Offset from computed pin position, in SVG units (added after auto center or pinX/pinY)
|
|
2402
|
+
pinOffsetX: 0,
|
|
2403
|
+
pinOffsetY: 0
|
|
2377
2404
|
};
|
|
2378
2405
|
|
|
2379
2406
|
this.options = Object.assign({}, defaultOptions, options);
|
|
@@ -3225,6 +3252,102 @@ class svgMap {
|
|
|
3225
3252
|
|
|
3226
3253
|
// Add map elements
|
|
3227
3254
|
var countryElements = [];
|
|
3255
|
+
|
|
3256
|
+
const clearActive = function clearActive() {
|
|
3257
|
+
this.mapImage
|
|
3258
|
+
.querySelectorAll('.svgMap-active')
|
|
3259
|
+
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3260
|
+
}.bind(this);
|
|
3261
|
+
|
|
3262
|
+
const isClickTooltip =
|
|
3263
|
+
this.options.showTooltips && this.options.tooltipTrigger === 'click';
|
|
3264
|
+
|
|
3265
|
+
const getCountryFromEvent = function (e) {
|
|
3266
|
+
return e.target && e.target.closest
|
|
3267
|
+
? e.target.closest('.svgMap-country')
|
|
3268
|
+
: null;
|
|
3269
|
+
};
|
|
3270
|
+
|
|
3271
|
+
const raiseCountry = function (countryElement, setActive) {
|
|
3272
|
+
if (setActive) {
|
|
3273
|
+
clearActive();
|
|
3274
|
+
}
|
|
3275
|
+
countryElement.parentNode.insertBefore(
|
|
3276
|
+
countryElement,
|
|
3277
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3278
|
+
);
|
|
3279
|
+
if (setActive) {
|
|
3280
|
+
countryElement.classList.add('svgMap-active');
|
|
3281
|
+
}
|
|
3282
|
+
}.bind(this);
|
|
3283
|
+
|
|
3284
|
+
const showCountryTooltip = function (countryElement, e, setActive) {
|
|
3285
|
+
raiseCountry(countryElement, setActive);
|
|
3286
|
+
this.setTooltipContent(this.getTooltipContent(countryElement.dataset.id));
|
|
3287
|
+
this.showTooltip(e);
|
|
3288
|
+
}.bind(this);
|
|
3289
|
+
|
|
3290
|
+
// Touch only: preview tooltip on finger down without marking country active
|
|
3291
|
+
// (active is set on pointerup so link countries keep two-tap navigation)
|
|
3292
|
+
this.mapImage.addEventListener(
|
|
3293
|
+
'pointerdown',
|
|
3294
|
+
(e) => {
|
|
3295
|
+
if (!this.options.showTooltips || e.pointerType !== 'touch') {
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
const countryElement = getCountryFromEvent(e);
|
|
3300
|
+
if (!countryElement) {
|
|
3301
|
+
this.hideTooltip();
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
showCountryTooltip(countryElement, e, false);
|
|
3306
|
+
this.moveTooltip(e);
|
|
3307
|
+
},
|
|
3308
|
+
{ passive: true }
|
|
3309
|
+
);
|
|
3310
|
+
|
|
3311
|
+
this.mapImage.addEventListener(
|
|
3312
|
+
'pointercancel',
|
|
3313
|
+
(e) => {
|
|
3314
|
+
if (e.pointerType === 'touch') {
|
|
3315
|
+
this.hideTooltip();
|
|
3316
|
+
}
|
|
3317
|
+
},
|
|
3318
|
+
{ passive: true }
|
|
3319
|
+
);
|
|
3320
|
+
|
|
3321
|
+
// Hover (mouse/pen) and touch drag: raise country + optional floating tooltip
|
|
3322
|
+
this.mapImage.addEventListener(
|
|
3323
|
+
'pointermove',
|
|
3324
|
+
(e) => {
|
|
3325
|
+
const countryElement = getCountryFromEvent(e);
|
|
3326
|
+
if (!countryElement) {
|
|
3327
|
+
clearActive();
|
|
3328
|
+
if (this.options.showTooltips) {
|
|
3329
|
+
this.hideTooltip();
|
|
3330
|
+
}
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3334
|
+
const mouseClickMode = e.pointerType === 'mouse' && isClickTooltip;
|
|
3335
|
+
|
|
3336
|
+
// Always raise hovered country (SVG paint order + .svgMap-active stroke)
|
|
3337
|
+
if (!this.options.showTooltips || mouseClickMode) {
|
|
3338
|
+
raiseCountry(countryElement, true);
|
|
3339
|
+
return;
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
showCountryTooltip(countryElement, e, true);
|
|
3343
|
+
|
|
3344
|
+
if (e.pointerType === 'touch') {
|
|
3345
|
+
this.moveTooltip(e);
|
|
3346
|
+
}
|
|
3347
|
+
},
|
|
3348
|
+
{ passive: true }
|
|
3349
|
+
);
|
|
3350
|
+
|
|
3228
3351
|
Object.keys(mapPaths).forEach(
|
|
3229
3352
|
function (countryID) {
|
|
3230
3353
|
var countryData = this.mapPaths[countryID];
|
|
@@ -3242,166 +3365,22 @@ class svgMap {
|
|
|
3242
3365
|
'id',
|
|
3243
3366
|
this.id + '-map-country-' + countryID
|
|
3244
3367
|
);
|
|
3245
|
-
countryElement.
|
|
3368
|
+
countryElement.dataset.id = countryID;
|
|
3246
3369
|
countryElement.classList.add('svgMap-country');
|
|
3247
3370
|
|
|
3248
3371
|
this.mapImage.appendChild(countryElement);
|
|
3249
3372
|
countryElements.push(countryElement);
|
|
3250
3373
|
|
|
3251
|
-
// Add tooltip when touch is used
|
|
3252
|
-
function handlePointerMove(e) {
|
|
3253
|
-
if (e.pointerType === 'touch') return;
|
|
3254
|
-
|
|
3255
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
3256
|
-
|
|
3257
|
-
if (
|
|
3258
|
-
!target ||
|
|
3259
|
-
(!target.closest('.svgMap-country') &&
|
|
3260
|
-
!target.closest('.svgMap-tooltip'))
|
|
3261
|
-
) {
|
|
3262
|
-
this.hideTooltip();
|
|
3263
|
-
document
|
|
3264
|
-
.querySelectorAll('.svgMap-active')
|
|
3265
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3266
|
-
}
|
|
3267
|
-
}
|
|
3268
|
-
|
|
3269
|
-
const handlePointerMoveBound = handlePointerMove.bind(this);
|
|
3270
|
-
|
|
3271
|
-
countryElement.addEventListener(
|
|
3272
|
-
'pointerenter',
|
|
3273
|
-
function (e) {
|
|
3274
|
-
if (
|
|
3275
|
-
e.pointerType === 'mouse' &&
|
|
3276
|
-
this.options.showTooltips &&
|
|
3277
|
-
this.options.tooltipTrigger === 'click'
|
|
3278
|
-
) {
|
|
3279
|
-
return;
|
|
3280
|
-
}
|
|
3281
|
-
|
|
3282
|
-
// Only add pointermove listener for non-touch pointers
|
|
3283
|
-
if (e.pointerType !== 'touch') {
|
|
3284
|
-
document.addEventListener('pointermove', handlePointerMoveBound, {
|
|
3285
|
-
passive: true
|
|
3286
|
-
});
|
|
3287
|
-
}
|
|
3288
|
-
|
|
3289
|
-
document
|
|
3290
|
-
.querySelectorAll('.svgMap-active')
|
|
3291
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3292
|
-
|
|
3293
|
-
countryElement.parentNode.insertBefore(
|
|
3294
|
-
countryElement,
|
|
3295
|
-
this.persistentTooltipGroup || null
|
|
3296
|
-
);
|
|
3297
|
-
countryElement.classList.add('svgMap-active');
|
|
3298
|
-
|
|
3299
|
-
const countryID = countryElement.getAttribute('data-id');
|
|
3300
|
-
if (this.options.showTooltips) {
|
|
3301
|
-
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3302
|
-
this.showTooltip(e);
|
|
3303
|
-
|
|
3304
|
-
// For touch, move tooltip to the touch position and keep it there
|
|
3305
|
-
if (e.pointerType === 'touch') {
|
|
3306
|
-
this.moveTooltip(e);
|
|
3307
|
-
}
|
|
3308
|
-
}
|
|
3309
|
-
}.bind(this)
|
|
3310
|
-
);
|
|
3311
|
-
|
|
3312
|
-
// Handle touch move - update tooltip position while panning
|
|
3313
|
-
countryElement.addEventListener(
|
|
3314
|
-
'touchmove',
|
|
3315
|
-
function (e) {
|
|
3316
|
-
this.moveTooltip(e);
|
|
3317
|
-
}.bind(this),
|
|
3318
|
-
{ passive: true }
|
|
3319
|
-
);
|
|
3320
|
-
|
|
3321
|
-
// Handle touch end - remove active state and hide tooltip
|
|
3322
|
-
countryElement.addEventListener(
|
|
3323
|
-
'touchend',
|
|
3324
|
-
function (e) {
|
|
3325
|
-
const touch = e.changedTouches[0];
|
|
3326
|
-
const elementAtEnd = document.elementFromPoint(
|
|
3327
|
-
touch.clientX,
|
|
3328
|
-
touch.clientY
|
|
3329
|
-
);
|
|
3330
|
-
|
|
3331
|
-
// Only hide if touch ended outside the country or tooltip
|
|
3332
|
-
if (
|
|
3333
|
-
!elementAtEnd ||
|
|
3334
|
-
(!elementAtEnd.closest('.svgMap-country') &&
|
|
3335
|
-
!elementAtEnd.closest('.svgMap-tooltip'))
|
|
3336
|
-
) {
|
|
3337
|
-
this.hideTooltip();
|
|
3338
|
-
document
|
|
3339
|
-
.querySelectorAll('.svgMap-active')
|
|
3340
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3341
|
-
}
|
|
3342
|
-
}.bind(this),
|
|
3343
|
-
{ passive: true }
|
|
3344
|
-
);
|
|
3345
|
-
|
|
3346
|
-
// Remove pointermove listener when leaving non-touch pointer
|
|
3347
|
-
countryElement.addEventListener(
|
|
3348
|
-
'pointerleave',
|
|
3349
|
-
function (e) {
|
|
3350
|
-
if (e.pointerType !== 'touch') {
|
|
3351
|
-
document.removeEventListener(
|
|
3352
|
-
'pointermove',
|
|
3353
|
-
handlePointerMoveBound
|
|
3354
|
-
);
|
|
3355
|
-
if (
|
|
3356
|
-
!(
|
|
3357
|
-
e.pointerType === 'mouse' &&
|
|
3358
|
-
this.options.showTooltips &&
|
|
3359
|
-
this.options.tooltipTrigger === 'click'
|
|
3360
|
-
)
|
|
3361
|
-
) {
|
|
3362
|
-
this.hideTooltip();
|
|
3363
|
-
document
|
|
3364
|
-
.querySelectorAll('.svgMap-active')
|
|
3365
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3366
|
-
}
|
|
3367
|
-
}
|
|
3368
|
-
}.bind(this)
|
|
3369
|
-
);
|
|
3370
|
-
|
|
3371
|
-
document.addEventListener(
|
|
3372
|
-
'pointerover',
|
|
3373
|
-
function (e) {
|
|
3374
|
-
if (e.pointerType !== 'touch') return;
|
|
3375
|
-
|
|
3376
|
-
if (
|
|
3377
|
-
e.target.closest('.svgMap-country') ||
|
|
3378
|
-
e.target.closest('.svgMap-tooltip')
|
|
3379
|
-
) {
|
|
3380
|
-
return;
|
|
3381
|
-
}
|
|
3382
|
-
|
|
3383
|
-
this.hideTooltip();
|
|
3384
|
-
document
|
|
3385
|
-
.querySelectorAll('.svgMap-active')
|
|
3386
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3387
|
-
}.bind(this),
|
|
3388
|
-
{ passive: true }
|
|
3389
|
-
);
|
|
3390
|
-
|
|
3391
3374
|
if (
|
|
3392
3375
|
this.options.data.values &&
|
|
3393
3376
|
this.options.data.values[countryID] &&
|
|
3394
3377
|
this.options.data.values[countryID]['link']
|
|
3395
3378
|
) {
|
|
3396
|
-
countryElement.
|
|
3397
|
-
'
|
|
3398
|
-
this.options.data.values[countryID]['link']
|
|
3399
|
-
);
|
|
3379
|
+
countryElement.dataset.link =
|
|
3380
|
+
this.options.data.values[countryID]['link'];
|
|
3400
3381
|
if (this.options.data.values[countryID]['linkTarget']) {
|
|
3401
|
-
countryElement.
|
|
3402
|
-
|
|
3403
|
-
this.options.data.values[countryID]['linkTarget']
|
|
3404
|
-
);
|
|
3382
|
+
countryElement.dataset.linkTarget =
|
|
3383
|
+
this.options.data.values[countryID]['linkTarget'];
|
|
3405
3384
|
}
|
|
3406
3385
|
}
|
|
3407
3386
|
}.bind(this)
|
|
@@ -3415,6 +3394,10 @@ class svgMap {
|
|
|
3415
3394
|
this.createPersistentTooltips(countryElements);
|
|
3416
3395
|
}
|
|
3417
3396
|
|
|
3397
|
+
if (this.options.staticPins) {
|
|
3398
|
+
this.createStaticPins(countryElements);
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3418
3401
|
let pointerStart = null;
|
|
3419
3402
|
let activeCountry = null;
|
|
3420
3403
|
|
|
@@ -3447,21 +3430,18 @@ class svgMap {
|
|
|
3447
3430
|
const countryElement = e.target.closest('.svgMap-country');
|
|
3448
3431
|
if (!countryElement) return;
|
|
3449
3432
|
|
|
3450
|
-
const countryID = countryElement.
|
|
3451
|
-
const link = countryElement.
|
|
3452
|
-
const linkTarget = countryElement.
|
|
3433
|
+
const countryID = countryElement.dataset.id;
|
|
3434
|
+
const link = countryElement.dataset.link;
|
|
3435
|
+
const linkTarget = countryElement.dataset.linkTarget;
|
|
3453
3436
|
const hasCallback = typeof this.options.onCountryClick === 'function';
|
|
3454
3437
|
const hasLink = !!link;
|
|
3455
3438
|
const isTouch = e.pointerType === 'touch' || e.pointerType === 'pen';
|
|
3456
3439
|
|
|
3457
|
-
const isClickTooltipMouse =
|
|
3458
|
-
e.pointerType === 'mouse' &&
|
|
3459
|
-
this.options.showTooltips &&
|
|
3460
|
-
this.options.tooltipTrigger === 'click';
|
|
3440
|
+
const isClickTooltipMouse = e.pointerType === 'mouse' && isClickTooltip;
|
|
3461
3441
|
|
|
3462
3442
|
if (!hasLink && !hasCallback && !isClickTooltipMouse) return;
|
|
3463
3443
|
|
|
3464
|
-
if (isClickTooltipMouse
|
|
3444
|
+
if (isClickTooltipMouse) {
|
|
3465
3445
|
const willNavigate =
|
|
3466
3446
|
hasLink && countryElement.classList.contains('svgMap-active');
|
|
3467
3447
|
const shouldFireCallback = hasCallback && (!hasLink || willNavigate);
|
|
@@ -3477,12 +3457,10 @@ class svgMap {
|
|
|
3477
3457
|
if (linkTarget) window.open(link, linkTarget);
|
|
3478
3458
|
else window.location.href = link;
|
|
3479
3459
|
} else {
|
|
3480
|
-
|
|
3481
|
-
.querySelectorAll('.svgMap-country.svgMap-active')
|
|
3482
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3460
|
+
clearActive();
|
|
3483
3461
|
countryElement.parentNode.insertBefore(
|
|
3484
3462
|
countryElement,
|
|
3485
|
-
this.persistentTooltipGroup || null
|
|
3463
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3486
3464
|
);
|
|
3487
3465
|
countryElement.classList.add('svgMap-active');
|
|
3488
3466
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3493,12 +3471,10 @@ class svgMap {
|
|
|
3493
3471
|
|
|
3494
3472
|
if (callbackResultClick === false) return;
|
|
3495
3473
|
|
|
3496
|
-
|
|
3497
|
-
.querySelectorAll('.svgMap-country.svgMap-active')
|
|
3498
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3474
|
+
clearActive();
|
|
3499
3475
|
countryElement.parentNode.insertBefore(
|
|
3500
3476
|
countryElement,
|
|
3501
|
-
this.persistentTooltipGroup || null
|
|
3477
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3502
3478
|
);
|
|
3503
3479
|
countryElement.classList.add('svgMap-active');
|
|
3504
3480
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3548,15 +3524,9 @@ class svgMap {
|
|
|
3548
3524
|
});
|
|
3549
3525
|
|
|
3550
3526
|
this._clickTooltipOutsideHandler = function (ev) {
|
|
3551
|
-
if (
|
|
3552
|
-
if (
|
|
3553
|
-
!this.options.showTooltips ||
|
|
3554
|
-
this.options.tooltipTrigger !== 'click' ||
|
|
3555
|
-
!this.tooltip
|
|
3556
|
-
) {
|
|
3527
|
+
if (!this.tooltip || !this.tooltip.classList.contains('svgMap-active')) {
|
|
3557
3528
|
return;
|
|
3558
3529
|
}
|
|
3559
|
-
if (!this.tooltip.classList.contains('svgMap-active')) return;
|
|
3560
3530
|
var node = ev.target;
|
|
3561
3531
|
if (
|
|
3562
3532
|
node &&
|
|
@@ -3574,11 +3544,6 @@ class svgMap {
|
|
|
3574
3544
|
});
|
|
3575
3545
|
}
|
|
3576
3546
|
}.bind(this);
|
|
3577
|
-
document.addEventListener(
|
|
3578
|
-
'pointerdown',
|
|
3579
|
-
this._clickTooltipOutsideHandler,
|
|
3580
|
-
true
|
|
3581
|
-
);
|
|
3582
3547
|
|
|
3583
3548
|
// Expose instance
|
|
3584
3549
|
var me = this;
|
|
@@ -3661,7 +3626,7 @@ class svgMap {
|
|
|
3661
3626
|
|
|
3662
3627
|
countryElements.forEach(
|
|
3663
3628
|
function (countryElement) {
|
|
3664
|
-
var countryID = countryElement.
|
|
3629
|
+
var countryID = countryElement.dataset.id;
|
|
3665
3630
|
if (!this.shouldShowTooltipOnLoad(countryID)) {
|
|
3666
3631
|
return;
|
|
3667
3632
|
}
|
|
@@ -3697,6 +3662,157 @@ class svgMap {
|
|
|
3697
3662
|
);
|
|
3698
3663
|
}
|
|
3699
3664
|
|
|
3665
|
+
// Create static pins on the map
|
|
3666
|
+
|
|
3667
|
+
createStaticPins(countryElements) {
|
|
3668
|
+
if (this.pinGroup) {
|
|
3669
|
+
this.pinGroup.remove();
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
this.pinGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
3673
|
+
this.pinGroup.classList.add('svgMap-pin-group');
|
|
3674
|
+
this.mapImage.appendChild(this.pinGroup);
|
|
3675
|
+
|
|
3676
|
+
countryElements.forEach(
|
|
3677
|
+
function (countryElement) {
|
|
3678
|
+
var countryID = countryElement.getAttribute('data-id');
|
|
3679
|
+
if (!this.shouldShowPin(countryID)) {
|
|
3680
|
+
return;
|
|
3681
|
+
}
|
|
3682
|
+
|
|
3683
|
+
var countryValues = this.options.data.values[countryID];
|
|
3684
|
+
var cx, cy;
|
|
3685
|
+
|
|
3686
|
+
if (
|
|
3687
|
+
countryValues &&
|
|
3688
|
+
countryValues.pinX != null &&
|
|
3689
|
+
countryValues.pinY != null
|
|
3690
|
+
) {
|
|
3691
|
+
cx = countryValues.pinX;
|
|
3692
|
+
cy = countryValues.pinY;
|
|
3693
|
+
} else {
|
|
3694
|
+
// Split the path at absolute M commands and use the largest sub-path
|
|
3695
|
+
// to avoid overseas territories (islands, colonies) skewing the center.
|
|
3696
|
+
var d = countryElement.getAttribute('d');
|
|
3697
|
+
var subPaths = d.split(/(?=M)/).filter((s) => s.trim().length > 0);
|
|
3698
|
+
var largestBB = null;
|
|
3699
|
+
var largestArea = -1;
|
|
3700
|
+
|
|
3701
|
+
subPaths.forEach(
|
|
3702
|
+
function (subPath) {
|
|
3703
|
+
var tmp = document.createElementNS(
|
|
3704
|
+
'http://www.w3.org/2000/svg',
|
|
3705
|
+
'path'
|
|
3706
|
+
);
|
|
3707
|
+
tmp.setAttribute('d', subPath);
|
|
3708
|
+
this.mapImage.appendChild(tmp);
|
|
3709
|
+
var bb = tmp.getBBox();
|
|
3710
|
+
var area = bb.width * bb.height;
|
|
3711
|
+
if (area > largestArea) {
|
|
3712
|
+
largestArea = area;
|
|
3713
|
+
largestBB = bb;
|
|
3714
|
+
}
|
|
3715
|
+
this.mapImage.removeChild(tmp);
|
|
3716
|
+
}.bind(this)
|
|
3717
|
+
);
|
|
3718
|
+
|
|
3719
|
+
cx = largestBB.x + largestBB.width / 2;
|
|
3720
|
+
cy = largestBB.y + largestBB.height / 2;
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
var offsetX =
|
|
3724
|
+
countryValues && countryValues.pinOffsetX != null
|
|
3725
|
+
? countryValues.pinOffsetX
|
|
3726
|
+
: this.options.pinOffsetX;
|
|
3727
|
+
var offsetY =
|
|
3728
|
+
countryValues && countryValues.pinOffsetY != null
|
|
3729
|
+
? countryValues.pinOffsetY
|
|
3730
|
+
: this.options.pinOffsetY;
|
|
3731
|
+
cx += offsetX;
|
|
3732
|
+
cy += offsetY;
|
|
3733
|
+
|
|
3734
|
+
var color =
|
|
3735
|
+
(countryValues && countryValues.pinColor) || this.options.pinColor;
|
|
3736
|
+
var size =
|
|
3737
|
+
(countryValues && countryValues.pinSize) || this.options.pinSize;
|
|
3738
|
+
var strokeColor =
|
|
3739
|
+
(countryValues && countryValues.pinStrokeColor) ||
|
|
3740
|
+
this.options.pinStrokeColor;
|
|
3741
|
+
var strokeWidth =
|
|
3742
|
+
(countryValues && countryValues.pinStrokeWidth) ||
|
|
3743
|
+
this.options.pinStrokeWidth;
|
|
3744
|
+
|
|
3745
|
+
if (typeof this.options.onGetPin === 'function') {
|
|
3746
|
+
var custom = this.options.onGetPin(countryID, countryValues);
|
|
3747
|
+
if (custom) {
|
|
3748
|
+
custom.setAttribute(
|
|
3749
|
+
'transform',
|
|
3750
|
+
'translate(' + cx + ',' + cy + ')'
|
|
3751
|
+
);
|
|
3752
|
+
this.pinGroup.appendChild(custom);
|
|
3753
|
+
return;
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
|
|
3757
|
+
var pinImage =
|
|
3758
|
+
(countryValues && countryValues.pinImage) || this.options.pinImage;
|
|
3759
|
+
|
|
3760
|
+
if (pinImage) {
|
|
3761
|
+
var pinW =
|
|
3762
|
+
(countryValues && countryValues.pinImageWidth) ||
|
|
3763
|
+
this.options.pinImageWidth;
|
|
3764
|
+
var pinH =
|
|
3765
|
+
(countryValues && countryValues.pinImageHeight) ||
|
|
3766
|
+
this.options.pinImageHeight;
|
|
3767
|
+
var img = document.createElementNS(
|
|
3768
|
+
'http://www.w3.org/2000/svg',
|
|
3769
|
+
'image'
|
|
3770
|
+
);
|
|
3771
|
+
img.setAttribute('href', pinImage);
|
|
3772
|
+
img.setAttribute('x', cx - pinW / 2);
|
|
3773
|
+
img.setAttribute('y', cy - pinH / 2);
|
|
3774
|
+
img.setAttribute('width', pinW);
|
|
3775
|
+
img.setAttribute('height', pinH);
|
|
3776
|
+
img.setAttribute('data-id', countryID);
|
|
3777
|
+
img.classList.add('svgMap-pin');
|
|
3778
|
+
this.pinGroup.appendChild(img);
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
|
|
3782
|
+
var circle = document.createElementNS(
|
|
3783
|
+
'http://www.w3.org/2000/svg',
|
|
3784
|
+
'circle'
|
|
3785
|
+
);
|
|
3786
|
+
circle.setAttribute('cx', cx);
|
|
3787
|
+
circle.setAttribute('cy', cy);
|
|
3788
|
+
circle.setAttribute('r', size);
|
|
3789
|
+
circle.setAttribute('fill', color);
|
|
3790
|
+
if (strokeWidth > 0) {
|
|
3791
|
+
circle.setAttribute('stroke', strokeColor);
|
|
3792
|
+
circle.setAttribute('stroke-width', strokeWidth);
|
|
3793
|
+
circle.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
3794
|
+
}
|
|
3795
|
+
circle.setAttribute('data-id', countryID);
|
|
3796
|
+
circle.classList.add('svgMap-pin');
|
|
3797
|
+
this.pinGroup.appendChild(circle);
|
|
3798
|
+
}.bind(this)
|
|
3799
|
+
);
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3802
|
+
// Check if a static pin should be shown for a country
|
|
3803
|
+
|
|
3804
|
+
shouldShowPin(countryID) {
|
|
3805
|
+
var pins = this.options.staticPins;
|
|
3806
|
+
var countryValues = this.options.data.values[countryID];
|
|
3807
|
+
if (Array.isArray(pins)) {
|
|
3808
|
+
return pins.indexOf(countryID) !== -1;
|
|
3809
|
+
}
|
|
3810
|
+
if (typeof pins === 'function') {
|
|
3811
|
+
return pins(countryID, countryValues);
|
|
3812
|
+
}
|
|
3813
|
+
return false;
|
|
3814
|
+
}
|
|
3815
|
+
|
|
3700
3816
|
// Check if a persistent tooltip should be shown on load
|
|
3701
3817
|
|
|
3702
3818
|
shouldShowTooltipOnLoad(countryID) {
|
|
@@ -4706,6 +4822,23 @@ class svgMap {
|
|
|
4706
4822
|
return;
|
|
4707
4823
|
}
|
|
4708
4824
|
this.tooltip.classList.add('svgMap-active');
|
|
4825
|
+
|
|
4826
|
+
if (
|
|
4827
|
+
this.options.showTooltips &&
|
|
4828
|
+
this.options.tooltipTrigger === 'click' &&
|
|
4829
|
+
e.pointerType === 'mouse'
|
|
4830
|
+
) {
|
|
4831
|
+
// don't register event listener in the same frame
|
|
4832
|
+
// to prevent it from being triggered immediately
|
|
4833
|
+
requestAnimationFrame(() => {
|
|
4834
|
+
document.addEventListener(
|
|
4835
|
+
'pointerdown',
|
|
4836
|
+
this._clickTooltipOutsideHandler,
|
|
4837
|
+
{ once: true, passive: true }
|
|
4838
|
+
);
|
|
4839
|
+
});
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4709
4842
|
this.moveTooltip(e);
|
|
4710
4843
|
}
|
|
4711
4844
|
|
|
@@ -4715,7 +4848,12 @@ class svgMap {
|
|
|
4715
4848
|
if (!this.tooltip) {
|
|
4716
4849
|
return;
|
|
4717
4850
|
}
|
|
4851
|
+
|
|
4718
4852
|
this.tooltip.classList.remove('svgMap-active');
|
|
4853
|
+
document.removeEventListener(
|
|
4854
|
+
'pointerdown',
|
|
4855
|
+
this._clickTooltipOutsideHandler
|
|
4856
|
+
);
|
|
4719
4857
|
}
|
|
4720
4858
|
|
|
4721
4859
|
// Move the tooltip
|