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/svgMap.css
CHANGED
|
@@ -204,6 +204,15 @@
|
|
|
204
204
|
cursor: pointer;
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
.svgMap-pin-group {
|
|
208
|
+
pointer-events: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.svgMap-pin {
|
|
212
|
+
vector-effect: non-scaling-stroke;
|
|
213
|
+
transition: r 250ms;
|
|
214
|
+
}
|
|
215
|
+
|
|
207
216
|
.svgMap-tooltip,
|
|
208
217
|
.svgMap-persistent-tooltip {
|
|
209
218
|
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
package/dist/svgMap.js
CHANGED
|
@@ -2379,7 +2379,34 @@
|
|
|
2379
2379
|
showContinentSelector: false,
|
|
2380
2380
|
|
|
2381
2381
|
// Reset zoom on resize
|
|
2382
|
-
resetZoomOnResize: false
|
|
2382
|
+
resetZoomOnResize: false,
|
|
2383
|
+
|
|
2384
|
+
// Static pins: false | string[] | function(countryID, countryValues) => boolean
|
|
2385
|
+
staticPins: false,
|
|
2386
|
+
|
|
2387
|
+
// Default pin fill color
|
|
2388
|
+
pinColor: '#000000',
|
|
2389
|
+
|
|
2390
|
+
// Default pin stroke color and width (circle pins; width is in screen pixels with non-scaling stroke)
|
|
2391
|
+
pinStrokeColor: '#ffffff',
|
|
2392
|
+
pinStrokeWidth: 1.5,
|
|
2393
|
+
|
|
2394
|
+
// Default pin radius in SVG units (viewBox is 2000 × 1001)
|
|
2395
|
+
pinSize: 8,
|
|
2396
|
+
|
|
2397
|
+
// Custom pin element: function(countryID, countryValues) => SVGElement | null
|
|
2398
|
+
onGetPin: null,
|
|
2399
|
+
|
|
2400
|
+
// Image URL to use as a pin instead of the default circle (can also be set per-country via values[id].pinImage)
|
|
2401
|
+
pinImage: null,
|
|
2402
|
+
|
|
2403
|
+
// Width and height of the pin image in SVG units (viewBox is 2000 × 1001)
|
|
2404
|
+
pinImageWidth: 20,
|
|
2405
|
+
pinImageHeight: 20,
|
|
2406
|
+
|
|
2407
|
+
// Offset from computed pin position, in SVG units (added after auto center or pinX/pinY)
|
|
2408
|
+
pinOffsetX: 0,
|
|
2409
|
+
pinOffsetY: 0
|
|
2383
2410
|
};
|
|
2384
2411
|
|
|
2385
2412
|
this.options = Object.assign({}, defaultOptions, options);
|
|
@@ -3231,6 +3258,102 @@
|
|
|
3231
3258
|
|
|
3232
3259
|
// Add map elements
|
|
3233
3260
|
var countryElements = [];
|
|
3261
|
+
|
|
3262
|
+
const clearActive = function clearActive() {
|
|
3263
|
+
this.mapImage
|
|
3264
|
+
.querySelectorAll('.svgMap-active')
|
|
3265
|
+
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3266
|
+
}.bind(this);
|
|
3267
|
+
|
|
3268
|
+
const isClickTooltip =
|
|
3269
|
+
this.options.showTooltips && this.options.tooltipTrigger === 'click';
|
|
3270
|
+
|
|
3271
|
+
const getCountryFromEvent = function (e) {
|
|
3272
|
+
return e.target && e.target.closest
|
|
3273
|
+
? e.target.closest('.svgMap-country')
|
|
3274
|
+
: null;
|
|
3275
|
+
};
|
|
3276
|
+
|
|
3277
|
+
const raiseCountry = function (countryElement, setActive) {
|
|
3278
|
+
if (setActive) {
|
|
3279
|
+
clearActive();
|
|
3280
|
+
}
|
|
3281
|
+
countryElement.parentNode.insertBefore(
|
|
3282
|
+
countryElement,
|
|
3283
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3284
|
+
);
|
|
3285
|
+
if (setActive) {
|
|
3286
|
+
countryElement.classList.add('svgMap-active');
|
|
3287
|
+
}
|
|
3288
|
+
}.bind(this);
|
|
3289
|
+
|
|
3290
|
+
const showCountryTooltip = function (countryElement, e, setActive) {
|
|
3291
|
+
raiseCountry(countryElement, setActive);
|
|
3292
|
+
this.setTooltipContent(this.getTooltipContent(countryElement.dataset.id));
|
|
3293
|
+
this.showTooltip(e);
|
|
3294
|
+
}.bind(this);
|
|
3295
|
+
|
|
3296
|
+
// Touch only: preview tooltip on finger down without marking country active
|
|
3297
|
+
// (active is set on pointerup so link countries keep two-tap navigation)
|
|
3298
|
+
this.mapImage.addEventListener(
|
|
3299
|
+
'pointerdown',
|
|
3300
|
+
(e) => {
|
|
3301
|
+
if (!this.options.showTooltips || e.pointerType !== 'touch') {
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
|
|
3305
|
+
const countryElement = getCountryFromEvent(e);
|
|
3306
|
+
if (!countryElement) {
|
|
3307
|
+
this.hideTooltip();
|
|
3308
|
+
return;
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
showCountryTooltip(countryElement, e, false);
|
|
3312
|
+
this.moveTooltip(e);
|
|
3313
|
+
},
|
|
3314
|
+
{ passive: true }
|
|
3315
|
+
);
|
|
3316
|
+
|
|
3317
|
+
this.mapImage.addEventListener(
|
|
3318
|
+
'pointercancel',
|
|
3319
|
+
(e) => {
|
|
3320
|
+
if (e.pointerType === 'touch') {
|
|
3321
|
+
this.hideTooltip();
|
|
3322
|
+
}
|
|
3323
|
+
},
|
|
3324
|
+
{ passive: true }
|
|
3325
|
+
);
|
|
3326
|
+
|
|
3327
|
+
// Hover (mouse/pen) and touch drag: raise country + optional floating tooltip
|
|
3328
|
+
this.mapImage.addEventListener(
|
|
3329
|
+
'pointermove',
|
|
3330
|
+
(e) => {
|
|
3331
|
+
const countryElement = getCountryFromEvent(e);
|
|
3332
|
+
if (!countryElement) {
|
|
3333
|
+
clearActive();
|
|
3334
|
+
if (this.options.showTooltips) {
|
|
3335
|
+
this.hideTooltip();
|
|
3336
|
+
}
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
const mouseClickMode = e.pointerType === 'mouse' && isClickTooltip;
|
|
3341
|
+
|
|
3342
|
+
// Always raise hovered country (SVG paint order + .svgMap-active stroke)
|
|
3343
|
+
if (!this.options.showTooltips || mouseClickMode) {
|
|
3344
|
+
raiseCountry(countryElement, true);
|
|
3345
|
+
return;
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
showCountryTooltip(countryElement, e, true);
|
|
3349
|
+
|
|
3350
|
+
if (e.pointerType === 'touch') {
|
|
3351
|
+
this.moveTooltip(e);
|
|
3352
|
+
}
|
|
3353
|
+
},
|
|
3354
|
+
{ passive: true }
|
|
3355
|
+
);
|
|
3356
|
+
|
|
3234
3357
|
Object.keys(mapPaths).forEach(
|
|
3235
3358
|
function (countryID) {
|
|
3236
3359
|
var countryData = this.mapPaths[countryID];
|
|
@@ -3248,166 +3371,22 @@
|
|
|
3248
3371
|
'id',
|
|
3249
3372
|
this.id + '-map-country-' + countryID
|
|
3250
3373
|
);
|
|
3251
|
-
countryElement.
|
|
3374
|
+
countryElement.dataset.id = countryID;
|
|
3252
3375
|
countryElement.classList.add('svgMap-country');
|
|
3253
3376
|
|
|
3254
3377
|
this.mapImage.appendChild(countryElement);
|
|
3255
3378
|
countryElements.push(countryElement);
|
|
3256
3379
|
|
|
3257
|
-
// Add tooltip when touch is used
|
|
3258
|
-
function handlePointerMove(e) {
|
|
3259
|
-
if (e.pointerType === 'touch') return;
|
|
3260
|
-
|
|
3261
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
3262
|
-
|
|
3263
|
-
if (
|
|
3264
|
-
!target ||
|
|
3265
|
-
(!target.closest('.svgMap-country') &&
|
|
3266
|
-
!target.closest('.svgMap-tooltip'))
|
|
3267
|
-
) {
|
|
3268
|
-
this.hideTooltip();
|
|
3269
|
-
document
|
|
3270
|
-
.querySelectorAll('.svgMap-active')
|
|
3271
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3272
|
-
}
|
|
3273
|
-
}
|
|
3274
|
-
|
|
3275
|
-
const handlePointerMoveBound = handlePointerMove.bind(this);
|
|
3276
|
-
|
|
3277
|
-
countryElement.addEventListener(
|
|
3278
|
-
'pointerenter',
|
|
3279
|
-
function (e) {
|
|
3280
|
-
if (
|
|
3281
|
-
e.pointerType === 'mouse' &&
|
|
3282
|
-
this.options.showTooltips &&
|
|
3283
|
-
this.options.tooltipTrigger === 'click'
|
|
3284
|
-
) {
|
|
3285
|
-
return;
|
|
3286
|
-
}
|
|
3287
|
-
|
|
3288
|
-
// Only add pointermove listener for non-touch pointers
|
|
3289
|
-
if (e.pointerType !== 'touch') {
|
|
3290
|
-
document.addEventListener('pointermove', handlePointerMoveBound, {
|
|
3291
|
-
passive: true
|
|
3292
|
-
});
|
|
3293
|
-
}
|
|
3294
|
-
|
|
3295
|
-
document
|
|
3296
|
-
.querySelectorAll('.svgMap-active')
|
|
3297
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3298
|
-
|
|
3299
|
-
countryElement.parentNode.insertBefore(
|
|
3300
|
-
countryElement,
|
|
3301
|
-
this.persistentTooltipGroup || null
|
|
3302
|
-
);
|
|
3303
|
-
countryElement.classList.add('svgMap-active');
|
|
3304
|
-
|
|
3305
|
-
const countryID = countryElement.getAttribute('data-id');
|
|
3306
|
-
if (this.options.showTooltips) {
|
|
3307
|
-
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
3308
|
-
this.showTooltip(e);
|
|
3309
|
-
|
|
3310
|
-
// For touch, move tooltip to the touch position and keep it there
|
|
3311
|
-
if (e.pointerType === 'touch') {
|
|
3312
|
-
this.moveTooltip(e);
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
}.bind(this)
|
|
3316
|
-
);
|
|
3317
|
-
|
|
3318
|
-
// Handle touch move - update tooltip position while panning
|
|
3319
|
-
countryElement.addEventListener(
|
|
3320
|
-
'touchmove',
|
|
3321
|
-
function (e) {
|
|
3322
|
-
this.moveTooltip(e);
|
|
3323
|
-
}.bind(this),
|
|
3324
|
-
{ passive: true }
|
|
3325
|
-
);
|
|
3326
|
-
|
|
3327
|
-
// Handle touch end - remove active state and hide tooltip
|
|
3328
|
-
countryElement.addEventListener(
|
|
3329
|
-
'touchend',
|
|
3330
|
-
function (e) {
|
|
3331
|
-
const touch = e.changedTouches[0];
|
|
3332
|
-
const elementAtEnd = document.elementFromPoint(
|
|
3333
|
-
touch.clientX,
|
|
3334
|
-
touch.clientY
|
|
3335
|
-
);
|
|
3336
|
-
|
|
3337
|
-
// Only hide if touch ended outside the country or tooltip
|
|
3338
|
-
if (
|
|
3339
|
-
!elementAtEnd ||
|
|
3340
|
-
(!elementAtEnd.closest('.svgMap-country') &&
|
|
3341
|
-
!elementAtEnd.closest('.svgMap-tooltip'))
|
|
3342
|
-
) {
|
|
3343
|
-
this.hideTooltip();
|
|
3344
|
-
document
|
|
3345
|
-
.querySelectorAll('.svgMap-active')
|
|
3346
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3347
|
-
}
|
|
3348
|
-
}.bind(this),
|
|
3349
|
-
{ passive: true }
|
|
3350
|
-
);
|
|
3351
|
-
|
|
3352
|
-
// Remove pointermove listener when leaving non-touch pointer
|
|
3353
|
-
countryElement.addEventListener(
|
|
3354
|
-
'pointerleave',
|
|
3355
|
-
function (e) {
|
|
3356
|
-
if (e.pointerType !== 'touch') {
|
|
3357
|
-
document.removeEventListener(
|
|
3358
|
-
'pointermove',
|
|
3359
|
-
handlePointerMoveBound
|
|
3360
|
-
);
|
|
3361
|
-
if (
|
|
3362
|
-
!(
|
|
3363
|
-
e.pointerType === 'mouse' &&
|
|
3364
|
-
this.options.showTooltips &&
|
|
3365
|
-
this.options.tooltipTrigger === 'click'
|
|
3366
|
-
)
|
|
3367
|
-
) {
|
|
3368
|
-
this.hideTooltip();
|
|
3369
|
-
document
|
|
3370
|
-
.querySelectorAll('.svgMap-active')
|
|
3371
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3372
|
-
}
|
|
3373
|
-
}
|
|
3374
|
-
}.bind(this)
|
|
3375
|
-
);
|
|
3376
|
-
|
|
3377
|
-
document.addEventListener(
|
|
3378
|
-
'pointerover',
|
|
3379
|
-
function (e) {
|
|
3380
|
-
if (e.pointerType !== 'touch') return;
|
|
3381
|
-
|
|
3382
|
-
if (
|
|
3383
|
-
e.target.closest('.svgMap-country') ||
|
|
3384
|
-
e.target.closest('.svgMap-tooltip')
|
|
3385
|
-
) {
|
|
3386
|
-
return;
|
|
3387
|
-
}
|
|
3388
|
-
|
|
3389
|
-
this.hideTooltip();
|
|
3390
|
-
document
|
|
3391
|
-
.querySelectorAll('.svgMap-active')
|
|
3392
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3393
|
-
}.bind(this),
|
|
3394
|
-
{ passive: true }
|
|
3395
|
-
);
|
|
3396
|
-
|
|
3397
3380
|
if (
|
|
3398
3381
|
this.options.data.values &&
|
|
3399
3382
|
this.options.data.values[countryID] &&
|
|
3400
3383
|
this.options.data.values[countryID]['link']
|
|
3401
3384
|
) {
|
|
3402
|
-
countryElement.
|
|
3403
|
-
'
|
|
3404
|
-
this.options.data.values[countryID]['link']
|
|
3405
|
-
);
|
|
3385
|
+
countryElement.dataset.link =
|
|
3386
|
+
this.options.data.values[countryID]['link'];
|
|
3406
3387
|
if (this.options.data.values[countryID]['linkTarget']) {
|
|
3407
|
-
countryElement.
|
|
3408
|
-
|
|
3409
|
-
this.options.data.values[countryID]['linkTarget']
|
|
3410
|
-
);
|
|
3388
|
+
countryElement.dataset.linkTarget =
|
|
3389
|
+
this.options.data.values[countryID]['linkTarget'];
|
|
3411
3390
|
}
|
|
3412
3391
|
}
|
|
3413
3392
|
}.bind(this)
|
|
@@ -3421,6 +3400,10 @@
|
|
|
3421
3400
|
this.createPersistentTooltips(countryElements);
|
|
3422
3401
|
}
|
|
3423
3402
|
|
|
3403
|
+
if (this.options.staticPins) {
|
|
3404
|
+
this.createStaticPins(countryElements);
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3424
3407
|
let pointerStart = null;
|
|
3425
3408
|
let activeCountry = null;
|
|
3426
3409
|
|
|
@@ -3453,21 +3436,18 @@
|
|
|
3453
3436
|
const countryElement = e.target.closest('.svgMap-country');
|
|
3454
3437
|
if (!countryElement) return;
|
|
3455
3438
|
|
|
3456
|
-
const countryID = countryElement.
|
|
3457
|
-
const link = countryElement.
|
|
3458
|
-
const linkTarget = countryElement.
|
|
3439
|
+
const countryID = countryElement.dataset.id;
|
|
3440
|
+
const link = countryElement.dataset.link;
|
|
3441
|
+
const linkTarget = countryElement.dataset.linkTarget;
|
|
3459
3442
|
const hasCallback = typeof this.options.onCountryClick === 'function';
|
|
3460
3443
|
const hasLink = !!link;
|
|
3461
3444
|
const isTouch = e.pointerType === 'touch' || e.pointerType === 'pen';
|
|
3462
3445
|
|
|
3463
|
-
const isClickTooltipMouse =
|
|
3464
|
-
e.pointerType === 'mouse' &&
|
|
3465
|
-
this.options.showTooltips &&
|
|
3466
|
-
this.options.tooltipTrigger === 'click';
|
|
3446
|
+
const isClickTooltipMouse = e.pointerType === 'mouse' && isClickTooltip;
|
|
3467
3447
|
|
|
3468
3448
|
if (!hasLink && !hasCallback && !isClickTooltipMouse) return;
|
|
3469
3449
|
|
|
3470
|
-
if (isClickTooltipMouse
|
|
3450
|
+
if (isClickTooltipMouse) {
|
|
3471
3451
|
const willNavigate =
|
|
3472
3452
|
hasLink && countryElement.classList.contains('svgMap-active');
|
|
3473
3453
|
const shouldFireCallback = hasCallback && (!hasLink || willNavigate);
|
|
@@ -3483,12 +3463,10 @@
|
|
|
3483
3463
|
if (linkTarget) window.open(link, linkTarget);
|
|
3484
3464
|
else window.location.href = link;
|
|
3485
3465
|
} else {
|
|
3486
|
-
|
|
3487
|
-
.querySelectorAll('.svgMap-country.svgMap-active')
|
|
3488
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3466
|
+
clearActive();
|
|
3489
3467
|
countryElement.parentNode.insertBefore(
|
|
3490
3468
|
countryElement,
|
|
3491
|
-
this.persistentTooltipGroup || null
|
|
3469
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3492
3470
|
);
|
|
3493
3471
|
countryElement.classList.add('svgMap-active');
|
|
3494
3472
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3499,12 +3477,10 @@
|
|
|
3499
3477
|
|
|
3500
3478
|
if (callbackResultClick === false) return;
|
|
3501
3479
|
|
|
3502
|
-
|
|
3503
|
-
.querySelectorAll('.svgMap-country.svgMap-active')
|
|
3504
|
-
.forEach((el) => el.classList.remove('svgMap-active'));
|
|
3480
|
+
clearActive();
|
|
3505
3481
|
countryElement.parentNode.insertBefore(
|
|
3506
3482
|
countryElement,
|
|
3507
|
-
this.persistentTooltipGroup || null
|
|
3483
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3508
3484
|
);
|
|
3509
3485
|
countryElement.classList.add('svgMap-active');
|
|
3510
3486
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3554,15 +3530,9 @@
|
|
|
3554
3530
|
});
|
|
3555
3531
|
|
|
3556
3532
|
this._clickTooltipOutsideHandler = function (ev) {
|
|
3557
|
-
if (
|
|
3558
|
-
if (
|
|
3559
|
-
!this.options.showTooltips ||
|
|
3560
|
-
this.options.tooltipTrigger !== 'click' ||
|
|
3561
|
-
!this.tooltip
|
|
3562
|
-
) {
|
|
3533
|
+
if (!this.tooltip || !this.tooltip.classList.contains('svgMap-active')) {
|
|
3563
3534
|
return;
|
|
3564
3535
|
}
|
|
3565
|
-
if (!this.tooltip.classList.contains('svgMap-active')) return;
|
|
3566
3536
|
var node = ev.target;
|
|
3567
3537
|
if (
|
|
3568
3538
|
node &&
|
|
@@ -3580,11 +3550,6 @@
|
|
|
3580
3550
|
});
|
|
3581
3551
|
}
|
|
3582
3552
|
}.bind(this);
|
|
3583
|
-
document.addEventListener(
|
|
3584
|
-
'pointerdown',
|
|
3585
|
-
this._clickTooltipOutsideHandler,
|
|
3586
|
-
true
|
|
3587
|
-
);
|
|
3588
3553
|
|
|
3589
3554
|
// Expose instance
|
|
3590
3555
|
var me = this;
|
|
@@ -3667,7 +3632,7 @@
|
|
|
3667
3632
|
|
|
3668
3633
|
countryElements.forEach(
|
|
3669
3634
|
function (countryElement) {
|
|
3670
|
-
var countryID = countryElement.
|
|
3635
|
+
var countryID = countryElement.dataset.id;
|
|
3671
3636
|
if (!this.shouldShowTooltipOnLoad(countryID)) {
|
|
3672
3637
|
return;
|
|
3673
3638
|
}
|
|
@@ -3703,6 +3668,157 @@
|
|
|
3703
3668
|
);
|
|
3704
3669
|
}
|
|
3705
3670
|
|
|
3671
|
+
// Create static pins on the map
|
|
3672
|
+
|
|
3673
|
+
createStaticPins(countryElements) {
|
|
3674
|
+
if (this.pinGroup) {
|
|
3675
|
+
this.pinGroup.remove();
|
|
3676
|
+
}
|
|
3677
|
+
|
|
3678
|
+
this.pinGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
3679
|
+
this.pinGroup.classList.add('svgMap-pin-group');
|
|
3680
|
+
this.mapImage.appendChild(this.pinGroup);
|
|
3681
|
+
|
|
3682
|
+
countryElements.forEach(
|
|
3683
|
+
function (countryElement) {
|
|
3684
|
+
var countryID = countryElement.getAttribute('data-id');
|
|
3685
|
+
if (!this.shouldShowPin(countryID)) {
|
|
3686
|
+
return;
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
var countryValues = this.options.data.values[countryID];
|
|
3690
|
+
var cx, cy;
|
|
3691
|
+
|
|
3692
|
+
if (
|
|
3693
|
+
countryValues &&
|
|
3694
|
+
countryValues.pinX != null &&
|
|
3695
|
+
countryValues.pinY != null
|
|
3696
|
+
) {
|
|
3697
|
+
cx = countryValues.pinX;
|
|
3698
|
+
cy = countryValues.pinY;
|
|
3699
|
+
} else {
|
|
3700
|
+
// Split the path at absolute M commands and use the largest sub-path
|
|
3701
|
+
// to avoid overseas territories (islands, colonies) skewing the center.
|
|
3702
|
+
var d = countryElement.getAttribute('d');
|
|
3703
|
+
var subPaths = d.split(/(?=M)/).filter((s) => s.trim().length > 0);
|
|
3704
|
+
var largestBB = null;
|
|
3705
|
+
var largestArea = -1;
|
|
3706
|
+
|
|
3707
|
+
subPaths.forEach(
|
|
3708
|
+
function (subPath) {
|
|
3709
|
+
var tmp = document.createElementNS(
|
|
3710
|
+
'http://www.w3.org/2000/svg',
|
|
3711
|
+
'path'
|
|
3712
|
+
);
|
|
3713
|
+
tmp.setAttribute('d', subPath);
|
|
3714
|
+
this.mapImage.appendChild(tmp);
|
|
3715
|
+
var bb = tmp.getBBox();
|
|
3716
|
+
var area = bb.width * bb.height;
|
|
3717
|
+
if (area > largestArea) {
|
|
3718
|
+
largestArea = area;
|
|
3719
|
+
largestBB = bb;
|
|
3720
|
+
}
|
|
3721
|
+
this.mapImage.removeChild(tmp);
|
|
3722
|
+
}.bind(this)
|
|
3723
|
+
);
|
|
3724
|
+
|
|
3725
|
+
cx = largestBB.x + largestBB.width / 2;
|
|
3726
|
+
cy = largestBB.y + largestBB.height / 2;
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3729
|
+
var offsetX =
|
|
3730
|
+
countryValues && countryValues.pinOffsetX != null
|
|
3731
|
+
? countryValues.pinOffsetX
|
|
3732
|
+
: this.options.pinOffsetX;
|
|
3733
|
+
var offsetY =
|
|
3734
|
+
countryValues && countryValues.pinOffsetY != null
|
|
3735
|
+
? countryValues.pinOffsetY
|
|
3736
|
+
: this.options.pinOffsetY;
|
|
3737
|
+
cx += offsetX;
|
|
3738
|
+
cy += offsetY;
|
|
3739
|
+
|
|
3740
|
+
var color =
|
|
3741
|
+
(countryValues && countryValues.pinColor) || this.options.pinColor;
|
|
3742
|
+
var size =
|
|
3743
|
+
(countryValues && countryValues.pinSize) || this.options.pinSize;
|
|
3744
|
+
var strokeColor =
|
|
3745
|
+
(countryValues && countryValues.pinStrokeColor) ||
|
|
3746
|
+
this.options.pinStrokeColor;
|
|
3747
|
+
var strokeWidth =
|
|
3748
|
+
(countryValues && countryValues.pinStrokeWidth) ||
|
|
3749
|
+
this.options.pinStrokeWidth;
|
|
3750
|
+
|
|
3751
|
+
if (typeof this.options.onGetPin === 'function') {
|
|
3752
|
+
var custom = this.options.onGetPin(countryID, countryValues);
|
|
3753
|
+
if (custom) {
|
|
3754
|
+
custom.setAttribute(
|
|
3755
|
+
'transform',
|
|
3756
|
+
'translate(' + cx + ',' + cy + ')'
|
|
3757
|
+
);
|
|
3758
|
+
this.pinGroup.appendChild(custom);
|
|
3759
|
+
return;
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
var pinImage =
|
|
3764
|
+
(countryValues && countryValues.pinImage) || this.options.pinImage;
|
|
3765
|
+
|
|
3766
|
+
if (pinImage) {
|
|
3767
|
+
var pinW =
|
|
3768
|
+
(countryValues && countryValues.pinImageWidth) ||
|
|
3769
|
+
this.options.pinImageWidth;
|
|
3770
|
+
var pinH =
|
|
3771
|
+
(countryValues && countryValues.pinImageHeight) ||
|
|
3772
|
+
this.options.pinImageHeight;
|
|
3773
|
+
var img = document.createElementNS(
|
|
3774
|
+
'http://www.w3.org/2000/svg',
|
|
3775
|
+
'image'
|
|
3776
|
+
);
|
|
3777
|
+
img.setAttribute('href', pinImage);
|
|
3778
|
+
img.setAttribute('x', cx - pinW / 2);
|
|
3779
|
+
img.setAttribute('y', cy - pinH / 2);
|
|
3780
|
+
img.setAttribute('width', pinW);
|
|
3781
|
+
img.setAttribute('height', pinH);
|
|
3782
|
+
img.setAttribute('data-id', countryID);
|
|
3783
|
+
img.classList.add('svgMap-pin');
|
|
3784
|
+
this.pinGroup.appendChild(img);
|
|
3785
|
+
return;
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3788
|
+
var circle = document.createElementNS(
|
|
3789
|
+
'http://www.w3.org/2000/svg',
|
|
3790
|
+
'circle'
|
|
3791
|
+
);
|
|
3792
|
+
circle.setAttribute('cx', cx);
|
|
3793
|
+
circle.setAttribute('cy', cy);
|
|
3794
|
+
circle.setAttribute('r', size);
|
|
3795
|
+
circle.setAttribute('fill', color);
|
|
3796
|
+
if (strokeWidth > 0) {
|
|
3797
|
+
circle.setAttribute('stroke', strokeColor);
|
|
3798
|
+
circle.setAttribute('stroke-width', strokeWidth);
|
|
3799
|
+
circle.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
3800
|
+
}
|
|
3801
|
+
circle.setAttribute('data-id', countryID);
|
|
3802
|
+
circle.classList.add('svgMap-pin');
|
|
3803
|
+
this.pinGroup.appendChild(circle);
|
|
3804
|
+
}.bind(this)
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
// Check if a static pin should be shown for a country
|
|
3809
|
+
|
|
3810
|
+
shouldShowPin(countryID) {
|
|
3811
|
+
var pins = this.options.staticPins;
|
|
3812
|
+
var countryValues = this.options.data.values[countryID];
|
|
3813
|
+
if (Array.isArray(pins)) {
|
|
3814
|
+
return pins.indexOf(countryID) !== -1;
|
|
3815
|
+
}
|
|
3816
|
+
if (typeof pins === 'function') {
|
|
3817
|
+
return pins(countryID, countryValues);
|
|
3818
|
+
}
|
|
3819
|
+
return false;
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3706
3822
|
// Check if a persistent tooltip should be shown on load
|
|
3707
3823
|
|
|
3708
3824
|
shouldShowTooltipOnLoad(countryID) {
|
|
@@ -4712,6 +4828,23 @@
|
|
|
4712
4828
|
return;
|
|
4713
4829
|
}
|
|
4714
4830
|
this.tooltip.classList.add('svgMap-active');
|
|
4831
|
+
|
|
4832
|
+
if (
|
|
4833
|
+
this.options.showTooltips &&
|
|
4834
|
+
this.options.tooltipTrigger === 'click' &&
|
|
4835
|
+
e.pointerType === 'mouse'
|
|
4836
|
+
) {
|
|
4837
|
+
// don't register event listener in the same frame
|
|
4838
|
+
// to prevent it from being triggered immediately
|
|
4839
|
+
requestAnimationFrame(() => {
|
|
4840
|
+
document.addEventListener(
|
|
4841
|
+
'pointerdown',
|
|
4842
|
+
this._clickTooltipOutsideHandler,
|
|
4843
|
+
{ once: true, passive: true }
|
|
4844
|
+
);
|
|
4845
|
+
});
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4715
4848
|
this.moveTooltip(e);
|
|
4716
4849
|
}
|
|
4717
4850
|
|
|
@@ -4721,7 +4854,12 @@
|
|
|
4721
4854
|
if (!this.tooltip) {
|
|
4722
4855
|
return;
|
|
4723
4856
|
}
|
|
4857
|
+
|
|
4724
4858
|
this.tooltip.classList.remove('svgMap-active');
|
|
4859
|
+
document.removeEventListener(
|
|
4860
|
+
'pointerdown',
|
|
4861
|
+
this._clickTooltipOutsideHandler
|
|
4862
|
+
);
|
|
4725
4863
|
}
|
|
4726
4864
|
|
|
4727
4865
|
// Move the tooltip
|