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/README.md +22 -0
- package/dist/index.cjs +186 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +186 -4
- 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 +186 -4
- 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 +186 -4
- package/dist/svgMap.js.map +1 -1
- package/dist/svgMap.min.css +1 -1
- package/dist/svgMap.min.js +1 -1
- package/package.json +1 -1
- package/src/js/core/svg-map.js +186 -4
- package/src/scss/map.scss +11 -0
package/README.md
CHANGED
|
@@ -102,6 +102,17 @@ You can pass the following options into svgMap:
|
|
|
102
102
|
| `showTooltips` | `boolean` | `true` | When `false`, disables hover and touch-following tooltips only. Persistent on-map labels from `persistentTooltips` are unaffected. On touch devices, countries with a `link` open it on the first tap instead of using the two-tap pattern (first tap preview, second tap navigate). |
|
|
103
103
|
| `tooltipTrigger` | `'hover'`, `'click'` | `'hover'` | How the floating tooltip opens with the **mouse**: `'hover'` opens on mouseenter/mouseleave.`'click'` opens on primary click and closes when clicking outside the map countries or tooltip. Only applies when `showTooltips` is `true`. |
|
|
104
104
|
| `persistentTooltips` | `false`, `array`, `function` | `false` | Persistent tooltips fixed on the map when it loads: an array of country IDs, or a function (`function (countryID, countryValues) { … }`) to decide per country. Independent of `showTooltips`. Best used with `showTooltips: false` or `tooltipTrigger: 'click'`. |
|
|
105
|
+
| `staticPins` | `false`, `array`, `function` | `false` | Static pins on the map at load time: an array of [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country IDs (e.g. `['DE', 'FR']`), or a function (`function (countryID, countryValues) { … }`) to decide per country. Pins are placed at the geographic center of each country (largest landmass). Independent of `showTooltips`. |
|
|
106
|
+
| `pinColor` | `string` | `'#000000'` | Default fill color for circle pins. Accepts CSS vars, color names, rgb or hex values. Can be overridden per country via `data.values[id].pinColor`. |
|
|
107
|
+
| `pinStrokeColor` | `string` | `'#ffffff'` | Default stroke color for circle pins. Can be overridden per country via `data.values[id].pinStrokeColor`. |
|
|
108
|
+
| `pinStrokeWidth` | `number` | `1` | Default stroke width for circle pins, in screen pixels (non-scaling stroke). Can be overridden per country via `data.values[id].pinStrokeWidth`. Set to `0` for no stroke. |
|
|
109
|
+
| `pinSize` | `number` | `8` | Default radius for circle pins, in SVG units (viewBox is 2000 × 1001). Can be overridden per country via `data.values[id].pinSize`. |
|
|
110
|
+
| `pinImage` | `string` | | Image URL used as a pin instead of the default circle. Can be overridden per country via `data.values[id].pinImage`. |
|
|
111
|
+
| `pinImageWidth` | `number` | `20` | Width of the pin image in SVG units. Can be overridden per country via `data.values[id].pinImageWidth`. |
|
|
112
|
+
| `pinImageHeight` | `number` | `20` | Height of the pin image in SVG units. Can be overridden per country via `data.values[id].pinImageHeight`. |
|
|
113
|
+
| `pinOffsetX` | `number` | `0` | Horizontal offset from the pin position, in SVG units. Added after auto placement or `pinX`/`pinY`. Can be overridden per country via `data.values[id].pinOffsetX`. |
|
|
114
|
+
| `pinOffsetY` | `number` | `0` | Vertical offset from the pin position, in SVG units. Added after auto placement or `pinX`/`pinY`. Can be overridden per country via `data.values[id].pinOffsetY`. |
|
|
115
|
+
| `onGetPin` | `function` | | Custom pin element. Signature: `function (countryID, countryValues) { return svgElement; }`. Return an SVG element (e.g. `<g>`, `<path>`) to use instead of the default circle or image pin. The library positions it at the pin coordinates via `transform`. Return `null` to fall back to the default pin. |
|
|
105
116
|
| `onGetTooltip` | `function` | | Called when a tooltip is created to custimize the tooltip content (`function (tooltipDiv, countryID, countryValues) { return 'Custom HTML'; }`) |
|
|
106
117
|
| `onCountryClick` | `function` | | Called when the user clicks a country (primary button, pointer released without dragging). Signature: `function (countryID, event) { … }`. Use this for custom actions instead of or in addition to `data.values.link`. Return `false` to skip opening the URL when the country has a `link`. On touch devices with a link, the callback runs when the tap would navigate (not on the first tap that only shows the tooltip). Countries show a pointer cursor while this option is set. |
|
|
107
118
|
| `countries` | `object` | | Additional options specific to countries: |
|
|
@@ -117,6 +128,17 @@ You can pass the following options into svgMap:
|
|
|
117
128
|
| `↳ color` | `string` | | Forces a color for this country |
|
|
118
129
|
| `↳ link` | `string` | | An URL to redirect to when clicking the country |
|
|
119
130
|
| `↳ linkTarget` | `string` | | The target of the link. By default the link will be opened in the same tab. Use `'_blank'` to open the link in a new tab |
|
|
131
|
+
| `↳ pinColor` | `string` | | Pin fill color for this country (circle pins only) |
|
|
132
|
+
| `↳ pinStrokeColor` | `string` | | Pin stroke color for this country (circle pins only) |
|
|
133
|
+
| `↳ pinStrokeWidth` | `number` | | Pin stroke width for this country, in screen pixels (circle pins only) |
|
|
134
|
+
| `↳ pinSize` | `number` | | Pin radius for this country (circle pins only) |
|
|
135
|
+
| `↳ pinX` | `number` | | Pin X position in SVG units; use with `pinY` to override auto placement |
|
|
136
|
+
| `↳ pinY` | `number` | | Pin Y position in SVG units; use with `pinX` to override auto placement |
|
|
137
|
+
| `↳ pinOffsetX` | `number` | | Horizontal offset from the pin position, in SVG units (after auto placement or `pinX`/`pinY`) |
|
|
138
|
+
| `↳ pinOffsetY` | `number` | | Vertical offset from the pin position, in SVG units (after auto placement or `pinX`/`pinY`) |
|
|
139
|
+
| `↳ pinImage` | `string` | | Image URL used as the pin for this country |
|
|
140
|
+
| `↳ pinImageWidth` | `number` | | Width of the pin image for this country |
|
|
141
|
+
| `↳ pinImageHeight` | `number` | | Height of the pin image for this country |
|
|
120
142
|
| `countryNames` | `object` | | An object with the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code as key and the country name as value |
|
|
121
143
|
---
|
|
122
144
|
|
package/dist/index.cjs
CHANGED
|
@@ -2375,7 +2375,34 @@ class svgMap {
|
|
|
2375
2375
|
showContinentSelector: false,
|
|
2376
2376
|
|
|
2377
2377
|
// Reset zoom on resize
|
|
2378
|
-
resetZoomOnResize: false
|
|
2378
|
+
resetZoomOnResize: false,
|
|
2379
|
+
|
|
2380
|
+
// Static pins: false | string[] | function(countryID, countryValues) => boolean
|
|
2381
|
+
staticPins: false,
|
|
2382
|
+
|
|
2383
|
+
// Default pin fill color
|
|
2384
|
+
pinColor: '#000000',
|
|
2385
|
+
|
|
2386
|
+
// Default pin stroke color and width (circle pins; width is in screen pixels with non-scaling stroke)
|
|
2387
|
+
pinStrokeColor: '#ffffff',
|
|
2388
|
+
pinStrokeWidth: 1.5,
|
|
2389
|
+
|
|
2390
|
+
// Default pin radius in SVG units (viewBox is 2000 × 1001)
|
|
2391
|
+
pinSize: 8,
|
|
2392
|
+
|
|
2393
|
+
// Custom pin element: function(countryID, countryValues) => SVGElement | null
|
|
2394
|
+
onGetPin: null,
|
|
2395
|
+
|
|
2396
|
+
// Image URL to use as a pin instead of the default circle (can also be set per-country via values[id].pinImage)
|
|
2397
|
+
pinImage: null,
|
|
2398
|
+
|
|
2399
|
+
// Width and height of the pin image in SVG units (viewBox is 2000 × 1001)
|
|
2400
|
+
pinImageWidth: 20,
|
|
2401
|
+
pinImageHeight: 20,
|
|
2402
|
+
|
|
2403
|
+
// Offset from computed pin position, in SVG units (added after auto center or pinX/pinY)
|
|
2404
|
+
pinOffsetX: 0,
|
|
2405
|
+
pinOffsetY: 0
|
|
2379
2406
|
};
|
|
2380
2407
|
|
|
2381
2408
|
this.options = Object.assign({}, defaultOptions, options);
|
|
@@ -3249,7 +3276,7 @@ class svgMap {
|
|
|
3249
3276
|
}
|
|
3250
3277
|
countryElement.parentNode.insertBefore(
|
|
3251
3278
|
countryElement,
|
|
3252
|
-
this.persistentTooltipGroup || null
|
|
3279
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3253
3280
|
);
|
|
3254
3281
|
if (setActive) {
|
|
3255
3282
|
countryElement.classList.add('svgMap-active');
|
|
@@ -3369,6 +3396,10 @@ class svgMap {
|
|
|
3369
3396
|
this.createPersistentTooltips(countryElements);
|
|
3370
3397
|
}
|
|
3371
3398
|
|
|
3399
|
+
if (this.options.staticPins) {
|
|
3400
|
+
this.createStaticPins(countryElements);
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3372
3403
|
let pointerStart = null;
|
|
3373
3404
|
let activeCountry = null;
|
|
3374
3405
|
|
|
@@ -3431,7 +3462,7 @@ class svgMap {
|
|
|
3431
3462
|
clearActive();
|
|
3432
3463
|
countryElement.parentNode.insertBefore(
|
|
3433
3464
|
countryElement,
|
|
3434
|
-
this.persistentTooltipGroup || null
|
|
3465
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3435
3466
|
);
|
|
3436
3467
|
countryElement.classList.add('svgMap-active');
|
|
3437
3468
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3445,7 +3476,7 @@ class svgMap {
|
|
|
3445
3476
|
clearActive();
|
|
3446
3477
|
countryElement.parentNode.insertBefore(
|
|
3447
3478
|
countryElement,
|
|
3448
|
-
this.persistentTooltipGroup || null
|
|
3479
|
+
this.persistentTooltipGroup || this.pinGroup || null
|
|
3449
3480
|
);
|
|
3450
3481
|
countryElement.classList.add('svgMap-active');
|
|
3451
3482
|
this.setTooltipContent(this.getTooltipContent(countryID));
|
|
@@ -3633,6 +3664,157 @@ class svgMap {
|
|
|
3633
3664
|
);
|
|
3634
3665
|
}
|
|
3635
3666
|
|
|
3667
|
+
// Create static pins on the map
|
|
3668
|
+
|
|
3669
|
+
createStaticPins(countryElements) {
|
|
3670
|
+
if (this.pinGroup) {
|
|
3671
|
+
this.pinGroup.remove();
|
|
3672
|
+
}
|
|
3673
|
+
|
|
3674
|
+
this.pinGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
3675
|
+
this.pinGroup.classList.add('svgMap-pin-group');
|
|
3676
|
+
this.mapImage.appendChild(this.pinGroup);
|
|
3677
|
+
|
|
3678
|
+
countryElements.forEach(
|
|
3679
|
+
function (countryElement) {
|
|
3680
|
+
var countryID = countryElement.getAttribute('data-id');
|
|
3681
|
+
if (!this.shouldShowPin(countryID)) {
|
|
3682
|
+
return;
|
|
3683
|
+
}
|
|
3684
|
+
|
|
3685
|
+
var countryValues = this.options.data.values[countryID];
|
|
3686
|
+
var cx, cy;
|
|
3687
|
+
|
|
3688
|
+
if (
|
|
3689
|
+
countryValues &&
|
|
3690
|
+
countryValues.pinX != null &&
|
|
3691
|
+
countryValues.pinY != null
|
|
3692
|
+
) {
|
|
3693
|
+
cx = countryValues.pinX;
|
|
3694
|
+
cy = countryValues.pinY;
|
|
3695
|
+
} else {
|
|
3696
|
+
// Split the path at absolute M commands and use the largest sub-path
|
|
3697
|
+
// to avoid overseas territories (islands, colonies) skewing the center.
|
|
3698
|
+
var d = countryElement.getAttribute('d');
|
|
3699
|
+
var subPaths = d.split(/(?=M)/).filter((s) => s.trim().length > 0);
|
|
3700
|
+
var largestBB = null;
|
|
3701
|
+
var largestArea = -1;
|
|
3702
|
+
|
|
3703
|
+
subPaths.forEach(
|
|
3704
|
+
function (subPath) {
|
|
3705
|
+
var tmp = document.createElementNS(
|
|
3706
|
+
'http://www.w3.org/2000/svg',
|
|
3707
|
+
'path'
|
|
3708
|
+
);
|
|
3709
|
+
tmp.setAttribute('d', subPath);
|
|
3710
|
+
this.mapImage.appendChild(tmp);
|
|
3711
|
+
var bb = tmp.getBBox();
|
|
3712
|
+
var area = bb.width * bb.height;
|
|
3713
|
+
if (area > largestArea) {
|
|
3714
|
+
largestArea = area;
|
|
3715
|
+
largestBB = bb;
|
|
3716
|
+
}
|
|
3717
|
+
this.mapImage.removeChild(tmp);
|
|
3718
|
+
}.bind(this)
|
|
3719
|
+
);
|
|
3720
|
+
|
|
3721
|
+
cx = largestBB.x + largestBB.width / 2;
|
|
3722
|
+
cy = largestBB.y + largestBB.height / 2;
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
var offsetX =
|
|
3726
|
+
countryValues && countryValues.pinOffsetX != null
|
|
3727
|
+
? countryValues.pinOffsetX
|
|
3728
|
+
: this.options.pinOffsetX;
|
|
3729
|
+
var offsetY =
|
|
3730
|
+
countryValues && countryValues.pinOffsetY != null
|
|
3731
|
+
? countryValues.pinOffsetY
|
|
3732
|
+
: this.options.pinOffsetY;
|
|
3733
|
+
cx += offsetX;
|
|
3734
|
+
cy += offsetY;
|
|
3735
|
+
|
|
3736
|
+
var color =
|
|
3737
|
+
(countryValues && countryValues.pinColor) || this.options.pinColor;
|
|
3738
|
+
var size =
|
|
3739
|
+
(countryValues && countryValues.pinSize) || this.options.pinSize;
|
|
3740
|
+
var strokeColor =
|
|
3741
|
+
(countryValues && countryValues.pinStrokeColor) ||
|
|
3742
|
+
this.options.pinStrokeColor;
|
|
3743
|
+
var strokeWidth =
|
|
3744
|
+
(countryValues && countryValues.pinStrokeWidth) ||
|
|
3745
|
+
this.options.pinStrokeWidth;
|
|
3746
|
+
|
|
3747
|
+
if (typeof this.options.onGetPin === 'function') {
|
|
3748
|
+
var custom = this.options.onGetPin(countryID, countryValues);
|
|
3749
|
+
if (custom) {
|
|
3750
|
+
custom.setAttribute(
|
|
3751
|
+
'transform',
|
|
3752
|
+
'translate(' + cx + ',' + cy + ')'
|
|
3753
|
+
);
|
|
3754
|
+
this.pinGroup.appendChild(custom);
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
var pinImage =
|
|
3760
|
+
(countryValues && countryValues.pinImage) || this.options.pinImage;
|
|
3761
|
+
|
|
3762
|
+
if (pinImage) {
|
|
3763
|
+
var pinW =
|
|
3764
|
+
(countryValues && countryValues.pinImageWidth) ||
|
|
3765
|
+
this.options.pinImageWidth;
|
|
3766
|
+
var pinH =
|
|
3767
|
+
(countryValues && countryValues.pinImageHeight) ||
|
|
3768
|
+
this.options.pinImageHeight;
|
|
3769
|
+
var img = document.createElementNS(
|
|
3770
|
+
'http://www.w3.org/2000/svg',
|
|
3771
|
+
'image'
|
|
3772
|
+
);
|
|
3773
|
+
img.setAttribute('href', pinImage);
|
|
3774
|
+
img.setAttribute('x', cx - pinW / 2);
|
|
3775
|
+
img.setAttribute('y', cy - pinH / 2);
|
|
3776
|
+
img.setAttribute('width', pinW);
|
|
3777
|
+
img.setAttribute('height', pinH);
|
|
3778
|
+
img.setAttribute('data-id', countryID);
|
|
3779
|
+
img.classList.add('svgMap-pin');
|
|
3780
|
+
this.pinGroup.appendChild(img);
|
|
3781
|
+
return;
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
var circle = document.createElementNS(
|
|
3785
|
+
'http://www.w3.org/2000/svg',
|
|
3786
|
+
'circle'
|
|
3787
|
+
);
|
|
3788
|
+
circle.setAttribute('cx', cx);
|
|
3789
|
+
circle.setAttribute('cy', cy);
|
|
3790
|
+
circle.setAttribute('r', size);
|
|
3791
|
+
circle.setAttribute('fill', color);
|
|
3792
|
+
if (strokeWidth > 0) {
|
|
3793
|
+
circle.setAttribute('stroke', strokeColor);
|
|
3794
|
+
circle.setAttribute('stroke-width', strokeWidth);
|
|
3795
|
+
circle.setAttribute('vector-effect', 'non-scaling-stroke');
|
|
3796
|
+
}
|
|
3797
|
+
circle.setAttribute('data-id', countryID);
|
|
3798
|
+
circle.classList.add('svgMap-pin');
|
|
3799
|
+
this.pinGroup.appendChild(circle);
|
|
3800
|
+
}.bind(this)
|
|
3801
|
+
);
|
|
3802
|
+
}
|
|
3803
|
+
|
|
3804
|
+
// Check if a static pin should be shown for a country
|
|
3805
|
+
|
|
3806
|
+
shouldShowPin(countryID) {
|
|
3807
|
+
var pins = this.options.staticPins;
|
|
3808
|
+
var countryValues = this.options.data.values[countryID];
|
|
3809
|
+
if (Array.isArray(pins)) {
|
|
3810
|
+
return pins.indexOf(countryID) !== -1;
|
|
3811
|
+
}
|
|
3812
|
+
if (typeof pins === 'function') {
|
|
3813
|
+
return pins(countryID, countryValues);
|
|
3814
|
+
}
|
|
3815
|
+
return false;
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3636
3818
|
// Check if a persistent tooltip should be shown on load
|
|
3637
3819
|
|
|
3638
3820
|
shouldShowTooltipOnLoad(countryID) {
|