svgmap 2.20.0 → 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/dist/svgMap.js CHANGED
@@ -3231,6 +3231,102 @@
3231
3231
 
3232
3232
  // Add map elements
3233
3233
  var countryElements = [];
3234
+
3235
+ const clearActive = function clearActive() {
3236
+ this.mapImage
3237
+ .querySelectorAll('.svgMap-active')
3238
+ .forEach((el) => el.classList.remove('svgMap-active'));
3239
+ }.bind(this);
3240
+
3241
+ const isClickTooltip =
3242
+ this.options.showTooltips && this.options.tooltipTrigger === 'click';
3243
+
3244
+ const getCountryFromEvent = function (e) {
3245
+ return e.target && e.target.closest
3246
+ ? e.target.closest('.svgMap-country')
3247
+ : null;
3248
+ };
3249
+
3250
+ const raiseCountry = function (countryElement, setActive) {
3251
+ if (setActive) {
3252
+ clearActive();
3253
+ }
3254
+ countryElement.parentNode.insertBefore(
3255
+ countryElement,
3256
+ this.persistentTooltipGroup || null
3257
+ );
3258
+ if (setActive) {
3259
+ countryElement.classList.add('svgMap-active');
3260
+ }
3261
+ }.bind(this);
3262
+
3263
+ const showCountryTooltip = function (countryElement, e, setActive) {
3264
+ raiseCountry(countryElement, setActive);
3265
+ this.setTooltipContent(this.getTooltipContent(countryElement.dataset.id));
3266
+ this.showTooltip(e);
3267
+ }.bind(this);
3268
+
3269
+ // Touch only: preview tooltip on finger down without marking country active
3270
+ // (active is set on pointerup so link countries keep two-tap navigation)
3271
+ this.mapImage.addEventListener(
3272
+ 'pointerdown',
3273
+ (e) => {
3274
+ if (!this.options.showTooltips || e.pointerType !== 'touch') {
3275
+ return;
3276
+ }
3277
+
3278
+ const countryElement = getCountryFromEvent(e);
3279
+ if (!countryElement) {
3280
+ this.hideTooltip();
3281
+ return;
3282
+ }
3283
+
3284
+ showCountryTooltip(countryElement, e, false);
3285
+ this.moveTooltip(e);
3286
+ },
3287
+ { passive: true }
3288
+ );
3289
+
3290
+ this.mapImage.addEventListener(
3291
+ 'pointercancel',
3292
+ (e) => {
3293
+ if (e.pointerType === 'touch') {
3294
+ this.hideTooltip();
3295
+ }
3296
+ },
3297
+ { passive: true }
3298
+ );
3299
+
3300
+ // Hover (mouse/pen) and touch drag: raise country + optional floating tooltip
3301
+ this.mapImage.addEventListener(
3302
+ 'pointermove',
3303
+ (e) => {
3304
+ const countryElement = getCountryFromEvent(e);
3305
+ if (!countryElement) {
3306
+ clearActive();
3307
+ if (this.options.showTooltips) {
3308
+ this.hideTooltip();
3309
+ }
3310
+ return;
3311
+ }
3312
+
3313
+ const mouseClickMode = e.pointerType === 'mouse' && isClickTooltip;
3314
+
3315
+ // Always raise hovered country (SVG paint order + .svgMap-active stroke)
3316
+ if (!this.options.showTooltips || mouseClickMode) {
3317
+ raiseCountry(countryElement, true);
3318
+ return;
3319
+ }
3320
+
3321
+ showCountryTooltip(countryElement, e, true);
3322
+
3323
+ if (e.pointerType === 'touch') {
3324
+ this.moveTooltip(e);
3325
+ }
3326
+ },
3327
+ { passive: true }
3328
+ );
3329
+
3234
3330
  Object.keys(mapPaths).forEach(
3235
3331
  function (countryID) {
3236
3332
  var countryData = this.mapPaths[countryID];
@@ -3248,166 +3344,22 @@
3248
3344
  'id',
3249
3345
  this.id + '-map-country-' + countryID
3250
3346
  );
3251
- countryElement.setAttribute('data-id', countryID);
3347
+ countryElement.dataset.id = countryID;
3252
3348
  countryElement.classList.add('svgMap-country');
3253
3349
 
3254
3350
  this.mapImage.appendChild(countryElement);
3255
3351
  countryElements.push(countryElement);
3256
3352
 
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
3353
  if (
3398
3354
  this.options.data.values &&
3399
3355
  this.options.data.values[countryID] &&
3400
3356
  this.options.data.values[countryID]['link']
3401
3357
  ) {
3402
- countryElement.setAttribute(
3403
- 'data-link',
3404
- this.options.data.values[countryID]['link']
3405
- );
3358
+ countryElement.dataset.link =
3359
+ this.options.data.values[countryID]['link'];
3406
3360
  if (this.options.data.values[countryID]['linkTarget']) {
3407
- countryElement.setAttribute(
3408
- 'data-link-target',
3409
- this.options.data.values[countryID]['linkTarget']
3410
- );
3361
+ countryElement.dataset.linkTarget =
3362
+ this.options.data.values[countryID]['linkTarget'];
3411
3363
  }
3412
3364
  }
3413
3365
  }.bind(this)
