mapkick-rb 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +35 -7
- data/lib/mapkick/helper.rb +13 -2
- data/lib/mapkick/version.rb +1 -1
- data/licenses/LICENSE-mapkick-bundle.txt +1 -1
- data/vendor/assets/javascripts/mapkick.bundle.js +244 -58
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6040b675cb3aebd2b20f20fb679d6dbd8da27282bfca83a2a3063ed8ebf9a593
|
4
|
+
data.tar.gz: 0b1de6cbd644d9d9f5eb52ec854403c47218fc2198e00a23d5d435420b2b68c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f312d4524c8705ed35a2f4d6d51d3cc1651156e93ac335c22d74ae5a143687303a3062b8877c92008836c3db50fdfa62c59238cddf2448a82448f5565e73399f
|
7
|
+
data.tar.gz: da747aaa4b2bb078f981d5de52ba4c61fa9070c46e8ce6ff2364be7ec2c188077d717b31d1e69063ecbdafc2b26d4dbfb4094165a3ceba91739e8b3bdaecb588
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -16,7 +16,7 @@ Add this line to your application’s Gemfile:
|
|
16
16
|
gem "mapkick-rb"
|
17
17
|
```
|
18
18
|
|
19
|
-
Mapkick uses [Mapbox GL JS v1](https://github.com/mapbox/mapbox-gl-js/tree/v1.13.3). To use tiles from Mapbox, [create a Mapbox account](https://account.mapbox.com/auth/signup/) to get an access token and set `ENV["MAPBOX_ACCESS_TOKEN"]` in your environment.
|
19
|
+
Mapkick uses [Mapbox GL JS v1](https://github.com/mapbox/mapbox-gl-js/tree/v1.13.3). To use tiles from Mapbox, [create a Mapbox account](https://account.mapbox.com/auth/signup/) to get an access token and set `ENV["MAPBOX_ACCESS_TOKEN"]` in your environment (or set `Mapkick.options[:access_token]` in an initializer).
|
20
20
|
|
21
21
|
Then follow the instructions for your JavaScript setup:
|
22
22
|
|
@@ -79,12 +79,18 @@ In `app/assets/javascripts/application.js`, add:
|
|
79
79
|
|
80
80
|
## Maps
|
81
81
|
|
82
|
-
|
82
|
+
Point map
|
83
83
|
|
84
84
|
```erb
|
85
85
|
<%= js_map [{latitude: 37.7829, longitude: -122.4190}] %>
|
86
86
|
```
|
87
87
|
|
88
|
+
Area map (experimental)
|
89
|
+
|
90
|
+
```erb
|
91
|
+
<%= area_map [{geometry: {type: "Polygon", coordinates: ...}}] %>
|
92
|
+
```
|
93
|
+
|
88
94
|
## Data
|
89
95
|
|
90
96
|
Data can be an array
|
@@ -99,11 +105,13 @@ Or a URL that returns JSON (same format as above)
|
|
99
105
|
<%= js_map cities_path %>
|
100
106
|
```
|
101
107
|
|
102
|
-
|
108
|
+
### Point Map
|
109
|
+
|
110
|
+
Use `latitude` or `lat` for latitude and `longitude`, `lon`, or `lng` for longitude
|
103
111
|
|
104
112
|
You can specify a label and tooltip for each data point
|
105
113
|
|
106
|
-
```
|
114
|
+
```ruby
|
107
115
|
{
|
108
116
|
latitude: ...,
|
109
117
|
longitude: ...,
|
@@ -112,6 +120,20 @@ You can specify a label and tooltip for each data point
|
|
112
120
|
}
|
113
121
|
```
|
114
122
|
|
123
|
+
### Area Map
|
124
|
+
|
125
|
+
Use `geometry` with a GeoJSON `Polygon` or `MultiPolygon`
|
126
|
+
|
127
|
+
You can specify a label and tooltip for each data point
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
{
|
131
|
+
geometry: {type: "Polygon", coordinates: ...},
|
132
|
+
label: "Hot Chicken Takeover",
|
133
|
+
tooltip: "5 stars"
|
134
|
+
}
|
135
|
+
```
|
136
|
+
|
115
137
|
## Options
|
116
138
|
|
117
139
|
Id, width, and height
|
@@ -120,16 +142,22 @@ Id, width, and height
|
|
120
142
|
<%= js_map data, id: "cities-map", width: "800px", height: "500px" %>
|
121
143
|
```
|
122
144
|
|
123
|
-
|
145
|
+
Marker color
|
124
146
|
|
125
147
|
```erb
|
126
148
|
<%= js_map data, markers: {color: "#f84d4d"} %>
|
127
149
|
```
|
128
150
|
|
129
|
-
|
151
|
+
Show tooltips on click instead of hover
|
152
|
+
|
153
|
+
```erb
|
154
|
+
<%= js_map data, tooltips: {hover: false} %>
|
155
|
+
```
|
156
|
+
|
157
|
+
Allow HTML in tooltips (must sanitize manually)
|
130
158
|
|
131
159
|
```erb
|
132
|
-
<%= js_map data, tooltips: {
|
160
|
+
<%= js_map data, tooltips: {html: true} %>
|
133
161
|
```
|
134
162
|
|
135
163
|
Map style
|
data/lib/mapkick/helper.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
module Mapkick
|
2
2
|
module Helper
|
3
|
-
# don't break out options since need to merge with default options
|
4
3
|
def js_map(data_source, **options)
|
4
|
+
mapkick_map "Map", data_source, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def area_map(data_source, **options)
|
8
|
+
mapkick_map "AreaMap", data_source, **options
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# don't break out options since need to merge with default options
|
14
|
+
def mapkick_map(type, data_source, **options)
|
5
15
|
options = Mapkick::Utils.deep_merge(Mapkick.options, options)
|
6
16
|
|
7
17
|
@mapkick_map_id ||= 0
|
@@ -67,6 +77,7 @@ module Mapkick
|
|
67
77
|
|
68
78
|
# js vars
|
69
79
|
js_vars = {
|
80
|
+
type: type,
|
70
81
|
id: element_id,
|
71
82
|
data: data_source,
|
72
83
|
options: options
|
@@ -74,7 +85,7 @@ module Mapkick
|
|
74
85
|
js_vars.each_key do |k|
|
75
86
|
js_vars[k] = Mapkick::Utils.json_escape(js_vars[k].to_json)
|
76
87
|
end
|
77
|
-
createjs = "new Mapkick
|
88
|
+
createjs = "new Mapkick[%{type}](%{id}, %{data}, %{options});" % js_vars
|
78
89
|
|
79
90
|
# don't rerun JS on preview
|
80
91
|
js = <<~JS
|
data/lib/mapkick/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/*
|
2
2
|
* This bundle includes:
|
3
3
|
*
|
4
|
-
* Mapkick.js v0.2.
|
4
|
+
* Mapkick.js v0.2.3
|
5
5
|
* https://github.com/ankane/mapkick.js
|
6
6
|
* MIT License
|
7
7
|
*
|
@@ -304,7 +304,7 @@
|
|
304
304
|
|
305
305
|
var maps = {};
|
306
306
|
|
307
|
-
var
|
307
|
+
var BaseMap = function BaseMap(element, data, options, mapType) {
|
308
308
|
var this$1$1 = this;
|
309
309
|
|
310
310
|
if (!Mapkick.library && typeof window !== "undefined") {
|
@@ -405,24 +405,28 @@
|
|
405
405
|
element.textContent = message;
|
406
406
|
}
|
407
407
|
|
408
|
+
function errorCatcher(element, data, options, callback) {
|
409
|
+
try {
|
410
|
+
callback(element, data, options);
|
411
|
+
} catch (err) {
|
412
|
+
showError(element, err.message);
|
413
|
+
throw err
|
414
|
+
}
|
415
|
+
}
|
416
|
+
|
408
417
|
function fetchData(element, data, options, callback) {
|
409
418
|
if (typeof data === "string") {
|
410
419
|
getJSON(element, data, function (newData) {
|
411
|
-
|
420
|
+
errorCatcher(element, newData, options, callback);
|
412
421
|
});
|
413
422
|
} else if (typeof data === "function") {
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
});
|
420
|
-
} catch (err) {
|
421
|
-
showError(element, "Error");
|
422
|
-
throw err
|
423
|
-
}
|
423
|
+
data(function (newData) {
|
424
|
+
errorCatcher(element, newData, options, callback);
|
425
|
+
}, function (message) {
|
426
|
+
showError(element, message);
|
427
|
+
});
|
424
428
|
} else {
|
425
|
-
|
429
|
+
errorCatcher(element, data, options, callback);
|
426
430
|
}
|
427
431
|
}
|
428
432
|
|
@@ -445,21 +449,44 @@
|
|
445
449
|
for (var i = 0; i < data.length; i++) {
|
446
450
|
var row = data[i];
|
447
451
|
var properties = Object.assign({}, row);
|
452
|
+
var geometry = (void 0);
|
453
|
+
|
454
|
+
if (mapType === "point") {
|
455
|
+
if (!properties.icon) {
|
456
|
+
properties.icon = options.defaultIcon || "mapkick";
|
457
|
+
}
|
458
|
+
properties.mapkickIconSize = properties.icon === "mapkick" ? 0.5 : 1;
|
459
|
+
properties.mapkickIconAnchor = properties.icon === "mapkick" ? "bottom" : "center";
|
460
|
+
properties.mapkickIconOffset = properties.icon === "mapkick" ? [0, 10] : [0, 0];
|
461
|
+
|
462
|
+
var coordinates = rowCoordinates(row);
|
463
|
+
|
464
|
+
if (!coordinates[1]) {
|
465
|
+
throw new Error(("missing latitude (index: " + i + ")"))
|
466
|
+
}
|
467
|
+
|
468
|
+
if (!coordinates[0]) {
|
469
|
+
throw new Error(("missing longitude (index: " + i + ")"))
|
470
|
+
}
|
471
|
+
|
472
|
+
geometry = {
|
473
|
+
type: "Point",
|
474
|
+
coordinates: coordinates
|
475
|
+
};
|
476
|
+
} else {
|
477
|
+
geometry = row.geometry;
|
478
|
+
|
479
|
+
if (!geometry) {
|
480
|
+
throw new Error(("missing geometry (index: " + i + ")"))
|
481
|
+
}
|
448
482
|
|
449
|
-
|
450
|
-
properties.icon = options.defaultIcon || "mapkick";
|
483
|
+
delete properties.geometry;
|
451
484
|
}
|
452
|
-
properties.mapkickIconSize = properties.icon === "mapkick" ? 0.5 : 1;
|
453
|
-
properties.mapkickIconAnchor = properties.icon === "mapkick" ? "bottom" : "center";
|
454
|
-
properties.mapkickIconOffset = properties.icon === "mapkick" ? [0, 10] : [0, 0];
|
455
485
|
|
456
486
|
geojson.features.push({
|
457
487
|
type: "Feature",
|
458
488
|
id: i,
|
459
|
-
geometry:
|
460
|
-
type: "Point",
|
461
|
-
coordinates: rowCoordinates(row),
|
462
|
-
},
|
489
|
+
geometry: geometry,
|
463
490
|
properties: properties
|
464
491
|
});
|
465
492
|
}
|
@@ -509,42 +536,148 @@
|
|
509
536
|
return geojson
|
510
537
|
}
|
511
538
|
|
539
|
+
function generateLabelGeoJSON(data) {
|
540
|
+
var geojson = {
|
541
|
+
type: "FeatureCollection",
|
542
|
+
features: []
|
543
|
+
};
|
544
|
+
|
545
|
+
for (var i = 0; i < data.features.length; i++) {
|
546
|
+
var feature = data.features[i];
|
547
|
+
var coordinates = (void 0);
|
548
|
+
|
549
|
+
// use center for now
|
550
|
+
var bounds = new library.LngLatBounds();
|
551
|
+
extendBounds(bounds, feature.geometry);
|
552
|
+
if (!bounds.isEmpty()) {
|
553
|
+
var center = bounds.getCenter();
|
554
|
+
coordinates = [center.lng, center.lat];
|
555
|
+
}
|
556
|
+
|
557
|
+
if (coordinates) {
|
558
|
+
geojson.features.push({
|
559
|
+
type: "Feature",
|
560
|
+
id: i,
|
561
|
+
geometry: {
|
562
|
+
type: "Point",
|
563
|
+
coordinates: coordinates
|
564
|
+
},
|
565
|
+
properties: feature.properties
|
566
|
+
});
|
567
|
+
}
|
568
|
+
}
|
569
|
+
|
570
|
+
return geojson
|
571
|
+
}
|
572
|
+
|
573
|
+
function layerBeforeFill(map) {
|
574
|
+
// place below labels
|
575
|
+
var layers = map.getStyle().layers;
|
576
|
+
var beforeId;
|
577
|
+
for (var i = layers.length - 1; i >= 0; i--) {
|
578
|
+
var layer = layers[i];
|
579
|
+
// TODO improve
|
580
|
+
if (!(layer.metadata && layer.metadata["mapbox:featureComponent"] === "place-labels")) {
|
581
|
+
break
|
582
|
+
}
|
583
|
+
beforeId = layer.id;
|
584
|
+
}
|
585
|
+
return beforeId
|
586
|
+
}
|
587
|
+
|
512
588
|
function addLayer(name, geojson) {
|
589
|
+
var centersById = {};
|
590
|
+
|
513
591
|
map.addSource(name, {
|
514
592
|
type: "geojson",
|
515
593
|
data: geojson
|
516
594
|
});
|
517
595
|
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
596
|
+
if (mapType === "point") {
|
597
|
+
// use a symbol layer for markers for performance
|
598
|
+
// https://docs.mapbox.com/help/getting-started/add-markers/#approach-1-adding-markers-inside-a-map
|
599
|
+
// use separate layers to prevent labels from overlapping markers
|
600
|
+
map.addLayer({
|
601
|
+
id: (name + "-text"),
|
602
|
+
source: name,
|
603
|
+
type: "symbol",
|
604
|
+
layout: {
|
605
|
+
"text-field": "{label}",
|
606
|
+
"text-size": 11,
|
607
|
+
"text-anchor": "top",
|
608
|
+
"text-offset": [0, 1]
|
609
|
+
},
|
610
|
+
paint: {
|
611
|
+
"text-halo-color": "rgba(255, 255, 255, 1)",
|
612
|
+
"text-halo-width": 1
|
613
|
+
}
|
614
|
+
});
|
615
|
+
map.addLayer({
|
616
|
+
id: name,
|
617
|
+
source: name,
|
618
|
+
type: "symbol",
|
619
|
+
layout: {
|
620
|
+
"icon-image": "{icon}-15",
|
621
|
+
"icon-allow-overlap": true,
|
622
|
+
"icon-size": {type: "identity", property: "mapkickIconSize"},
|
623
|
+
"icon-anchor": {type: "identity", property: "mapkickIconAnchor"},
|
624
|
+
"icon-offset": {type: "identity", property: "mapkickIconOffset"}
|
625
|
+
}
|
626
|
+
});
|
627
|
+
} else {
|
628
|
+
var fillColor = markerOptions.color || "#0090ff";
|
629
|
+
|
630
|
+
var beforeId = layerBeforeFill(map);
|
631
|
+
|
632
|
+
var outlineId = name + "-outline";
|
633
|
+
map.addLayer({
|
634
|
+
id: outlineId,
|
635
|
+
source: name,
|
636
|
+
type: "line",
|
637
|
+
paint: {
|
638
|
+
"line-color": fillColor,
|
639
|
+
"line-opacity": 0.7,
|
640
|
+
"line-width": 1
|
641
|
+
}
|
642
|
+
}, beforeId);
|
643
|
+
|
644
|
+
map.addLayer({
|
645
|
+
id: name,
|
646
|
+
source: name,
|
647
|
+
type: "fill",
|
648
|
+
paint: {
|
649
|
+
"fill-color": fillColor,
|
650
|
+
"fill-opacity": 0.3
|
651
|
+
}
|
652
|
+
}, outlineId);
|
653
|
+
|
654
|
+
var labelName = name + "-text";
|
655
|
+
var labelData = generateLabelGeoJSON(geojson);
|
656
|
+
|
657
|
+
for (var i = 0; i < labelData.features.length; i++) {
|
658
|
+
var feature = labelData.features[i];
|
659
|
+
centersById[feature.id] = feature.geometry.coordinates;
|
546
660
|
}
|
547
|
-
|
661
|
+
|
662
|
+
map.addSource(labelName, {
|
663
|
+
type: "geojson",
|
664
|
+
data: labelData
|
665
|
+
});
|
666
|
+
|
667
|
+
map.addLayer({
|
668
|
+
id: (name + "-text"),
|
669
|
+
source: labelName,
|
670
|
+
type: "symbol",
|
671
|
+
layout: {
|
672
|
+
"text-field": "{label}",
|
673
|
+
"text-size": 11
|
674
|
+
},
|
675
|
+
paint: {
|
676
|
+
"text-halo-color": "rgba(255, 255, 255, 1)",
|
677
|
+
"text-halo-width": 1
|
678
|
+
}
|
679
|
+
});
|
680
|
+
}
|
548
681
|
|
549
682
|
var hover = !("hover" in tooltipOptions) || tooltipOptions.hover;
|
550
683
|
|
@@ -597,8 +730,15 @@
|
|
597
730
|
popup.options.offset = 14;
|
598
731
|
}
|
599
732
|
|
733
|
+
var coordinates;
|
734
|
+
if (mapType === "point") {
|
735
|
+
coordinates = feature.geometry.coordinates;
|
736
|
+
} else {
|
737
|
+
coordinates = centersById[feature.id];
|
738
|
+
}
|
739
|
+
|
600
740
|
// add the tooltip
|
601
|
-
popup.setLngLat(
|
741
|
+
popup.setLngLat(coordinates);
|
602
742
|
if (tooltipOptions.html) {
|
603
743
|
popup.setHTML(tooltip);
|
604
744
|
} else {
|
@@ -612,7 +752,9 @@
|
|
612
752
|
popup._container.style.width = popup._container.offsetWidth + 1 + "px";
|
613
753
|
}
|
614
754
|
|
615
|
-
|
755
|
+
if (mapType !== "area") {
|
756
|
+
panMap(map, popup);
|
757
|
+
}
|
616
758
|
};
|
617
759
|
|
618
760
|
var getLatitude = function (feature) {
|
@@ -673,12 +815,31 @@
|
|
673
815
|
});
|
674
816
|
}
|
675
817
|
|
818
|
+
function extendBounds(bounds, geometry) {
|
819
|
+
if (geometry.type === "Point") {
|
820
|
+
bounds.extend(geometry.coordinates);
|
821
|
+
} else if (geometry.type === "Polygon") {
|
822
|
+
var coordinates = geometry.coordinates[0];
|
823
|
+
for (var j = 0; j < coordinates.length; j++) {
|
824
|
+
bounds.extend(coordinates[j]);
|
825
|
+
}
|
826
|
+
} else if (geometry.type === "MultiPolygon") {
|
827
|
+
var coordinates$1 = geometry.coordinates;
|
828
|
+
for (var j$1 = 0; j$1 < coordinates$1.length; j$1++) {
|
829
|
+
var polygon = coordinates$1[j$1][0];
|
830
|
+
for (var k = 0; k < polygon.length; k++) {
|
831
|
+
bounds.extend(polygon[k]);
|
832
|
+
}
|
833
|
+
}
|
834
|
+
}
|
835
|
+
}
|
836
|
+
|
676
837
|
var generateMap = function (element, data, options) {
|
677
838
|
var geojson = generateGeoJSON(data, options);
|
678
839
|
options = options || {};
|
679
840
|
|
680
841
|
for (var i = 0; i < geojson.features.length; i++) {
|
681
|
-
bounds
|
842
|
+
extendBounds(bounds, geojson.features[i].geometry);
|
682
843
|
}
|
683
844
|
|
684
845
|
// remove any child elements
|
@@ -795,11 +956,11 @@
|
|
795
956
|
}
|
796
957
|
};
|
797
958
|
|
798
|
-
|
959
|
+
BaseMap.prototype.getMapObject = function getMapObject () {
|
799
960
|
return this.map
|
800
961
|
};
|
801
962
|
|
802
|
-
|
963
|
+
BaseMap.prototype.destroy = function destroy () {
|
803
964
|
this.stopRefresh();
|
804
965
|
|
805
966
|
if (this.map) {
|
@@ -808,15 +969,40 @@
|
|
808
969
|
}
|
809
970
|
};
|
810
971
|
|
811
|
-
|
972
|
+
BaseMap.prototype.stopRefresh = function stopRefresh () {
|
812
973
|
if (this.intervalId) {
|
813
974
|
clearInterval(this.intervalId);
|
814
975
|
this.intervalId = null;
|
815
976
|
}
|
816
977
|
};
|
817
978
|
|
979
|
+
var Map = /*@__PURE__*/(function (BaseMap) {
|
980
|
+
function Map(element, data, options) {
|
981
|
+
BaseMap.call(this, element, data, options, "point");
|
982
|
+
}
|
983
|
+
|
984
|
+
if ( BaseMap ) Map.__proto__ = BaseMap;
|
985
|
+
Map.prototype = Object.create( BaseMap && BaseMap.prototype );
|
986
|
+
Map.prototype.constructor = Map;
|
987
|
+
|
988
|
+
return Map;
|
989
|
+
}(BaseMap));
|
990
|
+
|
991
|
+
var AreaMap = /*@__PURE__*/(function (BaseMap) {
|
992
|
+
function AreaMap(element, data, options) {
|
993
|
+
BaseMap.call(this, element, data, options, "area");
|
994
|
+
}
|
995
|
+
|
996
|
+
if ( BaseMap ) AreaMap.__proto__ = BaseMap;
|
997
|
+
AreaMap.prototype = Object.create( BaseMap && BaseMap.prototype );
|
998
|
+
AreaMap.prototype.constructor = AreaMap;
|
999
|
+
|
1000
|
+
return AreaMap;
|
1001
|
+
}(BaseMap));
|
1002
|
+
|
818
1003
|
var Mapkick = {
|
819
1004
|
Map: Map,
|
1005
|
+
AreaMap: AreaMap,
|
820
1006
|
maps: maps,
|
821
1007
|
options: {},
|
822
1008
|
library: null
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mapkick-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: andrew@ankane.org
|
@@ -47,7 +47,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '0'
|
49
49
|
requirements: []
|
50
|
-
rubygems_version: 3.4.
|
50
|
+
rubygems_version: 3.4.6
|
51
51
|
signing_key:
|
52
52
|
specification_version: 4
|
53
53
|
summary: Create beautiful JavaScript maps with one line of Ruby
|