svgmap 2.20.1 → 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/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);
@@ -3247,7 +3274,7 @@ class svgMap {
3247
3274
  }
3248
3275
  countryElement.parentNode.insertBefore(
3249
3276
  countryElement,
3250
- this.persistentTooltipGroup || null
3277
+ this.persistentTooltipGroup || this.pinGroup || null
3251
3278
  );
3252
3279
  if (setActive) {
3253
3280
  countryElement.classList.add('svgMap-active');
@@ -3367,6 +3394,10 @@ class svgMap {
3367
3394
  this.createPersistentTooltips(countryElements);
3368
3395
  }
3369
3396
 
3397
+ if (this.options.staticPins) {
3398
+ this.createStaticPins(countryElements);
3399
+ }
3400
+
3370
3401
  let pointerStart = null;
3371
3402
  let activeCountry = null;
3372
3403
 
@@ -3429,7 +3460,7 @@ class svgMap {
3429
3460
  clearActive();
3430
3461
  countryElement.parentNode.insertBefore(
3431
3462
  countryElement,
3432
- this.persistentTooltipGroup || null
3463
+ this.persistentTooltipGroup || this.pinGroup || null
3433
3464
  );
3434
3465
  countryElement.classList.add('svgMap-active');
3435
3466
  this.setTooltipContent(this.getTooltipContent(countryID));
@@ -3443,7 +3474,7 @@ class svgMap {
3443
3474
  clearActive();
3444
3475
  countryElement.parentNode.insertBefore(
3445
3476
  countryElement,
3446
- this.persistentTooltipGroup || null
3477
+ this.persistentTooltipGroup || this.pinGroup || null
3447
3478
  );
3448
3479
  countryElement.classList.add('svgMap-active');
3449
3480
  this.setTooltipContent(this.getTooltipContent(countryID));
@@ -3631,6 +3662,157 @@ class svgMap {
3631
3662
  );
3632
3663
  }
3633
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
+
3634
3816
  // Check if a persistent tooltip should be shown on load
3635
3817
 
3636
3818
  shouldShowTooltipOnLoad(countryID) {