@@ -3453,21 +3405,18 @@
3453
3405
  const countryElement = e.target.closest('.svgMap-country');
3454
3406
  if (!countryElement) return;
3455
3407
 
3456
- const countryID = countryElement.getAttribute('data-id');
3457
- const link = countryElement.getAttribute('data-link');
3458
- const linkTarget = countryElement.getAttribute('data-link-target');
3408
+ const countryID = countryElement.dataset.id;
3409
+ const link = countryElement.dataset.link;
3410
+ const linkTarget = countryElement.dataset.linkTarget;
3459
3411
  const hasCallback = typeof this.options.onCountryClick === 'function';
3460
3412
  const hasLink = !!link;
3461
3413
  const isTouch = e.pointerType === 'touch' || e.pointerType === 'pen';
3462
3414
 
3463
- const isClickTooltipMouse =
3464
- e.pointerType === 'mouse' &&
3465
- this.options.showTooltips &&
3466
- this.options.tooltipTrigger === 'click';
3415
+ const isClickTooltipMouse = e.pointerType === 'mouse' && isClickTooltip;
3467
3416
 
3468
3417
  if (!hasLink && !hasCallback && !isClickTooltipMouse) return;
3469
3418
 
3470
- if (isClickTooltipMouse && this.options.showTooltips) {
3419
+ if (isClickTooltipMouse) {
3471
3420
  const willNavigate =
3472
3421
  hasLink && countryElement.classList.contains('svgMap-active');
3473
3422
  const shouldFireCallback = hasCallback && (!hasLink || willNavigate);
@@ -3483,9 +3432,7 @@
3483
3432
  if (linkTarget) window.open(link, linkTarget);
3484
3433
  else window.location.href = link;
3485
3434
  } else {
3486
- this.mapImage
3487
- .querySelectorAll('.svgMap-country.svgMap-active')
3488
- .forEach((el) => el.classList.remove('svgMap-active'));
3435
+ clearActive();
3489
3436
  countryElement.parentNode.insertBefore(
3490
3437
  countryElement,
3491
3438
  this.persistentTooltipGroup || null
@@ -3499,9 +3446,7 @@
3499
3446
 
3500
3447
  if (callbackResultClick === false) return;
3501
3448
 
3502
- this.mapImage
3503
- .querySelectorAll('.svgMap-country.svgMap-active')
3504
- .forEach((el) => el.classList.remove('svgMap-active'));
3449
+ clearActive();
3505
3450
  countryElement.parentNode.insertBefore(
3506
3451
  countryElement,
3507
3452
  this.persistentTooltipGroup || null
@@ -3554,15 +3499,9 @@
3554
3499
  });
3555
3500
 
3556
3501
  this._clickTooltipOutsideHandler = function (ev) {
3557
- if (ev.pointerType !== 'mouse') return;
3558
- if (
3559
- !this.options.showTooltips ||
3560
- this.options.tooltipTrigger !== 'click' ||
3561
- !this.tooltip
3562
- ) {
3502
+ if (!this.tooltip || !this.tooltip.classList.contains('svgMap-active')) {
3563
3503
  return;
3564
3504
  }
3565
- if (!this.tooltip.classList.contains('svgMap-active')) return;
3566
3505
  var node = ev.target;
3567
3506
  if (
3568
3507
  node &&
@@ -3580,11 +3519,6 @@
3580
3519
  });
3581
3520
  }
3582
3521
  }.bind(this);
3583
- document.addEventListener(
3584
- 'pointerdown',
3585
- this._clickTooltipOutsideHandler,
3586
- true
3587
- );
3588
3522
 
3589
3523
  // Expose instance
3590
3524
  var me = this;
@@ -3667,7 +3601,7 @@
3667
3601
 
3668
3602
  countryElements.forEach(
3669
3603
  function (countryElement) {
3670
- var countryID = countryElement.getAttribute('data-id');
3604
+ var countryID = countryElement.dataset.id;
3671
3605
  if (!this.shouldShowTooltipOnLoad(countryID)) {
3672
3606
  return;
3673
3607
  }
@@ -4712,6 +4646,23 @@
4712
4646
  return;
4713
4647
  }
4714
4648
  this.tooltip.classList.add('svgMap-active');
4649
+
4650
+ if (
4651
+ this.options.showTooltips &&
4652
+ this.options.tooltipTrigger === 'click' &&
4653
+ e.pointerType === 'mouse'
4654
+ ) {
4655
+ // don't register event listener in the same frame
4656
+ // to prevent it from being triggered immediately
4657
+ requestAnimationFrame(() => {
4658
+ document.addEventListener(
4659
+ 'pointerdown',
4660
+ this._clickTooltipOutsideHandler,
4661
+ { once: true, passive: true }
4662
+ );
4663
+ });
4664
+ }
4665
+
4715
4666
  this.moveTooltip(e);
4716
4667
  }
4717
4668
 
@@ -4721,7 +4672,12 @@
4721
4672
  if (!this.tooltip) {
4722
4673
  return;
4723
4674
  }
4675
+
4724
4676
  this.tooltip.classList.remove('svgMap-active');
4677
+ document.removeEventListener(
4678
+ 'pointerdown',
4679
+ this._clickTooltipOutsideHandler
4680
+ );
4725
4681
  }
4726
4682
 
4727
4683
  // Move the tooltip