svgmap 2.19.3 → 2.20.1
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 +4 -0
- package/dist/index.cjs +340 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +340 -143
- package/dist/index.js.map +1 -1
- package/dist/svg-map.css +61 -21
- package/dist/svg-map.min.css +1 -1
- package/dist/svg-map.umd.js +340 -143
- package/dist/svg-map.umd.js.map +1 -1
- package/dist/svg-map.umd.min.js +1 -1
- package/dist/svgMap.css +61 -21
- package/dist/svgMap.js +340 -143
- 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 +340 -143
- package/src/scss/map.scss +4 -0
- package/src/scss/tooltip.scss +26 -6
package/dist/index.js
CHANGED
|
@@ -2342,6 +2342,15 @@ class svgMap {
|
|
|
2342
2342
|
// Set to true to open the link on mobile devices, set to false (default) to show the tooltip
|
|
2343
2343
|
touchLink: false,
|
|
2344
2344
|
|
|
2345
|
+
// When false, disables hover/touch-following tooltips (not the on-map persistent labels; see persistentTooltips)
|
|
2346
|
+
showTooltips: true,
|
|
2347
|
+
|
|
2348
|
+
// 'hover' (default): mouse shows tooltip on enter. 'click': mouse opens tooltip on click; touch/pen unchanged.
|
|
2349
|
+
tooltipTrigger: 'hover',
|
|
2350
|
+
|
|
2351
|
+
// Persistent on-map tooltips: an array of country IDs, or a function (countryID, countryValues) => boolean
|
|
2352
|
+
persistentTooltips: false,
|
|
2353
|
+
|
|
2345
2354
|
// Set to true to show the to show a zoom reset button
|
|
2346
2355
|
showZoomReset: false,
|
|
2347
2356
|
|
|
@@ -2350,6 +2359,10 @@ class svgMap {
|
|
|
2350
2359
|
return null;
|
|
2351
2360
|
},
|
|
2352
2361
|
|
|
2362
|
+
// Called on country click (pointer released without dragging). Receives
|
|
2363
|
+
// (countryID, event). Return false to skip opening data.values[*].link.
|
|
2364
|
+
onCountryClick: null,
|
|
2365
|
+
|
|
2353
2366
|
// Country specific options
|
|
2354
2367
|
countries: {
|
|
2355
2368
|
// Western Sahara: Set to false to combine Morocco (MA) and Western Sahara (EH)
|
|
@@ -2389,6 +2402,9 @@ class svgMap {
|
|
|
2389
2402
|
// Wrapper element
|
|
2390
2403
|
this.wrapper = document.getElementById(this.options.targetElementID);
|
|
2391
2404
|
this.wrapper.classList.add('svgMap-wrapper');
|
|
2405
|
+
if (typeof this.options.onCountryClick === 'function') {
|
|
2406
|
+
this.wrapper.classList.add('svgMap-country-click-callback');
|
|
2407
|
+
}
|
|
2392
2408
|
|
|
2393
2409
|
// Container element
|
|
2394
2410
|
this.container = document.createElement('div');
|
|
@@ -3080,7 +3096,9 @@ class svgMap {
|
|
|
3080
3096
|
|
|
3081
3097
|
createMap() {
|
|
3082
3098
|
// Create the tooltip
|
|
3083
|
-
this.
|
|
3099
|
+
if (this.options.showTooltips) {
|
|
3100
|
+
this.createTooltip();
|
|
3101
|
+
}
|
|
3084
3102
|
|
|
3085
3103
|
// Create map wrappers
|
|
3086
3104
|
this.mapWrapper = this.createElement(
|
|
@@ -3206,6 +3224,103 @@ class svgMap {
|
|
|
3206
3224
|
}.bind(this);
|
|
3207
3225
|
|
|
3208
3226
|
// Add map elements
|
|
3227
|
+
var countryElements = [];
|
|
3228
|
+
|
|
3229
|
+
const clearActive = function clearActive() {
|
|
3230
|
+
this.mapImage
|
|
3231
|
+
.querySelectorAll('.svgMap-active')
|
|
3232
|
+
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3233
|
+
}.bind(this);
|
|
3234
|
+
|
|
3235
|
+
const isClickTooltip =
|
|
3236
|
+
this.options.showTooltips && this.options.tooltipTrigger === 'click';
|
|
3237
|
+
|
|
3238
|
+
const getCountryFromEvent = function (e) {
|
|
3239
|
+
return e.target && e.target.closest
|
|
3240
|
+
? e.target.closest('.svgMap-country')
|
|
3241
|
+
: null;
|
|
3242
|
+
};
|
|
3243
|
+
|
|
3244
|
+
const raiseCountry = function (countryElement, setActive) {
|
|
3245
|
+
if (setActive) {
|
|
3246
|
+
clearActive();
|
|
3247
|
+
}
|
|
3248
|
+
countryElement.parentNode.insertBefore(
|
|
3249
|
+
countryElement,
|
|
3250
|
+
this.persistentTooltipGroup || null
|
|
3251
|
+
);
|
|
3252
|
+
if (setActive) {
|
|
3253
|
+
countryElement.classList.add('svgMap-active');
|
|
3254
|
+
}
|
|
3255
|
+
}.bind(this);
|
|
3256
|
+
|
|
3257
|
+
const showCountryTooltip = function (countryElement, e, setActive) {
|
|
3258
|
+
raiseCountry(countryElement, setActive);
|
|
3259
|
+
this.setTooltipContent(this.getTooltipContent(countryElement.dataset.id));
|
|
3260
|
+
this.showTooltip(e);
|
|
3261
|
+
}.bind(this);
|
|
3262
|
+
|
|
3263
|
+
// Touch only: preview tooltip on finger down without marking country active
|
|
3264
|
+
// (active is set on pointerup so link countries keep two-tap navigation)
|
|
3265
|
+
this.mapImage.addEventListener(
|
|
3266
|
+
'pointerdown',
|
|
3267
|
+
(e) => {
|
|
3268
|
+
if (!this.options.showTooltips || e.pointerType !== 'touch') {
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
const countryElement = getCountryFromEvent(e);
|
|
3273
|
+
if (!countryElement) {
|
|
3274
|
+
this.hideTooltip();
|
|
3275
|
+
return;
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
showCountryTooltip(countryElement, e, false);
|
|
3279
|
+
this.moveTooltip(e);
|
|
3280
|
+
},
|
|
3281
|
+
{ passive: true }
|
|
3282
|
+
);
|
|
3283
|
+
|
|
3284
|
+
this.mapImage.addEventListener(
|
|
3285
|
+
'pointercancel',
|
|
3286
|
+
(e) => {
|
|
3287
|
+
if (e.pointerType === 'touch') {
|
|
3288
|
+
this.hideTooltip();
|
|
3289
|
+
}
|
|
3290
|
+
},
|
|
3291
|
+
{ passive: true }
|
|
3292
|
+
);
|
|
3293
|
+
|
|
3294
|
+
// Hover (mouse/pen) and touch drag: raise country + optional floating tooltip
|
|
3295
|
+
this.mapImage.addEventListener(
|
|
3296
|
+
'pointermove',
|
|
3297
|
+
(e) => {
|
|
3298
|
+
const countryElement = getCountryFromEvent(e);
|
|
3299
|
+
if (!countryElement) {
|
|
3300
|
+
clearActive();
|
|
3301
|
+
if (this.options.showTooltips) {
|
|
3302
|
+
this.hideTooltip();
|
|
3303
|
+
}
|
|
3304
|
+
return;
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
const mouseClickMode = e.pointerType === 'mouse' && isClickTooltip;
|
|
3308
|
+
|
|
3309
|
+
// Always raise hovered country (SVG paint order + .svgMap-active stroke)
|
|
3310
|
+
if (!this.options.showTooltips || mouseClickMode) {
|
|
3311
|
+
raiseCountry(countryElement, true);
|
|
3312
|
+
return;
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
showCountryTooltip(countryElement, e, true);
|
|
3316
|
+
|
|
3317
|
+
if (e.pointerType === 'touch') {
|
|
3318
|
+
this.moveTooltip(e);
|
|
3319
|
+
}
|
|
3320
|
+
},
|
|
3321
|
+
{ passive: true }
|
|
3322
|
+
);
|
|
3323
|
+
|
|
3209
3324
|
Object.keys(mapPaths).forEach(
|
|
3210
3325
|
function (countryID) {
|
|
3211
3326
|
var countryData = this.mapPaths[countryID];
|
|
@@ -3223,156 +3338,50 @@ class svgMap {
|
|
|
3223
3338
|
'id',
|
|
3224
3339
|
this.id + '-map-country-' + countryID
|
|
3225
3340
|
);
|
|
3226
|
-
countryElement.
|
|
3341
|
+
countryElement.dataset.id = countryID;
|
|
3227
3342
|
countryElement.classList.add('svgMap-country');
|
|
3228
3343
|
|
|
3229
3344
|
this.mapImage.appendChild(countryElement);
|
|
3230
|
-
|
|
3231
|
-
// Add tooltip when touch is used
|
|
3232
|
-
function handlePointerMove(e) {
|
|
3233
|
-
if (e.pointerType === 'touch') return;
|
|
3234
|
-
|
|
3235
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
3236
|
-
|
|
3237
|
-
if (
|
|
3238
|
-
!target ||
|
|
3239
|
-
(!target.closest('.svgMap-country') &&
|
|
3240
|
-
!target.closest('.svgMap-tooltip'))
|
|
3241
|
-
) {
|
|
3242
|
-
this.hideTooltip();
|
|
3243
|
-
document
|
|
3244
|
-
.querySelectorAll('.svgMap-active')
|
|
3245
|
-
.forEach(el => el.classList.remove('svgMap-active'));
|
|
3246
|
-
}
|
|
3247
|
-
}
|
|
3248
|
-
|
|
3249
|
-
const handlePointerMoveBound = handlePointerMove.bind(this);
|
|
3250
|
-
|
|
3251
|
-
countryElement.addEventListener(
|
|
3252
|
-
'pointerenter',
|
|
3253
|
-
function (e) {
|
|
3254
|
-
// Only add pointermove listener for non-touch pointers
|
|
3255
|
-
if (e.pointerType !== 'touch') {
|
|
3256
|
-
document.addEventListener(
|
|
3257
|
-
'pointermove',
|
|
3258
|
-
handlePointerMoveBound,
|
|
3259
|
-
{ passive: true }
|
|
3260
|
-
);
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
|
-
document
|
|
3264
|
-
.querySelectorAll('.svgMap-active')
|
|
3265
|
-
.forEach(el => el.classList.remove('svgMap-active'));
|
|
3266
|
-
|
|
3267
|
-
countryElement.parentNode.appendChild(countryElement);
|
|
3268
|
-
countryElement.classList.add('svgMap-active');
|
|
3269
|
-
|
|
3270
|
-
const countryID = countryElement.getAttribute('data-id');
|
|
3271
|
-
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3272
|
-
this.showTooltip(e);
|
|
3273
|
-
|
|
3274
|
-
// For touch, move tooltip to the touch position and keep it there
|
|
3275
|
-
if (e.pointerType === 'touch') {
|
|
3276
|
-
this.moveTooltip(e);
|
|
3277
|
-
}
|
|
3278
|
-
}.bind(this)
|
|
3279
|
-
);
|
|
3280
|
-
|
|
3281
|
-
// Handle touch move - update tooltip position while panning
|
|
3282
|
-
countryElement.addEventListener(
|
|
3283
|
-
'touchmove',
|
|
3284
|
-
function (e) {
|
|
3285
|
-
this.moveTooltip(e);
|
|
3286
|
-
}.bind(this),
|
|
3287
|
-
{ passive: true }
|
|
3288
|
-
);
|
|
3289
|
-
|
|
3290
|
-
// Handle touch end - remove active state and hide tooltip
|
|
3291
|
-
countryElement.addEventListener(
|
|
3292
|
-
'touchend',
|
|
3293
|
-
function (e) {
|
|
3294
|
-
const touch = e.changedTouches[0];
|
|
3295
|
-
const elementAtEnd = document.elementFromPoint(touch.clientX, touch.clientY);
|
|
3296
|
-
|
|
3297
|
-
// Only hide if touch ended outside the country or tooltip
|
|
3298
|
-
if (
|
|
3299
|
-
!elementAtEnd ||
|
|
3300
|
-
(!elementAtEnd.closest('.svgMap-country') &&
|
|
3301
|
-
!elementAtEnd.closest('.svgMap-tooltip'))
|
|
3302
|
-
) {
|
|
3303
|
-
this.hideTooltip();
|
|
3304
|
-
document
|
|
3305
|
-
.querySelectorAll('.svgMap-active')
|
|
3306
|
-
.forEach(el => el.classList.remove('svgMap-active'));
|
|
3307
|
-
}
|
|
3308
|
-
}.bind(this),
|
|
3309
|
-
{ passive: true }
|
|
3310
|
-
);
|
|
3311
|
-
|
|
3312
|
-
// Remove pointermove listener when leaving non-touch pointer
|
|
3313
|
-
countryElement.addEventListener(
|
|
3314
|
-
'pointerleave',
|
|
3315
|
-
function (e) {
|
|
3316
|
-
if (e.pointerType !== 'touch') {
|
|
3317
|
-
document.removeEventListener('pointermove', handlePointerMoveBound);
|
|
3318
|
-
this.hideTooltip();
|
|
3319
|
-
document
|
|
3320
|
-
.querySelectorAll('.svgMap-active')
|
|
3321
|
-
.forEach(el => el.classList.remove('svgMap-active'));
|
|
3322
|
-
}
|
|
3323
|
-
}.bind(this)
|
|
3324
|
-
);
|
|
3325
|
-
|
|
3326
|
-
document.addEventListener(
|
|
3327
|
-
'pointerover',
|
|
3328
|
-
function (e) {
|
|
3329
|
-
if (e.pointerType !== 'touch') return;
|
|
3330
|
-
|
|
3331
|
-
if (
|
|
3332
|
-
e.target.closest('.svgMap-country') ||
|
|
3333
|
-
e.target.closest('.svgMap-tooltip')
|
|
3334
|
-
) {
|
|
3335
|
-
return;
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
this.hideTooltip();
|
|
3339
|
-
document
|
|
3340
|
-
.querySelectorAll('.svgMap-active')
|
|
3341
|
-
.forEach(el => el.classList.remove('svgMap-active'));
|
|
3342
|
-
}.bind(this),
|
|
3343
|
-
{ passive: true }
|
|
3344
|
-
);
|
|
3345
|
+
countryElements.push(countryElement);
|
|
3345
3346
|
|
|
3346
3347
|
if (
|
|
3347
3348
|
this.options.data.values &&
|
|
3348
3349
|
this.options.data.values[countryID] &&
|
|
3349
3350
|
this.options.data.values[countryID]['link']
|
|
3350
3351
|
) {
|
|
3351
|
-
countryElement.
|
|
3352
|
-
'
|
|
3353
|
-
this.options.data.values[countryID]['link']
|
|
3354
|
-
);
|
|
3352
|
+
countryElement.dataset.link =
|
|
3353
|
+
this.options.data.values[countryID]['link'];
|
|
3355
3354
|
if (this.options.data.values[countryID]['linkTarget']) {
|
|
3356
|
-
countryElement.
|
|
3357
|
-
|
|
3358
|
-
this.options.data.values[countryID]['linkTarget']
|
|
3359
|
-
);
|
|
3355
|
+
countryElement.dataset.linkTarget =
|
|
3356
|
+
this.options.data.values[countryID]['linkTarget'];
|
|
3360
3357
|
}
|
|
3361
3358
|
}
|
|
3362
3359
|
}.bind(this)
|
|
3363
3360
|
);
|
|
3364
3361
|
|
|
3362
|
+
var persistent = this.options.persistentTooltips;
|
|
3363
|
+
if (
|
|
3364
|
+
persistent &&
|
|
3365
|
+
(Array.isArray(persistent) || typeof persistent === 'function')
|
|
3366
|
+
) {
|
|
3367
|
+
this.createPersistentTooltips(countryElements);
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3365
3370
|
let pointerStart = null;
|
|
3366
3371
|
let activeCountry = null;
|
|
3367
3372
|
|
|
3368
|
-
this.mapImage.addEventListener(
|
|
3369
|
-
|
|
3370
|
-
|
|
3373
|
+
this.mapImage.addEventListener(
|
|
3374
|
+
'pointerdown',
|
|
3375
|
+
(e) => {
|
|
3376
|
+
// Ignore right click (on desktop it allows inspecting the chart elements without opening the URL)
|
|
3377
|
+
if (e.button !== 0) return;
|
|
3371
3378
|
|
|
3372
|
-
|
|
3373
|
-
|
|
3379
|
+
pointerStart = { x: e.clientX, y: e.clientY };
|
|
3380
|
+
},
|
|
3381
|
+
{ passive: true }
|
|
3382
|
+
);
|
|
3374
3383
|
|
|
3375
|
-
this.mapImage.addEventListener('pointerup', e => {
|
|
3384
|
+
this.mapImage.addEventListener('pointerup', (e) => {
|
|
3376
3385
|
// Ignore right click (on desktop it allows inspecting the chart elements without opening the URL)
|
|
3377
3386
|
if (e.button !== 0) return;
|
|
3378
3387
|
|
|
@@ -3390,33 +3399,121 @@ class svgMap {
|
|
|
3390
3399
|
const countryElement = e.target.closest('.svgMap-country');
|
|
3391
3400
|
if (!countryElement) return;
|
|
3392
3401
|
|
|
3393
|
-
const countryID = countryElement.
|
|
3394
|
-
const link = countryElement.
|
|
3395
|
-
const
|
|
3396
|
-
|
|
3397
|
-
|
|
3402
|
+
const countryID = countryElement.dataset.id;
|
|
3403
|
+
const link = countryElement.dataset.link;
|
|
3404
|
+
const linkTarget = countryElement.dataset.linkTarget;
|
|
3405
|
+
const hasCallback = typeof this.options.onCountryClick === 'function';
|
|
3406
|
+
const hasLink = !!link;
|
|
3398
3407
|
const isTouch = e.pointerType === 'touch' || e.pointerType === 'pen';
|
|
3399
3408
|
|
|
3409
|
+
const isClickTooltipMouse = e.pointerType === 'mouse' && isClickTooltip;
|
|
3410
|
+
|
|
3411
|
+
if (!hasLink && !hasCallback && !isClickTooltipMouse) return;
|
|
3412
|
+
|
|
3413
|
+
if (isClickTooltipMouse) {
|
|
3414
|
+
const willNavigate =
|
|
3415
|
+
hasLink && countryElement.classList.contains('svgMap-active');
|
|
3416
|
+
const shouldFireCallback = hasCallback && (!hasLink || willNavigate);
|
|
3417
|
+
|
|
3418
|
+
var callbackResultClick;
|
|
3419
|
+
if (shouldFireCallback) {
|
|
3420
|
+
callbackResultClick = this.options.onCountryClick(countryID, e);
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
if (hasLink) {
|
|
3424
|
+
if (callbackResultClick === false) return;
|
|
3425
|
+
if (countryElement.classList.contains('svgMap-active')) {
|
|
3426
|
+
if (linkTarget) window.open(link, linkTarget);
|
|
3427
|
+
else window.location.href = link;
|
|
3428
|
+
} else {
|
|
3429
|
+
clearActive();
|
|
3430
|
+
countryElement.parentNode.insertBefore(
|
|
3431
|
+
countryElement,
|
|
3432
|
+
this.persistentTooltipGroup || null
|
|
3433
|
+
);
|
|
3434
|
+
countryElement.classList.add('svgMap-active');
|
|
3435
|
+
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3436
|
+
this.showTooltip(e);
|
|
3437
|
+
}
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
if (callbackResultClick === false) return;
|
|
3442
|
+
|
|
3443
|
+
clearActive();
|
|
3444
|
+
countryElement.parentNode.insertBefore(
|
|
3445
|
+
countryElement,
|
|
3446
|
+
this.persistentTooltipGroup || null
|
|
3447
|
+
);
|
|
3448
|
+
countryElement.classList.add('svgMap-active');
|
|
3449
|
+
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3450
|
+
this.showTooltip(e);
|
|
3451
|
+
return;
|
|
3452
|
+
}
|
|
3453
|
+
|
|
3454
|
+
const willNavigate =
|
|
3455
|
+
hasLink &&
|
|
3456
|
+
(!isTouch || countryElement.classList.contains('svgMap-active'));
|
|
3457
|
+
|
|
3458
|
+
const shouldFireCallback =
|
|
3459
|
+
hasCallback && (!hasLink || !isTouch || willNavigate);
|
|
3460
|
+
|
|
3461
|
+
var callbackResult;
|
|
3462
|
+
if (shouldFireCallback) {
|
|
3463
|
+
callbackResult = this.options.onCountryClick(countryID, e);
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
if (!hasLink) return;
|
|
3467
|
+
|
|
3468
|
+
if (callbackResult === false) return;
|
|
3469
|
+
|
|
3400
3470
|
if (isTouch) {
|
|
3401
3471
|
// Touch: only open if already active
|
|
3402
3472
|
if (countryElement.classList.contains('svgMap-active')) {
|
|
3403
|
-
if (
|
|
3473
|
+
if (linkTarget) window.open(link, linkTarget);
|
|
3404
3474
|
else window.location.href = link;
|
|
3405
3475
|
} else {
|
|
3406
|
-
// first tap shows tooltip
|
|
3476
|
+
// first tap shows tooltip (or opens link immediately if tooltips are off)
|
|
3407
3477
|
if (activeCountry) activeCountry.classList.remove('svgMap-active');
|
|
3408
3478
|
activeCountry = countryElement;
|
|
3409
3479
|
countryElement.classList.add('svgMap-active');
|
|
3410
|
-
|
|
3411
|
-
|
|
3480
|
+
if (this.options.showTooltips) {
|
|
3481
|
+
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3482
|
+
this.showTooltip(e);
|
|
3483
|
+
} else {
|
|
3484
|
+
if (linkTarget) window.open(link, linkTarget);
|
|
3485
|
+
else window.location.href = link;
|
|
3486
|
+
}
|
|
3412
3487
|
}
|
|
3413
3488
|
} else {
|
|
3414
3489
|
// Desktop: open immediately
|
|
3415
|
-
if (
|
|
3490
|
+
if (linkTarget) window.open(link, linkTarget);
|
|
3416
3491
|
else window.location.href = link;
|
|
3417
3492
|
}
|
|
3418
3493
|
});
|
|
3419
3494
|
|
|
3495
|
+
this._clickTooltipOutsideHandler = function (ev) {
|
|
3496
|
+
if (!this.tooltip || !this.tooltip.classList.contains('svgMap-active')) {
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
var node = ev.target;
|
|
3500
|
+
if (
|
|
3501
|
+
node &&
|
|
3502
|
+
node.closest &&
|
|
3503
|
+
(node.closest('.svgMap-country') || node.closest('.svgMap-tooltip'))
|
|
3504
|
+
) {
|
|
3505
|
+
return;
|
|
3506
|
+
}
|
|
3507
|
+
this.hideTooltip();
|
|
3508
|
+
if (this.mapImage) {
|
|
3509
|
+
this.mapImage
|
|
3510
|
+
.querySelectorAll('.svgMap-country.svgMap-active')
|
|
3511
|
+
.forEach(function (el) {
|
|
3512
|
+
el.classList.remove('svgMap-active');
|
|
3513
|
+
});
|
|
3514
|
+
}
|
|
3515
|
+
}.bind(this);
|
|
3516
|
+
|
|
3420
3517
|
// Expose instance
|
|
3421
3518
|
var me = this;
|
|
3422
3519
|
|
|
@@ -3482,13 +3579,82 @@ class svgMap {
|
|
|
3482
3579
|
}
|
|
3483
3580
|
}
|
|
3484
3581
|
|
|
3582
|
+
// Create the persistent tooltips
|
|
3583
|
+
|
|
3584
|
+
createPersistentTooltips(countryElements) {
|
|
3585
|
+
if (this.persistentTooltipGroup) {
|
|
3586
|
+
this.persistentTooltipGroup.remove();
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
this.persistentTooltipGroup = document.createElementNS(
|
|
3590
|
+
'http://www.w3.org/2000/svg',
|
|
3591
|
+
'g'
|
|
3592
|
+
);
|
|
3593
|
+
this.persistentTooltipGroup.classList.add('svgMap-persistent-tooltips');
|
|
3594
|
+
this.mapImage.appendChild(this.persistentTooltipGroup);
|
|
3595
|
+
|
|
3596
|
+
countryElements.forEach(
|
|
3597
|
+
function (countryElement) {
|
|
3598
|
+
var countryID = countryElement.dataset.id;
|
|
3599
|
+
if (!this.shouldShowTooltipOnLoad(countryID)) {
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
var boundingBox = countryElement.getBBox();
|
|
3604
|
+
var tooltipPosition = {
|
|
3605
|
+
x: boundingBox.x + boundingBox.width / 2,
|
|
3606
|
+
y: boundingBox.y + boundingBox.height / 2
|
|
3607
|
+
};
|
|
3608
|
+
|
|
3609
|
+
var tooltipObject = document.createElementNS(
|
|
3610
|
+
'http://www.w3.org/2000/svg',
|
|
3611
|
+
'foreignObject'
|
|
3612
|
+
);
|
|
3613
|
+
tooltipObject.setAttribute('x', tooltipPosition.x);
|
|
3614
|
+
tooltipObject.setAttribute('y', tooltipPosition.y);
|
|
3615
|
+
tooltipObject.setAttribute('width', 1);
|
|
3616
|
+
tooltipObject.setAttribute('height', 1);
|
|
3617
|
+
tooltipObject.classList.add('svgMap-persistent-tooltip-wrapper');
|
|
3618
|
+
|
|
3619
|
+
var tooltipElement = this.createElement(
|
|
3620
|
+
'div',
|
|
3621
|
+
'svgMap-persistent-tooltip',
|
|
3622
|
+
tooltipObject
|
|
3623
|
+
);
|
|
3624
|
+
tooltipElement.append(
|
|
3625
|
+
this.getTooltipContent(countryID, tooltipElement)
|
|
3626
|
+
);
|
|
3627
|
+
this.createElement('div', 'svgMap-tooltip-pointer', tooltipElement);
|
|
3628
|
+
|
|
3629
|
+
this.persistentTooltipGroup.appendChild(tooltipObject);
|
|
3630
|
+
}.bind(this)
|
|
3631
|
+
);
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
// Check if a persistent tooltip should be shown on load
|
|
3635
|
+
|
|
3636
|
+
shouldShowTooltipOnLoad(countryID) {
|
|
3637
|
+
var persistent = this.options.persistentTooltips;
|
|
3638
|
+
var countryValues = this.options.data.values[countryID];
|
|
3639
|
+
|
|
3640
|
+
if (Array.isArray(persistent)) {
|
|
3641
|
+
return persistent.indexOf(countryID) !== -1;
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
if (typeof persistent === 'function') {
|
|
3645
|
+
return persistent(countryID, countryValues);
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
return false;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3485
3651
|
// Create the tooltip content
|
|
3486
3652
|
|
|
3487
|
-
getTooltipContent(countryID) {
|
|
3653
|
+
getTooltipContent(countryID, tooltipDiv = this.tooltip) {
|
|
3488
3654
|
// Custom tooltip
|
|
3489
3655
|
if (this.options.onGetTooltip) {
|
|
3490
3656
|
var customDiv = this.options.onGetTooltip(
|
|
3491
|
-
|
|
3657
|
+
tooltipDiv,
|
|
3492
3658
|
countryID,
|
|
3493
3659
|
this.options.data.values[countryID]
|
|
3494
3660
|
);
|
|
@@ -4470,19 +4636,50 @@ class svgMap {
|
|
|
4470
4636
|
// Show the tooltip
|
|
4471
4637
|
|
|
4472
4638
|
showTooltip(e) {
|
|
4639
|
+
if (!this.tooltip) {
|
|
4640
|
+
return;
|
|
4641
|
+
}
|
|
4473
4642
|
this.tooltip.classList.add('svgMap-active');
|
|
4643
|
+
|
|
4644
|
+
if (
|
|
4645
|
+
this.options.showTooltips &&
|
|
4646
|
+
this.options.tooltipTrigger === 'click' &&
|
|
4647
|
+
e.pointerType === 'mouse'
|
|
4648
|
+
) {
|
|
4649
|
+
// don't register event listener in the same frame
|
|
4650
|
+
// to prevent it from being triggered immediately
|
|
4651
|
+
requestAnimationFrame(() => {
|
|
4652
|
+
document.addEventListener(
|
|
4653
|
+
'pointerdown',
|
|
4654
|
+
this._clickTooltipOutsideHandler,
|
|
4655
|
+
{ once: true, passive: true }
|
|
4656
|
+
);
|
|
4657
|
+
});
|
|
4658
|
+
}
|
|
4659
|
+
|
|
4474
4660
|
this.moveTooltip(e);
|
|
4475
4661
|
}
|
|
4476
4662
|
|
|
4477
4663
|
// Hide the tooltip
|
|
4478
4664
|
|
|
4479
4665
|
hideTooltip() {
|
|
4666
|
+
if (!this.tooltip) {
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4480
4670
|
this.tooltip.classList.remove('svgMap-active');
|
|
4671
|
+
document.removeEventListener(
|
|
4672
|
+
'pointerdown',
|
|
4673
|
+
this._clickTooltipOutsideHandler
|
|
4674
|
+
);
|
|
4481
4675
|
}
|
|
4482
4676
|
|
|
4483
4677
|
// Move the tooltip
|
|
4484
4678
|
|
|
4485
4679
|
moveTooltip(e) {
|
|
4680
|
+
if (!this.tooltip) {
|
|
4681
|
+
return;
|
|
4682
|
+
}
|
|
4486
4683
|
var x = e.pageX || (e.touches && e.touches[0] ? e.touches[0].pageX : null);
|
|
4487
4684
|
var y = e.pageY || (e.touches && e.touches[0] ? e.touches[0].pageY : null);
|
|
4488
4685
|
|