mapshaper 0.5.92 → 0.5.95
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/CHANGELOG.md +1319 -0
- package/mapshaper.js +114 -19
- package/package.json +1 -1
- package/www/manifest.js +7 -1
- package/www/mapshaper-gui.js +1660 -168
- package/www/mapshaper.js +114 -19
- package/www/nacis/Makefile +0 -22
- package/www/nacis/Makefile.txt +0 -22
- package/www/nacis/images/close.png +0 -0
- package/www/nacis/images/eye.png +0 -0
- package/www/nacis/images/eye2.png +0 -0
- package/www/nacis/index.html +0 -262
- package/www/nacis/manifest.js +0 -27
- package/www/nacis/map.svg +0 -12308
package/www/mapshaper-gui.js
CHANGED
|
@@ -1,16 +1,114 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
+
var utils = /*#__PURE__*/Object.freeze({
|
|
4
|
+
__proto__: null,
|
|
5
|
+
get default () { return utils; },
|
|
6
|
+
get getUniqueName () { return getUniqueName; },
|
|
7
|
+
get isFunction () { return isFunction; },
|
|
8
|
+
get isObject () { return isObject; },
|
|
9
|
+
get clamp () { return clamp; },
|
|
10
|
+
get isArray () { return isArray; },
|
|
11
|
+
get isNumber () { return isNumber; },
|
|
12
|
+
get isValidNumber () { return isValidNumber; },
|
|
13
|
+
get isFiniteNumber () { return isFiniteNumber; },
|
|
14
|
+
get isNonNegNumber () { return isNonNegNumber; },
|
|
15
|
+
get isInteger () { return isInteger; },
|
|
16
|
+
get isEven () { return isEven; },
|
|
17
|
+
get isOdd () { return isOdd; },
|
|
18
|
+
get isString () { return isString; },
|
|
19
|
+
get isDate () { return isDate; },
|
|
20
|
+
get isBoolean () { return isBoolean; },
|
|
21
|
+
get formatDateISO () { return formatDateISO; },
|
|
22
|
+
get toArray () { return toArray; },
|
|
23
|
+
get isArrayLike () { return isArrayLike; },
|
|
24
|
+
get addslashes () { return addslashes; },
|
|
25
|
+
get regexEscape () { return regexEscape; },
|
|
26
|
+
get htmlEscape () { return htmlEscape; },
|
|
27
|
+
get defaults () { return defaults; },
|
|
28
|
+
get extend () { return extend; },
|
|
29
|
+
get inherit () { return inherit; },
|
|
30
|
+
get reduceAsync () { return reduceAsync; },
|
|
31
|
+
get merge () { return merge; },
|
|
32
|
+
get difference () { return difference; },
|
|
33
|
+
get intersection () { return intersection; },
|
|
34
|
+
get indexOf () { return indexOf; },
|
|
35
|
+
get contains () { return contains; },
|
|
36
|
+
get some () { return some; },
|
|
37
|
+
get every () { return every; },
|
|
38
|
+
get find () { return find; },
|
|
39
|
+
get range () { return range; },
|
|
40
|
+
get repeat () { return repeat; },
|
|
41
|
+
get sum () { return sum; },
|
|
42
|
+
get getArrayBounds () { return getArrayBounds; },
|
|
43
|
+
get uniq () { return uniq; },
|
|
44
|
+
get pluck () { return pluck; },
|
|
45
|
+
get countValues () { return countValues; },
|
|
46
|
+
get indexOn () { return indexOn; },
|
|
47
|
+
get groupBy () { return groupBy; },
|
|
48
|
+
get arrayToIndex () { return arrayToIndex; },
|
|
49
|
+
get forEach () { return forEach; },
|
|
50
|
+
get forEachProperty () { return forEachProperty; },
|
|
51
|
+
get initializeArray () { return initializeArray; },
|
|
52
|
+
get replaceArray () { return replaceArray; },
|
|
53
|
+
get repeatString () { return repeatString; },
|
|
54
|
+
get splitLines () { return splitLines; },
|
|
55
|
+
get pluralSuffix () { return pluralSuffix; },
|
|
56
|
+
get endsWith () { return endsWith; },
|
|
57
|
+
get lpad () { return lpad; },
|
|
58
|
+
get rpad () { return rpad; },
|
|
59
|
+
get trim () { return trim; },
|
|
60
|
+
get ltrim () { return ltrim; },
|
|
61
|
+
get rtrim () { return rtrim; },
|
|
62
|
+
get addThousandsSep () { return addThousandsSep; },
|
|
63
|
+
get numToStr () { return numToStr; },
|
|
64
|
+
get formatNumber () { return formatNumber; },
|
|
65
|
+
get formatIntlNumber () { return formatIntlNumber; },
|
|
66
|
+
get formatNumberForDisplay () { return formatNumberForDisplay; },
|
|
67
|
+
get shuffle () { return shuffle; },
|
|
68
|
+
get sortOn () { return sortOn; },
|
|
69
|
+
get genericSort () { return genericSort; },
|
|
70
|
+
get getSortedIds () { return getSortedIds; },
|
|
71
|
+
get sortArrayIndex () { return sortArrayIndex; },
|
|
72
|
+
get reorderArray () { return reorderArray; },
|
|
73
|
+
get getKeyComparator () { return getKeyComparator; },
|
|
74
|
+
get getGenericComparator () { return getGenericComparator; },
|
|
75
|
+
get quicksort () { return quicksort; },
|
|
76
|
+
get quicksortPartition () { return quicksortPartition; },
|
|
77
|
+
get findRankByValue () { return findRankByValue; },
|
|
78
|
+
get findValueByPct () { return findValueByPct; },
|
|
79
|
+
get findValueByRank () { return findValueByRank; },
|
|
80
|
+
get findMedian () { return findMedian; },
|
|
81
|
+
get mean () { return mean; },
|
|
82
|
+
get format () { return format; },
|
|
83
|
+
get formatter () { return formatter; },
|
|
84
|
+
get wildcardToRegExp () { return wildcardToRegExp; },
|
|
85
|
+
get createBuffer () { return createBuffer; },
|
|
86
|
+
get expandoBuffer () { return expandoBuffer; },
|
|
87
|
+
get copyElements () { return copyElements; },
|
|
88
|
+
get extendBuffer () { return extendBuffer; },
|
|
89
|
+
get mergeNames () { return mergeNames; },
|
|
90
|
+
get findStringPrefix () { return findStringPrefix; },
|
|
91
|
+
get parsePercent () { return parsePercent; },
|
|
92
|
+
get formatVersionedName () { return formatVersionedName; },
|
|
93
|
+
get uniqifyNames () { return uniqifyNames; },
|
|
94
|
+
get parseString () { return parseString; },
|
|
95
|
+
get parseNumber () { return parseNumber; },
|
|
96
|
+
get parseIntlNumber () { return parseIntlNumber; },
|
|
97
|
+
get cleanNumericString () { return cleanNumericString; },
|
|
98
|
+
get trimQuotes () { return trimQuotes; }
|
|
99
|
+
});
|
|
100
|
+
|
|
3
101
|
var api = window.mapshaper; // assuming mapshaper is in global scope
|
|
4
102
|
var mapshaper = api,
|
|
5
|
-
utils = api.utils,
|
|
103
|
+
utils$1 = api.utils,
|
|
6
104
|
cli = api.cli,
|
|
7
105
|
geom = api.geom,
|
|
8
106
|
internal = api.internal,
|
|
9
107
|
Bounds = internal.Bounds,
|
|
10
|
-
UserError = internal.UserError,
|
|
11
|
-
message = internal.message, // stop, error and message are overridden in gui-proxy.js
|
|
12
|
-
stop = internal.stop,
|
|
13
|
-
error = internal.error;
|
|
108
|
+
UserError$1 = internal.UserError,
|
|
109
|
+
message$1 = internal.message, // stop, error and message are overridden in gui-proxy.js
|
|
110
|
+
stop$1 = internal.stop,
|
|
111
|
+
error$1 = internal.error;
|
|
14
112
|
|
|
15
113
|
api.enableLogging();
|
|
16
114
|
|
|
@@ -46,7 +144,7 @@
|
|
|
46
144
|
|
|
47
145
|
html = '<table>';
|
|
48
146
|
if (catalog.title) {
|
|
49
|
-
html += utils.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
|
|
147
|
+
html += utils$1.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
|
|
50
148
|
}
|
|
51
149
|
while (row < rows) {
|
|
52
150
|
html += renderRow(items.slice(row * cols, row * cols + cols));
|
|
@@ -111,7 +209,7 @@
|
|
|
111
209
|
|
|
112
210
|
function renderCell(item, i) {
|
|
113
211
|
var template = '<td data-id="%d"><h4 class="title">%s</h4><div class="subtitle">%s</div></td>';
|
|
114
|
-
return utils.format(template, i, item.title, item.subtitle || '');
|
|
212
|
+
return utils$1.format(template, i, item.title, item.subtitle || '');
|
|
115
213
|
}
|
|
116
214
|
|
|
117
215
|
}
|
|
@@ -228,7 +326,7 @@
|
|
|
228
326
|
}
|
|
229
327
|
parsed = internal.parseCommands(str);
|
|
230
328
|
if (!parsed.length || parsed[0].name != cmd) {
|
|
231
|
-
stop("Unable to parse command line options");
|
|
329
|
+
stop$1("Unable to parse command line options");
|
|
232
330
|
}
|
|
233
331
|
return parsed[0].options;
|
|
234
332
|
};
|
|
@@ -321,7 +419,7 @@
|
|
|
321
419
|
evt = new EventData(this.type);
|
|
322
420
|
evt.target = this.target;
|
|
323
421
|
} else if (evt.target != this.target || evt.type != this.type) {
|
|
324
|
-
error("[Handler] event target/type have changed.");
|
|
422
|
+
error$1("[Handler] event target/type have changed.");
|
|
325
423
|
}
|
|
326
424
|
this.callback.call(this.listener, evt);
|
|
327
425
|
};
|
|
@@ -330,7 +428,7 @@
|
|
|
330
428
|
this.type = type;
|
|
331
429
|
this.target = target;
|
|
332
430
|
if (data) {
|
|
333
|
-
utils.defaults(this, data);
|
|
431
|
+
utils$1.defaults(this, data);
|
|
334
432
|
this.data = data;
|
|
335
433
|
}
|
|
336
434
|
}
|
|
@@ -560,12 +658,12 @@
|
|
|
560
658
|
try {
|
|
561
659
|
els = root.querySelectorAll(selector);
|
|
562
660
|
} catch (e) {
|
|
563
|
-
error("Invalid selector:", selector);
|
|
661
|
+
error$1("Invalid selector:", selector);
|
|
564
662
|
}
|
|
565
663
|
} else {
|
|
566
|
-
error("This browser doesn't support CSS query selectors");
|
|
664
|
+
error$1("This browser doesn't support CSS query selectors");
|
|
567
665
|
}
|
|
568
|
-
return utils.toArray(els);
|
|
666
|
+
return utils$1.toArray(els);
|
|
569
667
|
};
|
|
570
668
|
|
|
571
669
|
// Converts dash-separated names (e.g. background-color) to camelCase (e.g. backgroundColor)
|
|
@@ -602,7 +700,7 @@
|
|
|
602
700
|
};
|
|
603
701
|
|
|
604
702
|
function El(ref) {
|
|
605
|
-
if (!ref) error("Element() needs a reference");
|
|
703
|
+
if (!ref) error$1("Element() needs a reference");
|
|
606
704
|
if (ref instanceof El) {
|
|
607
705
|
return ref;
|
|
608
706
|
}
|
|
@@ -611,7 +709,7 @@
|
|
|
611
709
|
}
|
|
612
710
|
|
|
613
711
|
var node;
|
|
614
|
-
if (utils.isString(ref)) {
|
|
712
|
+
if (utils$1.isString(ref)) {
|
|
615
713
|
if (ref[0] == '<') {
|
|
616
714
|
var parent = El('div').html(ref).node();
|
|
617
715
|
node = parent.childNodes.length == 1 ? parent.childNodes[0] : parent;
|
|
@@ -623,13 +721,13 @@
|
|
|
623
721
|
} else if (ref.tagName) {
|
|
624
722
|
node = ref;
|
|
625
723
|
}
|
|
626
|
-
if (!node) error("Unmatched element selector:", ref);
|
|
724
|
+
if (!node) error$1("Unmatched element selector:", ref);
|
|
627
725
|
this.el = node;
|
|
628
726
|
}
|
|
629
727
|
|
|
630
|
-
utils.inherit(El, EventDispatcher);
|
|
728
|
+
utils$1.inherit(El, EventDispatcher);
|
|
631
729
|
|
|
632
|
-
utils.extend(El.prototype, {
|
|
730
|
+
utils$1.extend(El.prototype, {
|
|
633
731
|
|
|
634
732
|
clone: function() {
|
|
635
733
|
var el = this.el.cloneNode(true);
|
|
@@ -638,7 +736,7 @@
|
|
|
638
736
|
// can ...
|
|
639
737
|
el = El('div').addClass(el.className).html(el.innerHTML).node();
|
|
640
738
|
}
|
|
641
|
-
el.id = utils.getUniqueName();
|
|
739
|
+
el.id = utils$1.getUniqueName();
|
|
642
740
|
this.el = el;
|
|
643
741
|
return this;
|
|
644
742
|
},
|
|
@@ -668,11 +766,11 @@
|
|
|
668
766
|
if (val != null) {
|
|
669
767
|
El.setStyle(this.el, css, val);
|
|
670
768
|
}
|
|
671
|
-
else if (utils.isString(css)) {
|
|
769
|
+
else if (utils$1.isString(css)) {
|
|
672
770
|
addCSS(this.el, css);
|
|
673
771
|
}
|
|
674
|
-
else if (utils.isObject(css)) {
|
|
675
|
-
utils.forEachProperty(css, function(val, key) {
|
|
772
|
+
else if (utils$1.isObject(css)) {
|
|
773
|
+
utils$1.forEachProperty(css, function(val, key) {
|
|
676
774
|
El.setStyle(this.el, key, val);
|
|
677
775
|
}, this);
|
|
678
776
|
}
|
|
@@ -680,7 +778,7 @@
|
|
|
680
778
|
},
|
|
681
779
|
|
|
682
780
|
attr: function(obj, value) {
|
|
683
|
-
if (utils.isString(obj)) {
|
|
781
|
+
if (utils$1.isString(obj)) {
|
|
684
782
|
if (arguments.length == 1) {
|
|
685
783
|
return this.el.getAttribute(obj);
|
|
686
784
|
}
|
|
@@ -764,7 +862,7 @@
|
|
|
764
862
|
},
|
|
765
863
|
|
|
766
864
|
text: function(str) {
|
|
767
|
-
this.html(utils.htmlEscape(str));
|
|
865
|
+
this.html(utils$1.htmlEscape(str));
|
|
768
866
|
return this;
|
|
769
867
|
},
|
|
770
868
|
|
|
@@ -854,7 +952,7 @@
|
|
|
854
952
|
El.prototype.__on = El.prototype.on;
|
|
855
953
|
El.prototype.on = function(type, func, ctx) {
|
|
856
954
|
if (ctx) {
|
|
857
|
-
error("[El#on()] Third argument no longer supported.");
|
|
955
|
+
error$1("[El#on()] Third argument no longer supported.");
|
|
858
956
|
}
|
|
859
957
|
if (this.constructor == El) {
|
|
860
958
|
this.el.addEventListener(type, func);
|
|
@@ -910,7 +1008,7 @@
|
|
|
910
1008
|
}
|
|
911
1009
|
|
|
912
1010
|
this.value = function(str) {
|
|
913
|
-
if (utils.isString(str)) {
|
|
1011
|
+
if (utils$1.isString(str)) {
|
|
914
1012
|
el.node().textContent = str;
|
|
915
1013
|
} else {
|
|
916
1014
|
return el.node().textContent;
|
|
@@ -918,7 +1016,7 @@
|
|
|
918
1016
|
};
|
|
919
1017
|
}
|
|
920
1018
|
|
|
921
|
-
utils.inherit(ClickText2, EventDispatcher);
|
|
1019
|
+
utils$1.inherit(ClickText2, EventDispatcher);
|
|
922
1020
|
|
|
923
1021
|
// @ref reference to a text input element
|
|
924
1022
|
function ClickText(ref) {
|
|
@@ -989,9 +1087,9 @@
|
|
|
989
1087
|
// return _parser ? _parser(valStr) : parseFloat(valStr);
|
|
990
1088
|
return _value;
|
|
991
1089
|
}
|
|
992
|
-
var val = utils.clamp(arg, _min, _max);
|
|
1090
|
+
var val = utils$1.clamp(arg, _min, _max);
|
|
993
1091
|
if (!_validator(val)) {
|
|
994
|
-
error("ClickText#value() invalid value:", arg);
|
|
1092
|
+
error$1("ClickText#value() invalid value:", arg);
|
|
995
1093
|
} else {
|
|
996
1094
|
_value = val;
|
|
997
1095
|
}
|
|
@@ -1000,14 +1098,14 @@
|
|
|
1000
1098
|
};
|
|
1001
1099
|
}
|
|
1002
1100
|
|
|
1003
|
-
utils.inherit(ClickText, EventDispatcher);
|
|
1101
|
+
utils$1.inherit(ClickText, EventDispatcher);
|
|
1004
1102
|
|
|
1005
1103
|
|
|
1006
1104
|
function Checkbox(ref) {
|
|
1007
1105
|
var _el = El(ref);
|
|
1008
1106
|
}
|
|
1009
1107
|
|
|
1010
|
-
utils.inherit(Checkbox, EventDispatcher);
|
|
1108
|
+
utils$1.inherit(Checkbox, EventDispatcher);
|
|
1011
1109
|
|
|
1012
1110
|
function SimpleButton(ref) {
|
|
1013
1111
|
var _el = El(ref),
|
|
@@ -1036,7 +1134,7 @@
|
|
|
1036
1134
|
}
|
|
1037
1135
|
}
|
|
1038
1136
|
|
|
1039
|
-
utils.inherit(SimpleButton, EventDispatcher);
|
|
1137
|
+
utils$1.inherit(SimpleButton, EventDispatcher);
|
|
1040
1138
|
|
|
1041
1139
|
// @cb function(<FileList>)
|
|
1042
1140
|
function DropControl(gui, el, cb) {
|
|
@@ -1316,7 +1414,7 @@
|
|
|
1316
1414
|
}
|
|
1317
1415
|
|
|
1318
1416
|
function filesMayContainPaths(files) {
|
|
1319
|
-
return utils.some(files, function(f) {
|
|
1417
|
+
return utils$1.some(files, function(f) {
|
|
1320
1418
|
var type = internal.guessInputFileType(f.name);
|
|
1321
1419
|
return type == 'shp' || type == 'json' || internal.isZipFile(f.name);
|
|
1322
1420
|
});
|
|
@@ -1372,7 +1470,7 @@
|
|
|
1372
1470
|
}
|
|
1373
1471
|
|
|
1374
1472
|
function handleImportError(e, fileName) {
|
|
1375
|
-
var msg = utils.isString(e) ? e : e.message;
|
|
1473
|
+
var msg = utils$1.isString(e) ? e : e.message;
|
|
1376
1474
|
if (fileName) {
|
|
1377
1475
|
msg = "Error importing <i>" + fileName + "</i><br>" + msg;
|
|
1378
1476
|
}
|
|
@@ -1402,7 +1500,7 @@
|
|
|
1402
1500
|
|
|
1403
1501
|
function downloadFiles(paths) {
|
|
1404
1502
|
var items = prepFilesForDownload(paths);
|
|
1405
|
-
utils.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1503
|
+
utils$1.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1406
1504
|
if (err) {
|
|
1407
1505
|
gui.alert(err);
|
|
1408
1506
|
} else if (!files.length) {
|
|
@@ -1568,7 +1666,7 @@
|
|
|
1568
1666
|
var defaults = {
|
|
1569
1667
|
space: 7
|
|
1570
1668
|
};
|
|
1571
|
-
opts = utils.extend(defaults, opts);
|
|
1669
|
+
opts = utils$1.extend(defaults, opts);
|
|
1572
1670
|
|
|
1573
1671
|
var _pct = 0;
|
|
1574
1672
|
var _track,
|
|
@@ -1621,7 +1719,7 @@
|
|
|
1621
1719
|
};
|
|
1622
1720
|
|
|
1623
1721
|
function setHandlePos(x, fire) {
|
|
1624
|
-
x = utils.clamp(x, 0, size());
|
|
1722
|
+
x = utils$1.clamp(x, 0, size());
|
|
1625
1723
|
var pct = x / size();
|
|
1626
1724
|
if (pct != _pct) {
|
|
1627
1725
|
_pct = pct;
|
|
@@ -1636,7 +1734,7 @@
|
|
|
1636
1734
|
}
|
|
1637
1735
|
}
|
|
1638
1736
|
|
|
1639
|
-
utils.inherit(Slider, EventDispatcher);
|
|
1737
|
+
utils$1.inherit(Slider, EventDispatcher);
|
|
1640
1738
|
|
|
1641
1739
|
/*
|
|
1642
1740
|
How changes in the simplify control should affect other components
|
|
@@ -1704,7 +1802,7 @@
|
|
|
1704
1802
|
slider.on('change', function(e) {
|
|
1705
1803
|
var pct = fromSliderPct(e.pct);
|
|
1706
1804
|
text.value(pct);
|
|
1707
|
-
pct = utils.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1805
|
+
pct = utils$1.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1708
1806
|
onChange(pct);
|
|
1709
1807
|
});
|
|
1710
1808
|
slider.on('start', function(e) {
|
|
@@ -1725,7 +1823,7 @@
|
|
|
1725
1823
|
else if (pct < 0.01) decimals = 3;
|
|
1726
1824
|
else if (pct < 1) decimals = 2;
|
|
1727
1825
|
else if (pct < 100) decimals = 1;
|
|
1728
|
-
return utils.formatNumberForDisplay(pct, decimals) + "%";
|
|
1826
|
+
return utils$1.formatNumberForDisplay(pct, decimals) + "%";
|
|
1729
1827
|
});
|
|
1730
1828
|
|
|
1731
1829
|
text.parser(function(s) {
|
|
@@ -1977,7 +2075,7 @@
|
|
|
1977
2075
|
|
|
1978
2076
|
// Replace error function in mapshaper lib
|
|
1979
2077
|
var error = function() {
|
|
1980
|
-
stop.apply(null, utils.toArray(arguments));
|
|
2078
|
+
stop.apply(null, utils$1.toArray(arguments));
|
|
1981
2079
|
};
|
|
1982
2080
|
|
|
1983
2081
|
var message = function() {
|
|
@@ -1991,11 +2089,11 @@
|
|
|
1991
2089
|
// replace CLI version of writeFiles()
|
|
1992
2090
|
internal.replaceWriteFiles(function(files, opts, done) {
|
|
1993
2091
|
var filename;
|
|
1994
|
-
if (!utils.isArray(files) || files.length === 0) {
|
|
2092
|
+
if (!utils$1.isArray(files) || files.length === 0) {
|
|
1995
2093
|
done("Nothing to export");
|
|
1996
2094
|
} else if (GUI.canSaveToServer() && !opts.save_to_download_folder) {
|
|
1997
|
-
var paths = internal.getOutputPaths(utils.pluck(files, 'filename'), opts);
|
|
1998
|
-
var data = utils.pluck(files, 'content');
|
|
2095
|
+
var paths = internal.getOutputPaths(utils$1.pluck(files, 'filename'), opts);
|
|
2096
|
+
var data = utils$1.pluck(files, 'content');
|
|
1999
2097
|
saveFilesToServer(paths, data, function(err) {
|
|
2000
2098
|
var msg;
|
|
2001
2099
|
if (err) {
|
|
@@ -2014,7 +2112,7 @@
|
|
|
2014
2112
|
} else if (files.length == 1) {
|
|
2015
2113
|
saveBlobToDownloadFolder(files[0].filename, new Blob([files[0].content]), done);
|
|
2016
2114
|
} else {
|
|
2017
|
-
filename = internal.getCommonFileBase(utils.pluck(files, 'filename')) || "output";
|
|
2115
|
+
filename = internal.getCommonFileBase(utils$1.pluck(files, 'filename')) || "output";
|
|
2018
2116
|
saveZipFile(filename + ".zip", files, done);
|
|
2019
2117
|
}
|
|
2020
2118
|
});
|
|
@@ -2036,10 +2134,10 @@
|
|
|
2036
2134
|
// try to match import filename of this dataset
|
|
2037
2135
|
if (d.info.input_files[0] == src) return d;
|
|
2038
2136
|
// try to match name of a layer in this dataset
|
|
2039
|
-
lyr = utils.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2137
|
+
lyr = utils$1.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2040
2138
|
return lyr ? internal.isolateLayer(lyr, d) : null;
|
|
2041
2139
|
}, null);
|
|
2042
|
-
if (!retn) stop("Missing data layer [" + src + "]");
|
|
2140
|
+
if (!retn) stop$1("Missing data layer [" + src + "]");
|
|
2043
2141
|
return retn;
|
|
2044
2142
|
}
|
|
2045
2143
|
|
|
@@ -2048,7 +2146,7 @@
|
|
|
2048
2146
|
// Return a copy with layers duplicated, so changes won't affect original layers
|
|
2049
2147
|
// This makes an (unsafe) assumption that the dataset arcs won't be changed...
|
|
2050
2148
|
// need to rethink this.
|
|
2051
|
-
return utils.defaults({
|
|
2149
|
+
return utils$1.defaults({
|
|
2052
2150
|
layers: dataset.layers.map(internal.copyLayer)
|
|
2053
2151
|
}, dataset);
|
|
2054
2152
|
});
|
|
@@ -2120,7 +2218,7 @@
|
|
|
2120
2218
|
}
|
|
2121
2219
|
|
|
2122
2220
|
function projectPointsForDisplay(lyr, src, dest) {
|
|
2123
|
-
var copy = utils.extend({}, lyr);
|
|
2221
|
+
var copy = utils$1.extend({}, lyr);
|
|
2124
2222
|
var proj = internal.getProjTransform2(src, dest);
|
|
2125
2223
|
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
2126
2224
|
internal.projectPointLayer(copy, proj);
|
|
@@ -2525,7 +2623,7 @@
|
|
|
2525
2623
|
} else if (cmd == 'history') {
|
|
2526
2624
|
toLog(gui.session.toCommandLineString());
|
|
2527
2625
|
} else if (cmd == 'layers') {
|
|
2528
|
-
message("Available layers:",
|
|
2626
|
+
message$1("Available layers:",
|
|
2529
2627
|
internal.getFormattedLayerList(model));
|
|
2530
2628
|
} else if (cmd == 'close' || cmd == 'exit' || cmd == 'quit') {
|
|
2531
2629
|
turnOff();
|
|
@@ -2614,7 +2712,7 @@
|
|
|
2614
2712
|
}
|
|
2615
2713
|
|
|
2616
2714
|
function onError(err) {
|
|
2617
|
-
if (utils.isString(err)) {
|
|
2715
|
+
if (utils$1.isString(err)) {
|
|
2618
2716
|
consoleStop(err);
|
|
2619
2717
|
} else if (err.name == 'UserError') {
|
|
2620
2718
|
// stop() has already been called, don't need to log
|
|
@@ -2629,7 +2727,7 @@
|
|
|
2629
2727
|
function consoleStop() {
|
|
2630
2728
|
var msg = GUI.formatMessageArgs(arguments);
|
|
2631
2729
|
consoleWarning(msg);
|
|
2632
|
-
throw new UserError(msg);
|
|
2730
|
+
throw new UserError$1(msg);
|
|
2633
2731
|
}
|
|
2634
2732
|
|
|
2635
2733
|
function consoleWarning() {
|
|
@@ -2793,7 +2891,7 @@
|
|
|
2793
2891
|
// console.log("first intersection:", internal.getIntersectionDebugData(XX[0], arcs));
|
|
2794
2892
|
pointLyr = {geometry_type: 'point', shapes: [internal.getIntersectionPoints(XX)]};
|
|
2795
2893
|
map.setIntersectionLayer(pointLyr, {layers:[pointLyr]});
|
|
2796
|
-
readout.html(utils.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils.pluralSuffix(n)));
|
|
2894
|
+
readout.html(utils$1.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils$1.pluralSuffix(n)));
|
|
2797
2895
|
readout.findChild('.close-btn').on('click', dismiss);
|
|
2798
2896
|
} else {
|
|
2799
2897
|
map.setIntersectionLayer(null);
|
|
@@ -2802,7 +2900,7 @@
|
|
|
2802
2900
|
}
|
|
2803
2901
|
}
|
|
2804
2902
|
|
|
2805
|
-
utils.inherit(RepairControl, EventDispatcher);
|
|
2903
|
+
utils$1.inherit(RepairControl, EventDispatcher);
|
|
2806
2904
|
|
|
2807
2905
|
function filterLayerByIds(lyr, ids) {
|
|
2808
2906
|
var shapes;
|
|
@@ -2810,7 +2908,7 @@
|
|
|
2810
2908
|
shapes = ids.map(function(id) {
|
|
2811
2909
|
return lyr.shapes[id];
|
|
2812
2910
|
});
|
|
2813
|
-
return utils.defaults({shapes: shapes, data: null}, lyr);
|
|
2911
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
2814
2912
|
}
|
|
2815
2913
|
return lyr;
|
|
2816
2914
|
}
|
|
@@ -2863,7 +2961,7 @@
|
|
|
2863
2961
|
});
|
|
2864
2962
|
|
|
2865
2963
|
internal.writeFiles = function() {
|
|
2866
|
-
error(unsupportedMsg);
|
|
2964
|
+
error$1(unsupportedMsg);
|
|
2867
2965
|
};
|
|
2868
2966
|
} else {
|
|
2869
2967
|
new SimpleButton(menu.findChild('.save-btn').addClass('default-btn')).on('click', onExportClick);
|
|
@@ -2899,7 +2997,7 @@
|
|
|
2899
2997
|
setTimeout(function() {
|
|
2900
2998
|
exportMenuSelection(layers, function(err) {
|
|
2901
2999
|
if (err) {
|
|
2902
|
-
if (utils.isString(err)) {
|
|
3000
|
+
if (utils$1.isString(err)) {
|
|
2903
3001
|
gui.alert(err);
|
|
2904
3002
|
} else {
|
|
2905
3003
|
// stack seems to change if Error is logged directly
|
|
@@ -2946,7 +3044,7 @@
|
|
|
2946
3044
|
// without changing its name elsewhere
|
|
2947
3045
|
layer: Object.assign({}, o.layer)
|
|
2948
3046
|
};
|
|
2949
|
-
var html = utils.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
3047
|
+
var html = utils$1.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
2950
3048
|
// return {layer: o.layer, html: html};
|
|
2951
3049
|
var el = El('div').html(html).addClass('layer-item');
|
|
2952
3050
|
var box = el.findChild('input').node();
|
|
@@ -3056,9 +3154,9 @@
|
|
|
3056
3154
|
|
|
3057
3155
|
function initFormatMenu() {
|
|
3058
3156
|
var defaults = ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'svg'];
|
|
3059
|
-
var formats = utils.uniq(defaults.concat(getInputFormats()));
|
|
3157
|
+
var formats = utils$1.uniq(defaults.concat(getInputFormats()));
|
|
3060
3158
|
var items = formats.map(function(fmt) {
|
|
3061
|
-
return utils.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3159
|
+
return utils$1.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3062
3160
|
' class="radio">%s</label></div>', fmt, internal.getFormatName(fmt));
|
|
3063
3161
|
});
|
|
3064
3162
|
menu.findChild('.export-formats').html(items.join('\n'));
|
|
@@ -3221,7 +3319,7 @@
|
|
|
3221
3319
|
// can be used as unique identifiers for caching rendered HTML, and as
|
|
3222
3320
|
// an id for layer menu event handlers
|
|
3223
3321
|
if (!lyr.menu_id || uniqIds[lyr.menu_id]) {
|
|
3224
|
-
lyr.menu_id = utils.getUniqueName();
|
|
3322
|
+
lyr.menu_id = utils$1.getUniqueName();
|
|
3225
3323
|
}
|
|
3226
3324
|
uniqIds[lyr.menu_id] = true;
|
|
3227
3325
|
if (isPinnable(lyr)) pinnableCount++;
|
|
@@ -3394,7 +3492,7 @@
|
|
|
3394
3492
|
type = lyr.geometry_type + ' feature';
|
|
3395
3493
|
}
|
|
3396
3494
|
if (type) {
|
|
3397
|
-
str = utils.format('%,d %s%s', n, type, utils.pluralSuffix(n));
|
|
3495
|
+
str = utils$1.format('%,d %s%s', n, type, utils$1.pluralSuffix(n));
|
|
3398
3496
|
} else {
|
|
3399
3497
|
str = "[empty]";
|
|
3400
3498
|
}
|
|
@@ -3405,7 +3503,7 @@
|
|
|
3405
3503
|
var file = internal.getLayerSourceFile(lyr, dataset);
|
|
3406
3504
|
var missing = [];
|
|
3407
3505
|
var msg;
|
|
3408
|
-
if (utils.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
|
|
3506
|
+
if (utils$1.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
|
|
3409
3507
|
if (!lyr.data) {
|
|
3410
3508
|
missing.push('.dbf');
|
|
3411
3509
|
}
|
|
@@ -3431,7 +3529,7 @@
|
|
|
3431
3529
|
|
|
3432
3530
|
|
|
3433
3531
|
function rowHTML(c1, c2, cname) {
|
|
3434
|
-
return utils.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
3532
|
+
return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
3435
3533
|
'<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
|
|
3436
3534
|
}
|
|
3437
3535
|
}
|
|
@@ -3630,14 +3728,38 @@
|
|
|
3630
3728
|
this.addHistoryState(stashedUndo, redo);
|
|
3631
3729
|
}, this);
|
|
3632
3730
|
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3731
|
+
gui.on('vertex_dragend', function(e) {
|
|
3732
|
+
var target = gui.model.getActiveLayer();
|
|
3733
|
+
var arcs = target.dataset.arcs;
|
|
3734
|
+
var startPoint = e.points[0];
|
|
3735
|
+
var endPoint = internal.getVertexCoords(e.ids[0], arcs);
|
|
3736
|
+
var undo = function() {
|
|
3737
|
+
if (e.insertion) {
|
|
3738
|
+
internal.deleteVertex(arcs, e.ids[0]);
|
|
3739
|
+
} else {
|
|
3740
|
+
snapVerticesToPoint(e.ids, startPoint, arcs, true);
|
|
3741
|
+
}
|
|
3742
|
+
};
|
|
3743
|
+
var redo = function() {
|
|
3744
|
+
if (e.insertion) {
|
|
3745
|
+
internal.insertVertex(arcs, e.ids[0], e.points[0]);
|
|
3746
|
+
}
|
|
3747
|
+
snapVerticesToPoint(e.ids, endPoint, arcs, true);
|
|
3748
|
+
};
|
|
3749
|
+
this.addHistoryState(undo, redo);
|
|
3636
3750
|
}, this);
|
|
3637
3751
|
|
|
3638
|
-
gui.on('
|
|
3639
|
-
var
|
|
3640
|
-
|
|
3752
|
+
gui.on('vertex_delete', function(e) {
|
|
3753
|
+
var target = gui.model.getActiveLayer();
|
|
3754
|
+
var arcs = target.dataset.arcs;
|
|
3755
|
+
var p = arcs.getVertex2(e.vertex_id);
|
|
3756
|
+
var redo = function() {
|
|
3757
|
+
internal.deleteVertex(arcs, e.vertex_id);
|
|
3758
|
+
};
|
|
3759
|
+
var undo = function() {
|
|
3760
|
+
internal.insertVertex(arcs, e.vertex_id, p);
|
|
3761
|
+
};
|
|
3762
|
+
this.addHistoryState(undo, redo);
|
|
3641
3763
|
}, this);
|
|
3642
3764
|
|
|
3643
3765
|
this.clear = function() {
|
|
@@ -3661,7 +3783,7 @@
|
|
|
3661
3783
|
};
|
|
3662
3784
|
};
|
|
3663
3785
|
|
|
3664
|
-
this.makeVertexSetter = function(
|
|
3786
|
+
this.makeVertexSetter = function(ids) {
|
|
3665
3787
|
var target = gui.model.getActiveLayer();
|
|
3666
3788
|
var arcs = target.dataset.arcs;
|
|
3667
3789
|
var p = internal.getVertexCoords(ids[0], arcs);
|
|
@@ -3799,7 +3921,7 @@
|
|
|
3799
3921
|
};
|
|
3800
3922
|
}
|
|
3801
3923
|
|
|
3802
|
-
utils.inherit(ModeSwitcher, EventDispatcher);
|
|
3924
|
+
utils$1.inherit(ModeSwitcher, EventDispatcher);
|
|
3803
3925
|
|
|
3804
3926
|
function KeyboardEvents(gui) {
|
|
3805
3927
|
var self = this;
|
|
@@ -3827,7 +3949,7 @@
|
|
|
3827
3949
|
};
|
|
3828
3950
|
}
|
|
3829
3951
|
|
|
3830
|
-
utils.inherit(KeyboardEvents, EventDispatcher);
|
|
3952
|
+
utils$1.inherit(KeyboardEvents, EventDispatcher);
|
|
3831
3953
|
|
|
3832
3954
|
function InteractionMode(gui) {
|
|
3833
3955
|
|
|
@@ -3853,7 +3975,7 @@
|
|
|
3853
3975
|
data: 'edit attributes',
|
|
3854
3976
|
labels: 'position labels',
|
|
3855
3977
|
location: 'drag points',
|
|
3856
|
-
vertices: '
|
|
3978
|
+
vertices: 'edit vertices',
|
|
3857
3979
|
selection: 'select features',
|
|
3858
3980
|
off: 'turn off'
|
|
3859
3981
|
};
|
|
@@ -4049,7 +4171,7 @@
|
|
|
4049
4171
|
function Model(gui) {
|
|
4050
4172
|
var self = new internal.Catalog();
|
|
4051
4173
|
var deleteLayer = self.deleteLayer;
|
|
4052
|
-
utils.extend(self, EventDispatcher.prototype);
|
|
4174
|
+
utils$1.extend(self, EventDispatcher.prototype);
|
|
4053
4175
|
|
|
4054
4176
|
// override Catalog method (so -drop command will work in web console)
|
|
4055
4177
|
self.deleteLayer = function(lyr, dataset) {
|
|
@@ -4083,7 +4205,7 @@
|
|
|
4083
4205
|
if (flags.select) {
|
|
4084
4206
|
self.dispatchEvent('select', active);
|
|
4085
4207
|
}
|
|
4086
|
-
self.dispatchEvent('update', utils.extend({flags: flags}, active));
|
|
4208
|
+
self.dispatchEvent('update', utils$1.extend({flags: flags}, active));
|
|
4087
4209
|
};
|
|
4088
4210
|
|
|
4089
4211
|
self.selectLayer = function(lyr, dataset) {
|
|
@@ -4106,6 +4228,1251 @@
|
|
|
4106
4228
|
return self;
|
|
4107
4229
|
}
|
|
4108
4230
|
|
|
4231
|
+
var Buffer = require('buffer').Buffer; // works with browserify
|
|
4232
|
+
|
|
4233
|
+
var context = createContext(); // command context (persist for the current command cycle)
|
|
4234
|
+
|
|
4235
|
+
function runningInBrowser() {
|
|
4236
|
+
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
function getStateVar(key) {
|
|
4240
|
+
return context[key];
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
function setStateVar(key, val) {
|
|
4244
|
+
context[key] = val;
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
function createContext() {
|
|
4248
|
+
return {
|
|
4249
|
+
DEBUG: false,
|
|
4250
|
+
QUIET: false,
|
|
4251
|
+
VERBOSE: false,
|
|
4252
|
+
defs: {},
|
|
4253
|
+
input_files: []
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
// Install a new set of context variables, clear them when an async callback is called.
|
|
4258
|
+
// @cb callback function to wrap
|
|
4259
|
+
// returns wrapped callback function
|
|
4260
|
+
function createAsyncContext(cb) {
|
|
4261
|
+
context = createContext();
|
|
4262
|
+
return function() {
|
|
4263
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4264
|
+
// clear context after cb(), so output/errors can be handled in current context
|
|
4265
|
+
context = createContext();
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
// Save the current context, restore it when an async callback is called
|
|
4270
|
+
// @cb callback function to wrap
|
|
4271
|
+
// returns wrapped callback function
|
|
4272
|
+
function preserveContext(cb) {
|
|
4273
|
+
var ctx = context;
|
|
4274
|
+
return function() {
|
|
4275
|
+
context = ctx;
|
|
4276
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4277
|
+
};
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
var LOGGING = false;
|
|
4281
|
+
var STDOUT = false; // use stdout for status messages
|
|
4282
|
+
|
|
4283
|
+
// These three functions can be reset by GUI using setLoggingFunctions();
|
|
4284
|
+
var _error = function() {
|
|
4285
|
+
var msg = utils.toArray(arguments).join(' ');
|
|
4286
|
+
throw new Error(msg);
|
|
4287
|
+
};
|
|
4288
|
+
|
|
4289
|
+
var _stop = function() {
|
|
4290
|
+
throw new UserError(formatLogArgs(arguments));
|
|
4291
|
+
};
|
|
4292
|
+
|
|
4293
|
+
var _interrupt = function() {
|
|
4294
|
+
throw new NonFatalError(formatLogArgs(arguments));
|
|
4295
|
+
};
|
|
4296
|
+
|
|
4297
|
+
var _message = function() {
|
|
4298
|
+
logArgs(arguments);
|
|
4299
|
+
};
|
|
4300
|
+
|
|
4301
|
+
function enableLogging() {
|
|
4302
|
+
LOGGING = true;
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
function loggingEnabled() {
|
|
4306
|
+
return !!LOGGING;
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4309
|
+
// Handle an unexpected condition (internal error)
|
|
4310
|
+
function error() {
|
|
4311
|
+
_error.apply(null, utils.toArray(arguments));
|
|
4312
|
+
}
|
|
4313
|
+
|
|
4314
|
+
// Handle an error caused by invalid input or misuse of API
|
|
4315
|
+
function stop() {
|
|
4316
|
+
_stop.apply(null, utils.toArray(arguments));
|
|
4317
|
+
}
|
|
4318
|
+
|
|
4319
|
+
function interrupt() {
|
|
4320
|
+
_interrupt.apply(null, utils.toArray(arguments));
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
// Print a status message
|
|
4324
|
+
function message() {
|
|
4325
|
+
_message.apply(null, messageArgs(arguments));
|
|
4326
|
+
}
|
|
4327
|
+
|
|
4328
|
+
// A way for the GUI to replace the CLI logging functions
|
|
4329
|
+
function setLoggingFunctions(message, error, stop) {
|
|
4330
|
+
_message = message;
|
|
4331
|
+
_error = error;
|
|
4332
|
+
_stop = stop;
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
|
|
4336
|
+
// print a message to stdout
|
|
4337
|
+
function print() {
|
|
4338
|
+
STDOUT = true; // tell logArgs() to print to stdout, not stderr
|
|
4339
|
+
// calling message() adds the "[command name]" prefix
|
|
4340
|
+
_message(utils.toArray(arguments));
|
|
4341
|
+
STDOUT = false;
|
|
4342
|
+
}
|
|
4343
|
+
|
|
4344
|
+
function verbose() {
|
|
4345
|
+
// verbose can be set globally with the -verbose command or separately for each command
|
|
4346
|
+
if (getStateVar('VERBOSE') || getStateVar('verbose')) {
|
|
4347
|
+
message.apply(null, arguments);
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
function debug() {
|
|
4352
|
+
if (getStateVar('DEBUG') || getStateVar('debug')) {
|
|
4353
|
+
logArgs(arguments);
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
function printError(err) {
|
|
4358
|
+
var msg;
|
|
4359
|
+
if (!LOGGING) return;
|
|
4360
|
+
if (utils.isString(err)) {
|
|
4361
|
+
err = new UserError(err);
|
|
4362
|
+
}
|
|
4363
|
+
if (err.name == 'NonFatalError') {
|
|
4364
|
+
console.error(messageArgs([err.message]).join(' '));
|
|
4365
|
+
} else if (err.name == 'UserError') {
|
|
4366
|
+
msg = err.message;
|
|
4367
|
+
if (!/Error/.test(msg)) {
|
|
4368
|
+
msg = "Error: " + msg;
|
|
4369
|
+
}
|
|
4370
|
+
console.error(messageArgs([msg]).join(' '));
|
|
4371
|
+
console.error("Run mapshaper -h to view help");
|
|
4372
|
+
} else {
|
|
4373
|
+
// not a user error (i.e. a bug in mapshaper)
|
|
4374
|
+
console.error(err);
|
|
4375
|
+
// throw err;
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
function UserError(msg) {
|
|
4380
|
+
var err = new Error(msg);
|
|
4381
|
+
err.name = 'UserError';
|
|
4382
|
+
return err;
|
|
4383
|
+
}
|
|
4384
|
+
|
|
4385
|
+
function NonFatalError(msg) {
|
|
4386
|
+
var err = new Error(msg);
|
|
4387
|
+
err.name = 'NonFatalError';
|
|
4388
|
+
return err;
|
|
4389
|
+
}
|
|
4390
|
+
|
|
4391
|
+
function formatColumns(arr, alignments) {
|
|
4392
|
+
var widths = arr.reduce(function(memo, line) {
|
|
4393
|
+
return line.map(function(str, i) {
|
|
4394
|
+
return memo ? Math.max(memo[i], str.length) : str.length;
|
|
4395
|
+
});
|
|
4396
|
+
}, null);
|
|
4397
|
+
return arr.map(function(line) {
|
|
4398
|
+
line = line.map(function(str, i) {
|
|
4399
|
+
var rt = alignments && alignments[i] == 'right';
|
|
4400
|
+
var pad = (rt ? str.padStart : str.padEnd).bind(str);
|
|
4401
|
+
return pad(widths[i], ' ');
|
|
4402
|
+
});
|
|
4403
|
+
return ' ' + line.join(' ');
|
|
4404
|
+
}).join('\n');
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4407
|
+
// Format an array of (preferably short) strings in columns for console logging.
|
|
4408
|
+
function formatStringsAsGrid(arr) {
|
|
4409
|
+
// TODO: variable column width
|
|
4410
|
+
var longest = arr.reduce(function(len, str) {
|
|
4411
|
+
return Math.max(len, str.length);
|
|
4412
|
+
}, 0),
|
|
4413
|
+
colWidth = longest + 2,
|
|
4414
|
+
perLine = Math.floor(80 / colWidth) || 1;
|
|
4415
|
+
return arr.reduce(function(memo, name, i) {
|
|
4416
|
+
var col = i % perLine;
|
|
4417
|
+
if (i > 0 && col === 0) memo += '\n';
|
|
4418
|
+
if (col < perLine - 1) { // right-pad all but rightmost column
|
|
4419
|
+
name = utils.rpad(name, colWidth - 2, ' ');
|
|
4420
|
+
}
|
|
4421
|
+
return memo + ' ' + name;
|
|
4422
|
+
}, '');
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
// expose so GUI can use it
|
|
4426
|
+
function formatLogArgs(args) {
|
|
4427
|
+
return utils.toArray(args).join(' ');
|
|
4428
|
+
}
|
|
4429
|
+
|
|
4430
|
+
function messageArgs(args) {
|
|
4431
|
+
var arr = utils.toArray(args);
|
|
4432
|
+
var cmd = getStateVar('current_command');
|
|
4433
|
+
if (cmd && cmd != 'help') {
|
|
4434
|
+
arr.unshift('[' + cmd + ']');
|
|
4435
|
+
}
|
|
4436
|
+
return arr;
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
function logArgs(args) {
|
|
4440
|
+
if (!LOGGING || getStateVar('QUIET') || !utils.isArrayLike(args)) return;
|
|
4441
|
+
var msg = formatLogArgs(args);
|
|
4442
|
+
if (STDOUT) console.log(msg);
|
|
4443
|
+
else console.error(msg);
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
var uniqCount = 0;
|
|
4447
|
+
function getUniqueName(prefix) {
|
|
4448
|
+
return (prefix || "__id_") + (++uniqCount);
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
function isFunction(obj) {
|
|
4452
|
+
return typeof obj == 'function';
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
function isObject(obj) {
|
|
4456
|
+
return obj === Object(obj); // via underscore
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
function clamp(val, min, max) {
|
|
4460
|
+
return val < min ? min : (val > max ? max : val);
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4463
|
+
function isArray(obj) {
|
|
4464
|
+
return Array.isArray(obj);
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
// Is obj a valid number or NaN? (test if obj is type number)
|
|
4468
|
+
function isNumber(obj) {
|
|
4469
|
+
return obj != null && obj.constructor == Number;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
function isValidNumber(val) {
|
|
4473
|
+
return isNumber(val) && !isNaN(val);
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
// Similar to isFinite() but does not coerce strings or other types
|
|
4477
|
+
function isFiniteNumber(val) {
|
|
4478
|
+
return isValidNumber(val) && val !== Infinity && val !== -Infinity;
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
// This uses type conversion
|
|
4482
|
+
// export function isFiniteNumber(val) {
|
|
4483
|
+
// return val > -Infinity && val < Infinity;
|
|
4484
|
+
// }
|
|
4485
|
+
|
|
4486
|
+
function isNonNegNumber(val) {
|
|
4487
|
+
return isNumber(val) && val >= 0;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
function isInteger(obj) {
|
|
4491
|
+
return isNumber(obj) && ((obj | 0) === obj);
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
function isEven(obj) {
|
|
4495
|
+
return (obj % 2) === 0;
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4498
|
+
function isOdd(obj) {
|
|
4499
|
+
return (obj % 2) === 1;
|
|
4500
|
+
}
|
|
4501
|
+
|
|
4502
|
+
function isString(obj) {
|
|
4503
|
+
return obj != null && obj.toString === String.prototype.toString;
|
|
4504
|
+
// TODO: replace w/ something better.
|
|
4505
|
+
}
|
|
4506
|
+
|
|
4507
|
+
function isDate(obj) {
|
|
4508
|
+
return !!obj && obj.getTime === Date.prototype.getTime;
|
|
4509
|
+
}
|
|
4510
|
+
|
|
4511
|
+
function isBoolean(obj) {
|
|
4512
|
+
return obj === true || obj === false;
|
|
4513
|
+
}
|
|
4514
|
+
|
|
4515
|
+
function formatDateISO(d) {
|
|
4516
|
+
if (!isDate(d)) return '';
|
|
4517
|
+
return d.toISOString().replace(':00.000Z', 'Z');
|
|
4518
|
+
}
|
|
4519
|
+
|
|
4520
|
+
// Convert an array-like object to an Array, or make a copy if @obj is an Array
|
|
4521
|
+
function toArray(obj) {
|
|
4522
|
+
var arr;
|
|
4523
|
+
if (!isArrayLike(obj)) error("toArray() requires an array-like object");
|
|
4524
|
+
try {
|
|
4525
|
+
arr = Array.prototype.slice.call(obj, 0); // breaks in ie8
|
|
4526
|
+
} catch(e) {
|
|
4527
|
+
// support ie8
|
|
4528
|
+
arr = [];
|
|
4529
|
+
for (var i=0, n=obj.length; i<n; i++) {
|
|
4530
|
+
arr[i] = obj[i];
|
|
4531
|
+
}
|
|
4532
|
+
}
|
|
4533
|
+
return arr;
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
// Array like: has length property, is numerically indexed and mutable.
|
|
4537
|
+
// TODO: try to detect objects with length property but no indexed data elements
|
|
4538
|
+
function isArrayLike(obj) {
|
|
4539
|
+
if (!obj) return false;
|
|
4540
|
+
if (isArray(obj)) return true;
|
|
4541
|
+
if (isString(obj)) return false;
|
|
4542
|
+
if (obj.length === 0) return true;
|
|
4543
|
+
if (obj.length > 0) return true;
|
|
4544
|
+
return false;
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
// See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js
|
|
4548
|
+
function addslashes(str) {
|
|
4549
|
+
return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4552
|
+
// Escape a literal string to use in a regexp.
|
|
4553
|
+
// Ref.: http://simonwillison.net/2006/Jan/20/escape/
|
|
4554
|
+
function regexEscape(str) {
|
|
4555
|
+
return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
4556
|
+
}
|
|
4557
|
+
|
|
4558
|
+
|
|
4559
|
+
// See https://github.com/janl/mustache.js/blob/master/mustache.js
|
|
4560
|
+
var entityMap = {
|
|
4561
|
+
'&': '&',
|
|
4562
|
+
'<': '<',
|
|
4563
|
+
'>': '>',
|
|
4564
|
+
'"': '"',
|
|
4565
|
+
"'": ''',
|
|
4566
|
+
'/': '/'
|
|
4567
|
+
};
|
|
4568
|
+
function htmlEscape(s) {
|
|
4569
|
+
return String(s).replace(/[&<>"'\/]/g, function(s) {
|
|
4570
|
+
return entityMap[s];
|
|
4571
|
+
});
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
function defaults(dest) {
|
|
4575
|
+
for (var i=1, n=arguments.length; i<n; i++) {
|
|
4576
|
+
var src = arguments[i] || {};
|
|
4577
|
+
for (var key in src) {
|
|
4578
|
+
if (key in dest === false && src.hasOwnProperty(key)) {
|
|
4579
|
+
dest[key] = src[key];
|
|
4580
|
+
}
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
return dest;
|
|
4584
|
+
}
|
|
4585
|
+
|
|
4586
|
+
function extend(o) {
|
|
4587
|
+
var dest = o || {},
|
|
4588
|
+
n = arguments.length,
|
|
4589
|
+
key, i, src;
|
|
4590
|
+
for (i=1; i<n; i++) {
|
|
4591
|
+
src = arguments[i] || {};
|
|
4592
|
+
for (key in src) {
|
|
4593
|
+
if (src.hasOwnProperty(key)) {
|
|
4594
|
+
dest[key] = src[key];
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
return dest;
|
|
4599
|
+
}
|
|
4600
|
+
|
|
4601
|
+
// Pseudoclassical inheritance
|
|
4602
|
+
//
|
|
4603
|
+
// Inherit from a Parent function:
|
|
4604
|
+
// inherit(Child, Parent);
|
|
4605
|
+
// Call parent's constructor (inside child constructor):
|
|
4606
|
+
// this.__super__([args...]);
|
|
4607
|
+
function inherit(targ, src) {
|
|
4608
|
+
var f = function() {
|
|
4609
|
+
if (this.__super__ == f) {
|
|
4610
|
+
// add __super__ of parent to front of lookup chain
|
|
4611
|
+
// so parent class constructor can call its parent using this.__super__
|
|
4612
|
+
this.__super__ = src.prototype.__super__;
|
|
4613
|
+
// call parent constructor function. this.__super__ now points to parent-of-parent
|
|
4614
|
+
src.apply(this, arguments);
|
|
4615
|
+
// remove temp __super__, expose targ.prototype.__super__ again
|
|
4616
|
+
delete this.__super__;
|
|
4617
|
+
}
|
|
4618
|
+
};
|
|
4619
|
+
|
|
4620
|
+
f.prototype = src.prototype || src; // added || src to allow inheriting from objects as well as functions
|
|
4621
|
+
// Extend targ prototype instead of wiping it out --
|
|
4622
|
+
// in case inherit() is called after targ.prototype = {stuff}; statement
|
|
4623
|
+
targ.prototype = extend(new f(), targ.prototype); //
|
|
4624
|
+
targ.prototype.constructor = targ;
|
|
4625
|
+
targ.prototype.__super__ = f;
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
|
|
4629
|
+
// Call @iter on each member of an array (similar to Array#reduce(iter))
|
|
4630
|
+
// iter: function(memo, item, callback)
|
|
4631
|
+
// Call @done when all members have been processed or if an error occurs
|
|
4632
|
+
// done: function(err, memo)
|
|
4633
|
+
// @memo: Initial value
|
|
4634
|
+
//
|
|
4635
|
+
function reduceAsync(arr, memo, iter, done) {
|
|
4636
|
+
var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate;
|
|
4637
|
+
var i=0;
|
|
4638
|
+
next(null, memo);
|
|
4639
|
+
|
|
4640
|
+
function next(err, memo) {
|
|
4641
|
+
// Detach next operation from call stack to prevent overflow
|
|
4642
|
+
// Don't use setTimeout(, 0) if setImmediate is available
|
|
4643
|
+
// (setTimeout() can introduce a long delay if previous operation was slow,
|
|
4644
|
+
// as of Node 0.10.32 -- a bug?)
|
|
4645
|
+
if (err) {
|
|
4646
|
+
return done(err, null);
|
|
4647
|
+
}
|
|
4648
|
+
call(function() {
|
|
4649
|
+
if (i < arr.length === false) {
|
|
4650
|
+
done(null, memo);
|
|
4651
|
+
} else {
|
|
4652
|
+
iter(memo, arr[i++], next);
|
|
4653
|
+
}
|
|
4654
|
+
}, 0);
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4658
|
+
|
|
4659
|
+
// Append elements of @src array to @dest array
|
|
4660
|
+
function merge(dest, src) {
|
|
4661
|
+
if (!isArray(dest) || !isArray(src)) {
|
|
4662
|
+
error("Usage: merge(destArray, srcArray);");
|
|
4663
|
+
}
|
|
4664
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
4665
|
+
dest.push(src[i]);
|
|
4666
|
+
}
|
|
4667
|
+
return dest;
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4670
|
+
// Returns elements in arr and not in other
|
|
4671
|
+
// (similar to underscore diff)
|
|
4672
|
+
function difference(arr, other) {
|
|
4673
|
+
var index = arrayToIndex(other);
|
|
4674
|
+
return arr.filter(function(el) {
|
|
4675
|
+
return !Object.prototype.hasOwnProperty.call(index, el);
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4678
|
+
|
|
4679
|
+
// Return the intersection of two arrays
|
|
4680
|
+
function intersection(a, b) {
|
|
4681
|
+
return a.filter(function(el) {
|
|
4682
|
+
return b.includes(el);
|
|
4683
|
+
});
|
|
4684
|
+
}
|
|
4685
|
+
|
|
4686
|
+
function indexOf(arr, item) {
|
|
4687
|
+
var nan = item !== item;
|
|
4688
|
+
for (var i = 0, len = arr.length || 0; i < len; i++) {
|
|
4689
|
+
if (arr[i] === item) return i;
|
|
4690
|
+
if (nan && arr[i] !== arr[i]) return i;
|
|
4691
|
+
}
|
|
4692
|
+
return -1;
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4695
|
+
// Test a string or array-like object for existence of substring or element
|
|
4696
|
+
function contains(container, item) {
|
|
4697
|
+
if (isString(container)) {
|
|
4698
|
+
return container.indexOf(item) != -1;
|
|
4699
|
+
}
|
|
4700
|
+
else if (isArrayLike(container)) {
|
|
4701
|
+
return indexOf(container, item) != -1;
|
|
4702
|
+
}
|
|
4703
|
+
error("Expected Array or String argument");
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
function some(arr, test) {
|
|
4707
|
+
return arr.reduce(function(val, item) {
|
|
4708
|
+
return val || test(item); // TODO: short-circuit?
|
|
4709
|
+
}, false);
|
|
4710
|
+
}
|
|
4711
|
+
|
|
4712
|
+
function every(arr, test) {
|
|
4713
|
+
return arr.reduce(function(val, item) {
|
|
4714
|
+
return val && test(item);
|
|
4715
|
+
}, true);
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
function find(arr, test, ctx) {
|
|
4719
|
+
var matches = arr.filter(test, ctx);
|
|
4720
|
+
return matches.length === 0 ? null : matches[0];
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
function range(len, start, inc) {
|
|
4724
|
+
var arr = [],
|
|
4725
|
+
v = start === void 0 ? 0 : start,
|
|
4726
|
+
i = inc === void 0 ? 1 : inc;
|
|
4727
|
+
while(len--) {
|
|
4728
|
+
arr.push(v);
|
|
4729
|
+
v += i;
|
|
4730
|
+
}
|
|
4731
|
+
return arr;
|
|
4732
|
+
}
|
|
4733
|
+
|
|
4734
|
+
function repeat(times, func) {
|
|
4735
|
+
var values = [],
|
|
4736
|
+
val;
|
|
4737
|
+
for (var i=0; i<times; i++) {
|
|
4738
|
+
val = func(i);
|
|
4739
|
+
if (val !== void 0) {
|
|
4740
|
+
values[i] = val;
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
return values.length > 0 ? values : void 0;
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
// Calc sum, skip falsy and NaN values
|
|
4747
|
+
// Assumes: no other non-numeric objects in array
|
|
4748
|
+
//
|
|
4749
|
+
function sum(arr, info) {
|
|
4750
|
+
if (!isArrayLike(arr)) error ("sum() expects an array, received:", arr);
|
|
4751
|
+
var tot = 0,
|
|
4752
|
+
nan = 0,
|
|
4753
|
+
val;
|
|
4754
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
4755
|
+
val = arr[i];
|
|
4756
|
+
if (val) {
|
|
4757
|
+
tot += val;
|
|
4758
|
+
} else if (isNaN(val)) {
|
|
4759
|
+
nan++;
|
|
4760
|
+
}
|
|
4761
|
+
}
|
|
4762
|
+
if (info) {
|
|
4763
|
+
info.nan = nan;
|
|
4764
|
+
}
|
|
4765
|
+
return tot;
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
// Calculate min and max values of an array, ignoring NaN values
|
|
4769
|
+
function getArrayBounds(arr) {
|
|
4770
|
+
var min = Infinity,
|
|
4771
|
+
max = -Infinity,
|
|
4772
|
+
nan = 0, val;
|
|
4773
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4774
|
+
val = arr[i];
|
|
4775
|
+
if (val !== val) nan++;
|
|
4776
|
+
if (val < min) min = val;
|
|
4777
|
+
if (val > max) max = val;
|
|
4778
|
+
}
|
|
4779
|
+
return {
|
|
4780
|
+
min: min,
|
|
4781
|
+
max: max,
|
|
4782
|
+
nan: nan
|
|
4783
|
+
};
|
|
4784
|
+
}
|
|
4785
|
+
|
|
4786
|
+
// export function uniq(src) {
|
|
4787
|
+
// var index = {};
|
|
4788
|
+
// return src.reduce(function(memo, el) {
|
|
4789
|
+
// if (el in index === false) {
|
|
4790
|
+
// index[el] = true;
|
|
4791
|
+
// memo.push(el);
|
|
4792
|
+
// }
|
|
4793
|
+
// return memo;
|
|
4794
|
+
// }, []);
|
|
4795
|
+
// }
|
|
4796
|
+
|
|
4797
|
+
function uniq(src) {
|
|
4798
|
+
var index = new Set();
|
|
4799
|
+
var arr = [];
|
|
4800
|
+
var item;
|
|
4801
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
4802
|
+
item = src[i];
|
|
4803
|
+
if (!index.has(item)) {
|
|
4804
|
+
arr.push(item);
|
|
4805
|
+
index.add(item);
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
return arr;
|
|
4809
|
+
}
|
|
4810
|
+
|
|
4811
|
+
function pluck(arr, key) {
|
|
4812
|
+
return arr.map(function(obj) {
|
|
4813
|
+
return obj[key];
|
|
4814
|
+
});
|
|
4815
|
+
}
|
|
4816
|
+
|
|
4817
|
+
function countValues(arr) {
|
|
4818
|
+
return arr.reduce(function(memo, val) {
|
|
4819
|
+
memo[val] = (val in memo) ? memo[val] + 1 : 1;
|
|
4820
|
+
return memo;
|
|
4821
|
+
}, {});
|
|
4822
|
+
}
|
|
4823
|
+
|
|
4824
|
+
function indexOn(arr, k) {
|
|
4825
|
+
return arr.reduce(function(index, o) {
|
|
4826
|
+
index[o[k]] = o;
|
|
4827
|
+
return index;
|
|
4828
|
+
}, {});
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
function groupBy(arr, k) {
|
|
4832
|
+
return arr.reduce(function(index, o) {
|
|
4833
|
+
var keyval = o[k];
|
|
4834
|
+
if (keyval in index) {
|
|
4835
|
+
index[keyval].push(o);
|
|
4836
|
+
} else {
|
|
4837
|
+
index[keyval] = [o];
|
|
4838
|
+
}
|
|
4839
|
+
return index;
|
|
4840
|
+
}, {});
|
|
4841
|
+
}
|
|
4842
|
+
|
|
4843
|
+
function arrayToIndex(arr, val) {
|
|
4844
|
+
var init = arguments.length > 1;
|
|
4845
|
+
return arr.reduce(function(index, key) {
|
|
4846
|
+
index[key] = init ? val : true;
|
|
4847
|
+
return index;
|
|
4848
|
+
}, {});
|
|
4849
|
+
}
|
|
4850
|
+
|
|
4851
|
+
// Support for iterating over array-like objects, like typed arrays
|
|
4852
|
+
function forEach(arr, func, ctx) {
|
|
4853
|
+
if (!isArrayLike(arr)) {
|
|
4854
|
+
throw new Error("#forEach() takes an array-like argument. " + arr);
|
|
4855
|
+
}
|
|
4856
|
+
for (var i=0, n=arr.length; i < n; i++) {
|
|
4857
|
+
func.call(ctx, arr[i], i);
|
|
4858
|
+
}
|
|
4859
|
+
}
|
|
4860
|
+
|
|
4861
|
+
function forEachProperty(o, func, ctx) {
|
|
4862
|
+
Object.keys(o).forEach(function(key) {
|
|
4863
|
+
func.call(ctx, o[key], key);
|
|
4864
|
+
});
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
function initializeArray(arr, init) {
|
|
4868
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4869
|
+
arr[i] = init;
|
|
4870
|
+
}
|
|
4871
|
+
return arr;
|
|
4872
|
+
}
|
|
4873
|
+
|
|
4874
|
+
function replaceArray(arr, arr2) {
|
|
4875
|
+
arr.splice(0, arr.length);
|
|
4876
|
+
for (var i=0, n=arr2.length; i<n; i++) {
|
|
4877
|
+
arr.push(arr2[i]);
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4881
|
+
function repeatString(src, n) {
|
|
4882
|
+
var str = "";
|
|
4883
|
+
for (var i=0; i<n; i++)
|
|
4884
|
+
str += src;
|
|
4885
|
+
return str;
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
function splitLines(str) {
|
|
4889
|
+
return str.split(/\r?\n/);
|
|
4890
|
+
}
|
|
4891
|
+
|
|
4892
|
+
function pluralSuffix(count) {
|
|
4893
|
+
return count != 1 ? 's' : '';
|
|
4894
|
+
}
|
|
4895
|
+
|
|
4896
|
+
function endsWith(str, ending) {
|
|
4897
|
+
return str.indexOf(ending, str.length - ending.length) !== -1;
|
|
4898
|
+
}
|
|
4899
|
+
|
|
4900
|
+
function lpad(str, size, pad) {
|
|
4901
|
+
pad = pad || ' ';
|
|
4902
|
+
str = String(str);
|
|
4903
|
+
return repeatString(pad, size - str.length) + str;
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
function rpad(str, size, pad) {
|
|
4907
|
+
pad = pad || ' ';
|
|
4908
|
+
str = String(str);
|
|
4909
|
+
return str + repeatString(pad, size - str.length);
|
|
4910
|
+
}
|
|
4911
|
+
|
|
4912
|
+
function trim(str) {
|
|
4913
|
+
return ltrim(rtrim(str));
|
|
4914
|
+
}
|
|
4915
|
+
|
|
4916
|
+
var ltrimRxp = /^\s+/;
|
|
4917
|
+
function ltrim(str) {
|
|
4918
|
+
return str.replace(ltrimRxp, '');
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
var rtrimRxp = /\s+$/;
|
|
4922
|
+
function rtrim(str) {
|
|
4923
|
+
return str.replace(rtrimRxp, '');
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4926
|
+
function addThousandsSep(str) {
|
|
4927
|
+
var fmt = '',
|
|
4928
|
+
start = str[0] == '-' ? 1 : 0,
|
|
4929
|
+
dec = str.indexOf('.'),
|
|
4930
|
+
end = str.length,
|
|
4931
|
+
ins = (dec == -1 ? end : dec) - 3;
|
|
4932
|
+
while (ins > start) {
|
|
4933
|
+
fmt = ',' + str.substring(ins, end) + fmt;
|
|
4934
|
+
end = ins;
|
|
4935
|
+
ins -= 3;
|
|
4936
|
+
}
|
|
4937
|
+
return str.substring(0, end) + fmt;
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4940
|
+
function numToStr(num, decimals) {
|
|
4941
|
+
return decimals >= 0 ? num.toFixed(decimals) : String(num);
|
|
4942
|
+
}
|
|
4943
|
+
|
|
4944
|
+
function formatNumber(val) {
|
|
4945
|
+
return val + '';
|
|
4946
|
+
}
|
|
4947
|
+
|
|
4948
|
+
function formatIntlNumber(val) {
|
|
4949
|
+
var str = formatNumber(val);
|
|
4950
|
+
return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited
|
|
4951
|
+
}
|
|
4952
|
+
|
|
4953
|
+
function formatNumberForDisplay(num, decimals, nullStr, showPos) {
|
|
4954
|
+
var fmt;
|
|
4955
|
+
if (isNaN(num)) {
|
|
4956
|
+
fmt = nullStr || '-';
|
|
4957
|
+
} else {
|
|
4958
|
+
fmt = numToStr(num, decimals);
|
|
4959
|
+
fmt = addThousandsSep(fmt);
|
|
4960
|
+
if (showPos && parseFloat(fmt) > 0) {
|
|
4961
|
+
fmt = "+" + fmt;
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
return fmt;
|
|
4965
|
+
}
|
|
4966
|
+
|
|
4967
|
+
function shuffle(arr) {
|
|
4968
|
+
var tmp, i, j;
|
|
4969
|
+
for (i = arr.length - 1; i > 0; i--) {
|
|
4970
|
+
j = Math.floor(Math.random() * (i + 1));
|
|
4971
|
+
tmp = arr[i];
|
|
4972
|
+
arr[i] = arr[j];
|
|
4973
|
+
arr[j] = tmp;
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
|
|
4977
|
+
// Sort an array of objects based on one or more properties.
|
|
4978
|
+
// Usage: sortOn(array, key1, asc?[, key2, asc? ...])
|
|
4979
|
+
//
|
|
4980
|
+
function sortOn(arr) {
|
|
4981
|
+
var comparators = [];
|
|
4982
|
+
for (var i=1; i<arguments.length; i+=2) {
|
|
4983
|
+
comparators.push(getKeyComparator(arguments[i], arguments[i+1]));
|
|
4984
|
+
}
|
|
4985
|
+
arr.sort(function(a, b) {
|
|
4986
|
+
var cmp = 0,
|
|
4987
|
+
i = 0,
|
|
4988
|
+
n = comparators.length;
|
|
4989
|
+
while (i < n && cmp === 0) {
|
|
4990
|
+
cmp = comparators[i](a, b);
|
|
4991
|
+
i++;
|
|
4992
|
+
}
|
|
4993
|
+
return cmp;
|
|
4994
|
+
});
|
|
4995
|
+
return arr;
|
|
4996
|
+
}
|
|
4997
|
+
|
|
4998
|
+
// Sort array of values that can be compared with < > operators (strings, numbers)
|
|
4999
|
+
// null, undefined and NaN are sorted to the end of the array
|
|
5000
|
+
// default order is ascending
|
|
5001
|
+
//
|
|
5002
|
+
function genericSort(arr, ascending) {
|
|
5003
|
+
var compare = getGenericComparator(ascending);
|
|
5004
|
+
Array.prototype.sort.call(arr, compare);
|
|
5005
|
+
return arr;
|
|
5006
|
+
}
|
|
5007
|
+
|
|
5008
|
+
function getSortedIds(arr, asc) {
|
|
5009
|
+
var ids = range(arr.length);
|
|
5010
|
+
sortArrayIndex(ids, arr, asc);
|
|
5011
|
+
return ids;
|
|
5012
|
+
}
|
|
5013
|
+
|
|
5014
|
+
function sortArrayIndex(ids, arr, asc) {
|
|
5015
|
+
var compare = getGenericComparator(asc);
|
|
5016
|
+
ids.sort(function(i, j) {
|
|
5017
|
+
// added i, j comparison to guarantee that sort is stable
|
|
5018
|
+
var cmp = compare(arr[i], arr[j]);
|
|
5019
|
+
return cmp > 0 || cmp === 0 && i > j ? 1 : -1;
|
|
5020
|
+
});
|
|
5021
|
+
}
|
|
5022
|
+
|
|
5023
|
+
function reorderArray(arr, idxs) {
|
|
5024
|
+
var len = idxs.length;
|
|
5025
|
+
var arr2 = [];
|
|
5026
|
+
for (var i=0; i<len; i++) {
|
|
5027
|
+
var idx = idxs[i];
|
|
5028
|
+
if (idx < 0 || idx >= len) error("Out-of-bounds array idx");
|
|
5029
|
+
arr2[i] = arr[idx];
|
|
5030
|
+
}
|
|
5031
|
+
replaceArray(arr, arr2);
|
|
5032
|
+
}
|
|
5033
|
+
|
|
5034
|
+
function getKeyComparator(key, asc) {
|
|
5035
|
+
var compare = getGenericComparator(asc);
|
|
5036
|
+
return function(a, b) {
|
|
5037
|
+
return compare(a[key], b[key]);
|
|
5038
|
+
};
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
function getGenericComparator(asc) {
|
|
5042
|
+
asc = asc !== false;
|
|
5043
|
+
return function(a, b) {
|
|
5044
|
+
var retn = 0;
|
|
5045
|
+
if (b == null) {
|
|
5046
|
+
retn = a == null ? 0 : -1;
|
|
5047
|
+
} else if (a == null) {
|
|
5048
|
+
retn = 1;
|
|
5049
|
+
} else if (a < b) {
|
|
5050
|
+
retn = asc ? -1 : 1;
|
|
5051
|
+
} else if (a > b) {
|
|
5052
|
+
retn = asc ? 1 : -1;
|
|
5053
|
+
} else if (a !== a) {
|
|
5054
|
+
retn = 1;
|
|
5055
|
+
} else if (b !== b) {
|
|
5056
|
+
retn = -1;
|
|
5057
|
+
}
|
|
5058
|
+
return retn;
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
|
|
5063
|
+
// Generic in-place sort (null, NaN, undefined not handled)
|
|
5064
|
+
function quicksort(arr, asc) {
|
|
5065
|
+
quicksortPartition(arr, 0, arr.length-1);
|
|
5066
|
+
if (asc === false) Array.prototype.reverse.call(arr); // Works with typed arrays
|
|
5067
|
+
return arr;
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
// Moved out of quicksort() (saw >100% speedup in Chrome with deep recursion)
|
|
5071
|
+
function quicksortPartition (a, lo, hi) {
|
|
5072
|
+
var i = lo,
|
|
5073
|
+
j = hi,
|
|
5074
|
+
pivot, tmp;
|
|
5075
|
+
while (i < hi) {
|
|
5076
|
+
pivot = a[lo + hi >> 1]; // avoid n^2 performance on sorted arrays
|
|
5077
|
+
while (i <= j) {
|
|
5078
|
+
while (a[i] < pivot) i++;
|
|
5079
|
+
while (a[j] > pivot) j--;
|
|
5080
|
+
if (i <= j) {
|
|
5081
|
+
tmp = a[i];
|
|
5082
|
+
a[i] = a[j];
|
|
5083
|
+
a[j] = tmp;
|
|
5084
|
+
i++;
|
|
5085
|
+
j--;
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
if (lo < j) quicksortPartition(a, lo, j);
|
|
5089
|
+
lo = i;
|
|
5090
|
+
j = hi;
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
|
|
5094
|
+
|
|
5095
|
+
function findRankByValue(arr, value) {
|
|
5096
|
+
if (isNaN(value)) return arr.length;
|
|
5097
|
+
var rank = 1;
|
|
5098
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
5099
|
+
if (value > arr[i]) rank++;
|
|
5100
|
+
}
|
|
5101
|
+
return rank;
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
function findValueByPct(arr, pct) {
|
|
5105
|
+
var rank = Math.ceil((1-pct) * (arr.length));
|
|
5106
|
+
return findValueByRank(arr, rank);
|
|
5107
|
+
}
|
|
5108
|
+
|
|
5109
|
+
// See http://ndevilla.free.fr/median/median/src/wirth.c
|
|
5110
|
+
// Elements of @arr are reordered
|
|
5111
|
+
//
|
|
5112
|
+
function findValueByRank(arr, rank) {
|
|
5113
|
+
if (!arr.length || rank < 1 || rank > arr.length) error("[findValueByRank()] invalid input");
|
|
5114
|
+
|
|
5115
|
+
rank = clamp(rank | 0, 1, arr.length);
|
|
5116
|
+
var k = rank - 1, // conv. rank to array index
|
|
5117
|
+
n = arr.length,
|
|
5118
|
+
l = 0,
|
|
5119
|
+
m = n - 1,
|
|
5120
|
+
i, j, val, tmp;
|
|
5121
|
+
|
|
5122
|
+
while (l < m) {
|
|
5123
|
+
val = arr[k];
|
|
5124
|
+
i = l;
|
|
5125
|
+
j = m;
|
|
5126
|
+
do {
|
|
5127
|
+
while (arr[i] < val) {i++;}
|
|
5128
|
+
while (val < arr[j]) {j--;}
|
|
5129
|
+
if (i <= j) {
|
|
5130
|
+
tmp = arr[i];
|
|
5131
|
+
arr[i] = arr[j];
|
|
5132
|
+
arr[j] = tmp;
|
|
5133
|
+
i++;
|
|
5134
|
+
j--;
|
|
5135
|
+
}
|
|
5136
|
+
} while (i <= j);
|
|
5137
|
+
if (j < k) l = i;
|
|
5138
|
+
if (k < i) m = j;
|
|
5139
|
+
}
|
|
5140
|
+
return arr[k];
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
//
|
|
5144
|
+
//
|
|
5145
|
+
function findMedian(arr) {
|
|
5146
|
+
var n = arr.length,
|
|
5147
|
+
rank = Math.floor(n / 2) + 1,
|
|
5148
|
+
median = findValueByRank(arr, rank);
|
|
5149
|
+
if ((n & 1) == 0) {
|
|
5150
|
+
median = (median + findValueByRank(arr, rank - 1)) / 2;
|
|
5151
|
+
}
|
|
5152
|
+
return median;
|
|
5153
|
+
}
|
|
5154
|
+
|
|
5155
|
+
|
|
5156
|
+
function mean(arr) {
|
|
5157
|
+
var count = 0,
|
|
5158
|
+
avg = NaN,
|
|
5159
|
+
val;
|
|
5160
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
5161
|
+
val = arr[i];
|
|
5162
|
+
if (isNaN(val)) continue;
|
|
5163
|
+
avg = ++count == 1 ? val : val / count + (count - 1) / count * avg;
|
|
5164
|
+
}
|
|
5165
|
+
return avg;
|
|
5166
|
+
}
|
|
5167
|
+
|
|
5168
|
+
|
|
5169
|
+
/*
|
|
5170
|
+
A simplified version of printf formatting
|
|
5171
|
+
Format codes: %[flags][width][.precision]type
|
|
5172
|
+
|
|
5173
|
+
supported flags:
|
|
5174
|
+
+ add '+' before positive numbers
|
|
5175
|
+
0 left-pad with '0'
|
|
5176
|
+
' Add thousands separator
|
|
5177
|
+
width: 1 to many
|
|
5178
|
+
precision: .(1 to many)
|
|
5179
|
+
type:
|
|
5180
|
+
s string
|
|
5181
|
+
di integers
|
|
5182
|
+
f decimal numbers
|
|
5183
|
+
xX hexidecimal (unsigned)
|
|
5184
|
+
% literal '%'
|
|
5185
|
+
|
|
5186
|
+
Examples:
|
|
5187
|
+
code val formatted
|
|
5188
|
+
%+d 1 '+1'
|
|
5189
|
+
%4i 32 ' 32'
|
|
5190
|
+
%04i 32 '0032'
|
|
5191
|
+
%x 255 'ff'
|
|
5192
|
+
%.2f 0.125 '0.13'
|
|
5193
|
+
%'f 1000 '1,000'
|
|
5194
|
+
*/
|
|
5195
|
+
|
|
5196
|
+
// Usage: format(formatString, [values])
|
|
5197
|
+
// Tip: When reusing the same format many times, use formatter() for 5x - 10x better performance
|
|
5198
|
+
//
|
|
5199
|
+
function format(fmt) {
|
|
5200
|
+
var fn = formatter(fmt);
|
|
5201
|
+
var str = fn.apply(null, Array.prototype.slice.call(arguments, 1));
|
|
5202
|
+
return str;
|
|
5203
|
+
}
|
|
5204
|
+
|
|
5205
|
+
function formatValue(val, matches) {
|
|
5206
|
+
var flags = matches[1];
|
|
5207
|
+
var padding = matches[2];
|
|
5208
|
+
var decimals = matches[3] ? parseInt(matches[3].substr(1)) : void 0;
|
|
5209
|
+
var type = matches[4];
|
|
5210
|
+
var isString = type == 's',
|
|
5211
|
+
isHex = type == 'x' || type == 'X',
|
|
5212
|
+
isInt = type == 'd' || type == 'i',
|
|
5213
|
+
isFloat = type == 'f',
|
|
5214
|
+
isNumber = !isString;
|
|
5215
|
+
|
|
5216
|
+
var sign = "",
|
|
5217
|
+
padDigits = 0,
|
|
5218
|
+
isZero = false,
|
|
5219
|
+
isNeg = false;
|
|
5220
|
+
|
|
5221
|
+
var str, padChar, padStr;
|
|
5222
|
+
if (isString) {
|
|
5223
|
+
str = String(val);
|
|
5224
|
+
}
|
|
5225
|
+
else if (isHex) {
|
|
5226
|
+
str = val.toString(16);
|
|
5227
|
+
if (type == 'X')
|
|
5228
|
+
str = str.toUpperCase();
|
|
5229
|
+
}
|
|
5230
|
+
else if (isNumber) {
|
|
5231
|
+
// str = formatNumberForDisplay(val, isInt ? 0 : decimals);
|
|
5232
|
+
str = numToStr(val, decimals);
|
|
5233
|
+
if (str[0] == '-') {
|
|
5234
|
+
isNeg = true;
|
|
5235
|
+
str = str.substr(1);
|
|
5236
|
+
}
|
|
5237
|
+
isZero = parseFloat(str) == 0;
|
|
5238
|
+
if (flags.indexOf("'") != -1 || flags.indexOf(',') != -1) {
|
|
5239
|
+
str = addThousandsSep(str);
|
|
5240
|
+
}
|
|
5241
|
+
if (!isZero) { // BUG: sign is added when num rounds to 0
|
|
5242
|
+
if (isNeg) {
|
|
5243
|
+
sign = "\u2212"; // U+2212
|
|
5244
|
+
} else if (flags.indexOf('+') != -1) {
|
|
5245
|
+
sign = '+';
|
|
5246
|
+
}
|
|
5247
|
+
}
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
if (padding) {
|
|
5251
|
+
var strLen = str.length + sign.length;
|
|
5252
|
+
var minWidth = parseInt(padding, 10);
|
|
5253
|
+
if (strLen < minWidth) {
|
|
5254
|
+
padDigits = minWidth - strLen;
|
|
5255
|
+
padChar = flags.indexOf('0') == -1 ? ' ' : '0';
|
|
5256
|
+
padStr = repeatString(padChar, padDigits);
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
|
|
5260
|
+
if (padDigits == 0) {
|
|
5261
|
+
str = sign + str;
|
|
5262
|
+
} else if (padChar == '0') {
|
|
5263
|
+
str = sign + padStr + str;
|
|
5264
|
+
} else {
|
|
5265
|
+
str = padStr + sign + str;
|
|
5266
|
+
}
|
|
5267
|
+
return str;
|
|
5268
|
+
}
|
|
5269
|
+
|
|
5270
|
+
// Get a function for interpolating formatted values into a string.
|
|
5271
|
+
function formatter(fmt) {
|
|
5272
|
+
var codeRxp = /%([\',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
|
|
5273
|
+
var literals = [],
|
|
5274
|
+
formatCodes = [],
|
|
5275
|
+
startIdx = 0,
|
|
5276
|
+
prefix = "",
|
|
5277
|
+
matches = codeRxp.exec(fmt),
|
|
5278
|
+
literal;
|
|
5279
|
+
|
|
5280
|
+
while (matches) {
|
|
5281
|
+
literal = fmt.substring(startIdx, codeRxp.lastIndex - matches[0].length);
|
|
5282
|
+
if (matches[0] == '%%') {
|
|
5283
|
+
prefix += literal + '%';
|
|
5284
|
+
} else {
|
|
5285
|
+
literals.push(prefix + literal);
|
|
5286
|
+
prefix = '';
|
|
5287
|
+
formatCodes.push(matches);
|
|
5288
|
+
}
|
|
5289
|
+
startIdx = codeRxp.lastIndex;
|
|
5290
|
+
matches = codeRxp.exec(fmt);
|
|
5291
|
+
}
|
|
5292
|
+
literals.push(prefix + fmt.substr(startIdx));
|
|
5293
|
+
|
|
5294
|
+
return function() {
|
|
5295
|
+
var str = literals[0],
|
|
5296
|
+
n = arguments.length;
|
|
5297
|
+
if (n != formatCodes.length) {
|
|
5298
|
+
error("[format()] Data does not match format string; format:", fmt, "data:", arguments);
|
|
5299
|
+
}
|
|
5300
|
+
for (var i=0; i<n; i++) {
|
|
5301
|
+
str += formatValue(arguments[i], formatCodes[i]) + literals[i+1];
|
|
5302
|
+
}
|
|
5303
|
+
return str;
|
|
5304
|
+
};
|
|
5305
|
+
}
|
|
5306
|
+
|
|
5307
|
+
function wildcardToRegExp(name) {
|
|
5308
|
+
var rxp = name.split('*').map(function(str) {
|
|
5309
|
+
return regexEscape(str);
|
|
5310
|
+
}).join('.*');
|
|
5311
|
+
return new RegExp('^' + rxp + '$');
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5314
|
+
function createBuffer(arg, arg2) {
|
|
5315
|
+
if (isInteger(arg)) {
|
|
5316
|
+
return Buffer.allocUnsafe ? Buffer.allocUnsafe(arg) : new Buffer(arg);
|
|
5317
|
+
} else {
|
|
5318
|
+
// check allocUnsafe to make sure Buffer.from() will accept strings (it didn't before Node v5.10)
|
|
5319
|
+
return Buffer.from && Buffer.allocUnsafe ? Buffer.from(arg, arg2) : new Buffer(arg, arg2);
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
|
|
5323
|
+
function expandoBuffer(constructor, rate) {
|
|
5324
|
+
var capacity = 0,
|
|
5325
|
+
k = rate >= 1 ? rate : 1.2,
|
|
5326
|
+
buf;
|
|
5327
|
+
return function(size) {
|
|
5328
|
+
if (size > capacity) {
|
|
5329
|
+
capacity = Math.ceil(size * k);
|
|
5330
|
+
buf = constructor ? new constructor(capacity) : createBuffer(capacity);
|
|
5331
|
+
}
|
|
5332
|
+
return buf;
|
|
5333
|
+
};
|
|
5334
|
+
}
|
|
5335
|
+
|
|
5336
|
+
function copyElements(src, i, dest, j, n, rev) {
|
|
5337
|
+
var same = src == dest || src.buffer && src.buffer == dest.buffer;
|
|
5338
|
+
var inc = 1,
|
|
5339
|
+
offs = 0,
|
|
5340
|
+
k;
|
|
5341
|
+
if (rev) {
|
|
5342
|
+
if (same) error('copy error');
|
|
5343
|
+
inc = -1;
|
|
5344
|
+
offs = n - 1;
|
|
5345
|
+
}
|
|
5346
|
+
if (same && j > i) {
|
|
5347
|
+
for (k=n-1; k>=0; k--) {
|
|
5348
|
+
dest[j + k] = src[i + k];
|
|
5349
|
+
}
|
|
5350
|
+
} else {
|
|
5351
|
+
for (k=0; k<n; k++, offs += inc) {
|
|
5352
|
+
dest[k + j] = src[i + offs];
|
|
5353
|
+
}
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
|
|
5357
|
+
function extendBuffer(src, newLen, copyLen) {
|
|
5358
|
+
var len = Math.max(src.length, newLen);
|
|
5359
|
+
var n = copyLen || src.length;
|
|
5360
|
+
var dest = new src.constructor(len);
|
|
5361
|
+
copyElements(src, 0, dest, 0, n);
|
|
5362
|
+
return dest;
|
|
5363
|
+
}
|
|
5364
|
+
|
|
5365
|
+
function mergeNames(name1, name2) {
|
|
5366
|
+
var merged;
|
|
5367
|
+
if (name1 && name2) {
|
|
5368
|
+
merged = findStringPrefix(name1, name2).replace(/[-_]$/, '');
|
|
5369
|
+
}
|
|
5370
|
+
return merged || '';
|
|
5371
|
+
}
|
|
5372
|
+
|
|
5373
|
+
function findStringPrefix(a, b) {
|
|
5374
|
+
var i = 0;
|
|
5375
|
+
for (var n=a.length; i<n; i++) {
|
|
5376
|
+
if (a[i] !== b[i]) break;
|
|
5377
|
+
}
|
|
5378
|
+
return a.substr(0, i);
|
|
5379
|
+
}
|
|
5380
|
+
|
|
5381
|
+
function parsePercent(o) {
|
|
5382
|
+
var str = String(o);
|
|
5383
|
+
var isPct = str.indexOf('%') > 0;
|
|
5384
|
+
var pct;
|
|
5385
|
+
if (isPct) {
|
|
5386
|
+
pct = Number(str.replace('%', '')) / 100;
|
|
5387
|
+
} else {
|
|
5388
|
+
pct = Number(str);
|
|
5389
|
+
}
|
|
5390
|
+
if (!(pct >= 0 && pct <= 1)) {
|
|
5391
|
+
stop(format("Invalid percentage: %s", str));
|
|
5392
|
+
}
|
|
5393
|
+
return pct;
|
|
5394
|
+
}
|
|
5395
|
+
|
|
5396
|
+
function formatVersionedName(name, i) {
|
|
5397
|
+
var suffix = String(i);
|
|
5398
|
+
if (/[0-9]$/.test(name)) {
|
|
5399
|
+
suffix = '-' + suffix;
|
|
5400
|
+
}
|
|
5401
|
+
return name + suffix;
|
|
5402
|
+
}
|
|
5403
|
+
|
|
5404
|
+
function uniqifyNames(names, formatter) {
|
|
5405
|
+
var counts = countValues(names),
|
|
5406
|
+
format = formatter || formatVersionedName,
|
|
5407
|
+
names2 = [];
|
|
5408
|
+
|
|
5409
|
+
names.forEach(function(name) {
|
|
5410
|
+
var i = 0,
|
|
5411
|
+
candidate = name,
|
|
5412
|
+
versionedName;
|
|
5413
|
+
while (
|
|
5414
|
+
names2.indexOf(candidate) > -1 || // candidate name has already been used
|
|
5415
|
+
candidate == name && counts[candidate] > 1 || // duplicate unversioned names
|
|
5416
|
+
candidate != name && counts[candidate] > 0) { // versioned name is a preexisting name
|
|
5417
|
+
i++;
|
|
5418
|
+
versionedName = format(name, i);
|
|
5419
|
+
if (!versionedName || versionedName == candidate) {
|
|
5420
|
+
throw new Error("Naming error"); // catch buggy versioning function
|
|
5421
|
+
}
|
|
5422
|
+
candidate = versionedName;
|
|
5423
|
+
}
|
|
5424
|
+
names2.push(candidate);
|
|
5425
|
+
});
|
|
5426
|
+
return names2;
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
|
|
5430
|
+
// Assume: @raw is string, undefined or null
|
|
5431
|
+
function parseString(raw) {
|
|
5432
|
+
return raw ? raw : "";
|
|
5433
|
+
}
|
|
5434
|
+
|
|
5435
|
+
// Assume: @raw is string, undefined or null
|
|
5436
|
+
// Use null instead of NaN for unparsable values
|
|
5437
|
+
// (in part because if NaN is used, empty strings get converted to "NaN"
|
|
5438
|
+
// when re-exported).
|
|
5439
|
+
function parseNumber(raw) {
|
|
5440
|
+
return parseToNum(raw, cleanNumericString);
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5443
|
+
function parseIntlNumber(raw) {
|
|
5444
|
+
return parseToNum(raw, convertIntlNumString);
|
|
5445
|
+
}
|
|
5446
|
+
|
|
5447
|
+
function parseToNum(raw, clean) {
|
|
5448
|
+
var str = String(raw).trim();
|
|
5449
|
+
var parsed = str ? Number(clean(str)) : NaN;
|
|
5450
|
+
return isNaN(parsed) ? null : parsed;
|
|
5451
|
+
}
|
|
5452
|
+
|
|
5453
|
+
// Remove comma separators from strings
|
|
5454
|
+
function cleanNumericString(str) {
|
|
5455
|
+
return (str.indexOf(',') > 0) ? str.replace(/,([0-9]{3})/g, '$1') : str;
|
|
5456
|
+
}
|
|
5457
|
+
|
|
5458
|
+
function convertIntlNumString(str) {
|
|
5459
|
+
str = str.replace(/[ .]([0-9]{3})/g, '$1');
|
|
5460
|
+
return str.replace(',', '.');
|
|
5461
|
+
}
|
|
5462
|
+
|
|
5463
|
+
function trimQuotes(raw) {
|
|
5464
|
+
var len = raw.length, first, last;
|
|
5465
|
+
if (len >= 2) {
|
|
5466
|
+
first = raw.charAt(0);
|
|
5467
|
+
last = raw.charAt(len-1);
|
|
5468
|
+
if (first == '"' && last == '"' && !raw.includes('","') ||
|
|
5469
|
+
first == "'" && last == "'" && !raw.includes("','")) {
|
|
5470
|
+
return raw.substr(1, len-2);
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
return raw;
|
|
5474
|
+
}
|
|
5475
|
+
|
|
4109
5476
|
function absArcId(arcId) {
|
|
4110
5477
|
return arcId >= 0 ? arcId : ~arcId;
|
|
4111
5478
|
}
|
|
@@ -4129,6 +5496,61 @@
|
|
|
4129
5496
|
return [xmin, ymin, xmax, ymax];
|
|
4130
5497
|
}
|
|
4131
5498
|
|
|
5499
|
+
function deleteVertex(arcs, i) {
|
|
5500
|
+
var data = arcs.getVertexData();
|
|
5501
|
+
var nn = data.nn;
|
|
5502
|
+
var n = data.xx.length;
|
|
5503
|
+
// avoid re-allocating memory
|
|
5504
|
+
var xx2 = new Float64Array(data.xx.buffer, 0, n-1);
|
|
5505
|
+
var yy2 = new Float64Array(data.yy.buffer, 0, n-1);
|
|
5506
|
+
var count = 0;
|
|
5507
|
+
var found = false;
|
|
5508
|
+
for (var j=0; j<nn.length; j++) {
|
|
5509
|
+
count += nn[j];
|
|
5510
|
+
if (count >= i && !found) { // TODO: confirm this
|
|
5511
|
+
nn[j] = nn[j] - 1;
|
|
5512
|
+
found = true;
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
utils.copyElements(data.xx, 0, xx2, 0, i);
|
|
5516
|
+
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
5517
|
+
utils.copyElements(data.xx, i+1, xx2, i, n-i-1);
|
|
5518
|
+
utils.copyElements(data.yy, i+1, yy2, i, n-i-1);
|
|
5519
|
+
arcs.updateVertexData(nn, xx2, yy2, null);
|
|
5520
|
+
}
|
|
5521
|
+
|
|
5522
|
+
function insertVertex(arcs, i, p) {
|
|
5523
|
+
// TODO: add extra bytes to the buffers, to reduce new memory allocation
|
|
5524
|
+
var data = arcs.getVertexData();
|
|
5525
|
+
var nn = data.nn;
|
|
5526
|
+
var n = data.xx.length;
|
|
5527
|
+
var count = 0;
|
|
5528
|
+
var found = false;
|
|
5529
|
+
var xx2, yy2;
|
|
5530
|
+
// avoid re-allocating memory on each insertion
|
|
5531
|
+
if (data.xx.buffer.byteLength >= data.xx.length * 8 + 8) {
|
|
5532
|
+
xx2 = new Float64Array(data.xx.buffer, 0, n+1);
|
|
5533
|
+
yy2 = new Float64Array(data.yy.buffer, 0, n+1);
|
|
5534
|
+
} else {
|
|
5535
|
+
xx2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
|
|
5536
|
+
yy2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
|
|
5537
|
+
}
|
|
5538
|
+
for (var j=0; j<nn.length; j++) {
|
|
5539
|
+
count += nn[j];
|
|
5540
|
+
if (count >= i && !found) { // TODO: confirm this
|
|
5541
|
+
nn[j] = nn[j] + 1;
|
|
5542
|
+
found = true;
|
|
5543
|
+
}
|
|
5544
|
+
}
|
|
5545
|
+
utils.copyElements(data.xx, 0, xx2, 0, i);
|
|
5546
|
+
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
5547
|
+
utils.copyElements(data.xx, i, xx2, i+1, n-i);
|
|
5548
|
+
utils.copyElements(data.yy, i, yy2, i+1, n-i);
|
|
5549
|
+
xx2[i] = p[0];
|
|
5550
|
+
yy2[i] = p[1];
|
|
5551
|
+
arcs.updateVertexData(nn, xx2, yy2, null);
|
|
5552
|
+
}
|
|
5553
|
+
|
|
4132
5554
|
function getShapeHitTest(displayLayer, ext, interactionMode) {
|
|
4133
5555
|
var geoType = displayLayer.layer.geometry_type;
|
|
4134
5556
|
var test;
|
|
@@ -4143,7 +5565,7 @@
|
|
|
4143
5565
|
} else if (geoType == 'polygon') {
|
|
4144
5566
|
test = polygonTest;
|
|
4145
5567
|
} else {
|
|
4146
|
-
error("Unexpected geometry type:", geoType);
|
|
5568
|
+
error$1("Unexpected geometry type:", geoType);
|
|
4147
5569
|
}
|
|
4148
5570
|
return test;
|
|
4149
5571
|
|
|
@@ -4179,7 +5601,7 @@
|
|
|
4179
5601
|
hits = pickNearestCandidates(cands, 0, maxDist);
|
|
4180
5602
|
}
|
|
4181
5603
|
return {
|
|
4182
|
-
ids: utils.pluck(hits, 'id')
|
|
5604
|
+
ids: utils$1.pluck(hits, 'id')
|
|
4183
5605
|
};
|
|
4184
5606
|
}
|
|
4185
5607
|
|
|
@@ -4201,15 +5623,15 @@
|
|
|
4201
5623
|
}
|
|
4202
5624
|
|
|
4203
5625
|
function vertexTest(x, y) {
|
|
4204
|
-
var maxDist = getZoomAdjustedHitBuffer(
|
|
5626
|
+
var maxDist = getZoomAdjustedHitBuffer(20, 2),
|
|
4205
5627
|
bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
|
|
4206
5628
|
cands = findHitCandidates(x, y, maxDist);
|
|
4207
5629
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4208
5630
|
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
4209
5631
|
var arcs = cands.map(function(cand) { return absArcId(cand.info.arcId); });
|
|
4210
5632
|
return {
|
|
4211
|
-
arcs: utils.uniq(arcs),
|
|
4212
|
-
ids: utils.pluck(cands, 'id')
|
|
5633
|
+
arcs: utils$1.uniq(arcs),
|
|
5634
|
+
ids: utils$1.pluck(cands, 'id')
|
|
4213
5635
|
};
|
|
4214
5636
|
}
|
|
4215
5637
|
|
|
@@ -4220,7 +5642,7 @@
|
|
|
4220
5642
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4221
5643
|
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
4222
5644
|
return {
|
|
4223
|
-
ids: utils.pluck(cands, 'id')
|
|
5645
|
+
ids: utils$1.pluck(cands, 'id')
|
|
4224
5646
|
};
|
|
4225
5647
|
}
|
|
4226
5648
|
|
|
@@ -4231,7 +5653,7 @@
|
|
|
4231
5653
|
cand.info = geom.getPointToShapeInfo(x, y, cands[i].shape, arcs);
|
|
4232
5654
|
cand.dist = cand.info.distance;
|
|
4233
5655
|
}
|
|
4234
|
-
utils.sortOn(cands, 'dist');
|
|
5656
|
+
utils$1.sortOn(cands, 'dist');
|
|
4235
5657
|
}
|
|
4236
5658
|
|
|
4237
5659
|
function pointTest(x, y) {
|
|
@@ -4258,7 +5680,7 @@
|
|
|
4258
5680
|
});
|
|
4259
5681
|
// console.log(hitThreshold, bullseye);
|
|
4260
5682
|
return {
|
|
4261
|
-
ids: utils.uniq(hits) // multipoint features can register multiple hits
|
|
5683
|
+
ids: utils$1.uniq(hits) // multipoint features can register multiple hits
|
|
4262
5684
|
};
|
|
4263
5685
|
}
|
|
4264
5686
|
|
|
@@ -4466,9 +5888,9 @@
|
|
|
4466
5888
|
var data = shapeTest(p[0], p[1]) || {ids:[]};
|
|
4467
5889
|
var svgData = svgTest(e); // null or a data object
|
|
4468
5890
|
if (svgData) { // mouse is over an SVG symbol
|
|
4469
|
-
utils.extend(data, svgData);
|
|
5891
|
+
utils$1.extend(data, svgData);
|
|
4470
5892
|
// placing symbol id in front of any other hits
|
|
4471
|
-
data.ids = utils.uniq([svgData.targetId].concat(data.ids));
|
|
5893
|
+
data.ids = utils$1.uniq([svgData.targetId].concat(data.ids));
|
|
4472
5894
|
}
|
|
4473
5895
|
data.id = data.ids.length > 0 ? data.ids[0] : -1;
|
|
4474
5896
|
return data;
|
|
@@ -4572,8 +5994,8 @@
|
|
|
4572
5994
|
|
|
4573
5995
|
self.addSelectionIds = function(ids) {
|
|
4574
5996
|
turnOn('selection');
|
|
4575
|
-
selectionIds = utils.uniq(selectionIds.concat(ids));
|
|
4576
|
-
ids = utils.uniq(storedData.ids.concat(ids));
|
|
5997
|
+
selectionIds = utils$1.uniq(selectionIds.concat(ids));
|
|
5998
|
+
ids = utils$1.uniq(storedData.ids.concat(ids));
|
|
4577
5999
|
updateSelectionState({ids: ids});
|
|
4578
6000
|
};
|
|
4579
6001
|
|
|
@@ -4746,7 +6168,7 @@
|
|
|
4746
6168
|
|
|
4747
6169
|
function toggleId(id, ids) {
|
|
4748
6170
|
if (ids.indexOf(id) > -1) {
|
|
4749
|
-
return utils.difference(ids, [id]);
|
|
6171
|
+
return utils$1.difference(ids, [id]);
|
|
4750
6172
|
}
|
|
4751
6173
|
return [id].concat(ids);
|
|
4752
6174
|
}
|
|
@@ -4760,9 +6182,11 @@
|
|
|
4760
6182
|
newData = noHitData();
|
|
4761
6183
|
selectionIds = [];
|
|
4762
6184
|
}
|
|
6185
|
+
|
|
4763
6186
|
if (!testHitChange(storedData, newData)) {
|
|
4764
6187
|
return;
|
|
4765
6188
|
}
|
|
6189
|
+
|
|
4766
6190
|
storedData = newData;
|
|
4767
6191
|
gui.container.findChild('.map-layers').classed('symbol-hit', nonEmpty);
|
|
4768
6192
|
if (active) {
|
|
@@ -4798,9 +6222,9 @@
|
|
|
4798
6222
|
// d: event data (may be a pointer event object, an ordinary object or null)
|
|
4799
6223
|
function triggerHitEvent(type, d) {
|
|
4800
6224
|
// Merge stored hit data into the event data
|
|
4801
|
-
var eventData = utils.extend({mode: interactionMode}, d || {}, storedData);
|
|
6225
|
+
var eventData = utils$1.extend({mode: interactionMode}, d || {}, storedData);
|
|
4802
6226
|
if (transientIds.length) {
|
|
4803
|
-
eventData.ids = utils.uniq(transientIds.concat(eventData.ids || []));
|
|
6227
|
+
eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
|
|
4804
6228
|
}
|
|
4805
6229
|
self.dispatchEvent(type, eventData);
|
|
4806
6230
|
}
|
|
@@ -4934,7 +6358,7 @@
|
|
|
4934
6358
|
}
|
|
4935
6359
|
}
|
|
4936
6360
|
|
|
4937
|
-
utils.inherit(Timer, EventDispatcher);
|
|
6361
|
+
utils$1.inherit(Timer, EventDispatcher);
|
|
4938
6362
|
|
|
4939
6363
|
function Tween(ease) {
|
|
4940
6364
|
var self = this,
|
|
@@ -4956,7 +6380,7 @@
|
|
|
4956
6380
|
}
|
|
4957
6381
|
}
|
|
4958
6382
|
|
|
4959
|
-
utils.inherit(Tween, EventDispatcher);
|
|
6383
|
+
utils$1.inherit(Tween, EventDispatcher);
|
|
4960
6384
|
|
|
4961
6385
|
Tween.sineInOut = function(n) {
|
|
4962
6386
|
return 0.5 - Math.cos(n * Math.PI) / 2;
|
|
@@ -5024,7 +6448,7 @@
|
|
|
5024
6448
|
update();
|
|
5025
6449
|
}
|
|
5026
6450
|
|
|
5027
|
-
utils.inherit(ElementPosition, EventDispatcher);
|
|
6451
|
+
utils$1.inherit(ElementPosition, EventDispatcher);
|
|
5028
6452
|
|
|
5029
6453
|
function MouseWheelDirection() {
|
|
5030
6454
|
var prevTime = 0;
|
|
@@ -5122,13 +6546,13 @@
|
|
|
5122
6546
|
// Decelerate towards the end of the sustain interval (for smoother zooming)
|
|
5123
6547
|
multiplier *= Tween.quadraticOut(1 - fadeFactor);
|
|
5124
6548
|
}
|
|
5125
|
-
obj = utils.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
6549
|
+
obj = utils$1.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
5126
6550
|
self.dispatchEvent('mousewheel', obj);
|
|
5127
6551
|
}
|
|
5128
6552
|
}
|
|
5129
6553
|
}
|
|
5130
6554
|
|
|
5131
|
-
utils.inherit(MouseWheel, EventDispatcher);
|
|
6555
|
+
utils$1.inherit(MouseWheel, EventDispatcher);
|
|
5132
6556
|
|
|
5133
6557
|
|
|
5134
6558
|
function MouseArea(element, pos) {
|
|
@@ -5182,7 +6606,7 @@
|
|
|
5182
6606
|
};
|
|
5183
6607
|
|
|
5184
6608
|
this.mouseData = function() {
|
|
5185
|
-
return utils.extend({}, _prevEvt);
|
|
6609
|
+
return utils$1.extend({}, _prevEvt);
|
|
5186
6610
|
};
|
|
5187
6611
|
|
|
5188
6612
|
function onAreaDown(e) {
|
|
@@ -5241,7 +6665,7 @@
|
|
|
5241
6665
|
dragX: evt.pageX - _downEvt.pageX,
|
|
5242
6666
|
dragY: evt.pageY - _downEvt.pageY
|
|
5243
6667
|
};
|
|
5244
|
-
_self.dispatchEvent('drag', utils.extend(obj, evt));
|
|
6668
|
+
_self.dispatchEvent('drag', utils$1.extend(obj, evt));
|
|
5245
6669
|
} else {
|
|
5246
6670
|
_self.dispatchEvent('hover', evt);
|
|
5247
6671
|
}
|
|
@@ -5273,7 +6697,7 @@
|
|
|
5273
6697
|
}
|
|
5274
6698
|
}
|
|
5275
6699
|
|
|
5276
|
-
utils.inherit(MouseArea, EventDispatcher);
|
|
6700
|
+
utils$1.inherit(MouseArea, EventDispatcher);
|
|
5277
6701
|
|
|
5278
6702
|
function initVariableClick(node, cb) {
|
|
5279
6703
|
var downEvent = null;
|
|
@@ -5420,7 +6844,7 @@
|
|
|
5420
6844
|
maxScale = 4,
|
|
5421
6845
|
minTime = 100,
|
|
5422
6846
|
maxTime = 800,
|
|
5423
|
-
time = utils.clamp(clickTime || 200, minTime, maxTime),
|
|
6847
|
+
time = utils$1.clamp(clickTime || 200, minTime, maxTime),
|
|
5424
6848
|
k = (time - minTime) / (maxTime - minTime),
|
|
5425
6849
|
scale = minScale + k * (maxScale - minScale);
|
|
5426
6850
|
return 1 + scale * zoomScaleMultiplier;
|
|
@@ -5647,7 +7071,7 @@
|
|
|
5647
7071
|
rows = 0;
|
|
5648
7072
|
// self.hide(); // clean up if panel is already open
|
|
5649
7073
|
el.empty(); // clean up if panel is already open
|
|
5650
|
-
utils.forEachProperty(rec, function(v, k) {
|
|
7074
|
+
utils$1.forEachProperty(rec, function(v, k) {
|
|
5651
7075
|
var type;
|
|
5652
7076
|
// missing GeoJSON fields are set to undefined on import; skip these
|
|
5653
7077
|
if (v !== undefined) {
|
|
@@ -5675,7 +7099,7 @@
|
|
|
5675
7099
|
// Some individual features can have undefined values for some or all of
|
|
5676
7100
|
// their data properties (properties are set to undefined when an input JSON file
|
|
5677
7101
|
// has inconsistent fields, or after force-merging layers with inconsistent fields).
|
|
5678
|
-
el.html(utils.format('<div class="note">This %s is missing attribute data.</div>',
|
|
7102
|
+
el.html(utils$1.format('<div class="note">This %s is missing attribute data.</div>',
|
|
5679
7103
|
table && table.getFields().length > 0 ? 'feature': 'layer'));
|
|
5680
7104
|
}
|
|
5681
7105
|
}
|
|
@@ -5686,7 +7110,7 @@
|
|
|
5686
7110
|
var str = formatInspectorValue(val, type);
|
|
5687
7111
|
var cell = El('tr')
|
|
5688
7112
|
.appendTo(table)
|
|
5689
|
-
.html(utils.format(rowHtml, key, utils.htmlEscape(str)))
|
|
7113
|
+
.html(utils$1.format(rowHtml, key, utils$1.htmlEscape(str)))
|
|
5690
7114
|
.findChild('.value');
|
|
5691
7115
|
setFieldClass(cell, val, type);
|
|
5692
7116
|
if (editable) {
|
|
@@ -5695,7 +7119,7 @@
|
|
|
5695
7119
|
}
|
|
5696
7120
|
|
|
5697
7121
|
function setFieldClass(el, val, type) {
|
|
5698
|
-
var isNum = type ? type == 'number' : utils.isNumber(val);
|
|
7122
|
+
var isNum = type ? type == 'number' : utils$1.isNumber(val);
|
|
5699
7123
|
var isNully = val === undefined || val === null || val !== val;
|
|
5700
7124
|
var isEmpty = val === '';
|
|
5701
7125
|
el.classed('num-field', isNum);
|
|
@@ -5735,7 +7159,7 @@
|
|
|
5735
7159
|
function formatInspectorValue(val, type) {
|
|
5736
7160
|
var str;
|
|
5737
7161
|
if (type == 'date') {
|
|
5738
|
-
str = utils.formatDateISO(val);
|
|
7162
|
+
str = utils$1.formatDateISO(val);
|
|
5739
7163
|
} else if (type == 'object') {
|
|
5740
7164
|
str = val ? JSON.stringify(val) : "";
|
|
5741
7165
|
} else {
|
|
@@ -5934,7 +7358,7 @@
|
|
|
5934
7358
|
// handle either numeric strings or numbers in fields
|
|
5935
7359
|
function applyDelta(rec, key, delta) {
|
|
5936
7360
|
var currVal = rec[key];
|
|
5937
|
-
var isString = utils.isString(currVal);
|
|
7361
|
+
var isString = utils$1.isString(currVal);
|
|
5938
7362
|
var newVal = (+currVal + delta) || 0;
|
|
5939
7363
|
rec[key] = isString ? String(newVal) : newVal;
|
|
5940
7364
|
}
|
|
@@ -5962,7 +7386,7 @@
|
|
|
5962
7386
|
hit.on('drag', function(e) {
|
|
5963
7387
|
if (!active(e)) return;
|
|
5964
7388
|
if (e.id != activeId) {
|
|
5965
|
-
error("Mismatched hit ids:", e.id, activeId);
|
|
7389
|
+
error$1("Mismatched hit ids:", e.id, activeId);
|
|
5966
7390
|
}
|
|
5967
7391
|
var scale = ext.getSymbolScale() || 1;
|
|
5968
7392
|
var textNode;
|
|
@@ -6112,20 +7536,20 @@
|
|
|
6112
7536
|
}
|
|
6113
7537
|
}
|
|
6114
7538
|
|
|
7539
|
+
// pointer thresholds for hovering near a vertex or segment midpoint
|
|
7540
|
+
var HOVER_THRESHOLD = 8;
|
|
7541
|
+
var MIDPOINT_THRESHOLD = 12;
|
|
7542
|
+
|
|
6115
7543
|
function initVertexDragging(gui, ext, hit) {
|
|
6116
|
-
var
|
|
6117
|
-
var
|
|
6118
|
-
var selectedVertexIds = null;
|
|
7544
|
+
var activeMidpoint;
|
|
7545
|
+
var dragInfo;
|
|
6119
7546
|
|
|
6120
|
-
function active(
|
|
6121
|
-
return
|
|
7547
|
+
function active() {
|
|
7548
|
+
return gui.interaction.getMode() == 'vertices';
|
|
6122
7549
|
}
|
|
6123
7550
|
|
|
6124
|
-
function
|
|
6125
|
-
|
|
6126
|
-
FID: activeShapeId,
|
|
6127
|
-
vertex_ids: draggedVertexIds
|
|
6128
|
-
});
|
|
7551
|
+
function dragging() {
|
|
7552
|
+
return active() && !!dragInfo;
|
|
6129
7553
|
}
|
|
6130
7554
|
|
|
6131
7555
|
function setHoverVertex(id) {
|
|
@@ -6146,70 +7570,134 @@
|
|
|
6146
7570
|
var p2 = target.arcs.getVertex2(nearestIds[0]);
|
|
6147
7571
|
var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
|
|
6148
7572
|
var pixelDist = dist / ext.getPixelSize();
|
|
6149
|
-
if (pixelDist >
|
|
6150
|
-
draggedVertexIds = null;
|
|
7573
|
+
if (pixelDist > HOVER_THRESHOLD) {
|
|
6151
7574
|
return null;
|
|
6152
7575
|
}
|
|
6153
|
-
return
|
|
7576
|
+
var points = nearestIds.map(function(i) {return target.arcs.getVertex2(i);});
|
|
7577
|
+
return {
|
|
7578
|
+
ids: nearestIds,
|
|
7579
|
+
points: points
|
|
7580
|
+
};
|
|
6154
7581
|
}
|
|
6155
7582
|
|
|
6156
7583
|
hit.on('dragstart', function(e) {
|
|
6157
|
-
if (!active(
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
7584
|
+
if (!active()) return;
|
|
7585
|
+
if (activeMidpoint) {
|
|
7586
|
+
var target = hit.getHitTarget();
|
|
7587
|
+
internal.insertVertex(target.arcs, activeMidpoint.i, activeMidpoint.point);
|
|
7588
|
+
dragInfo = {
|
|
7589
|
+
insertion: true,
|
|
7590
|
+
ids: [activeMidpoint.i],
|
|
7591
|
+
points: [activeMidpoint.point]
|
|
7592
|
+
};
|
|
7593
|
+
activeMidpoint = null;
|
|
7594
|
+
} else {
|
|
7595
|
+
dragInfo = findDraggableVertices(e);
|
|
7596
|
+
}
|
|
7597
|
+
if (dragInfo) {
|
|
7598
|
+
setHoverVertex(dragInfo.ids[0]);
|
|
7599
|
+
}
|
|
6163
7600
|
});
|
|
6164
7601
|
|
|
6165
7602
|
hit.on('drag', function(e) {
|
|
6166
|
-
if (!
|
|
7603
|
+
if (!dragging()) return;
|
|
6167
7604
|
var target = hit.getHitTarget();
|
|
6168
7605
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6169
7606
|
if (gui.keyboard.shiftIsPressed()) {
|
|
6170
|
-
internal.snapPointToArcEndpoint(p,
|
|
7607
|
+
internal.snapPointToArcEndpoint(p, dragInfo.ids, target.arcs);
|
|
6171
7608
|
}
|
|
6172
|
-
internal.snapVerticesToPoint(
|
|
6173
|
-
setHoverVertex(
|
|
7609
|
+
internal.snapVerticesToPoint(dragInfo.ids, p, target.arcs);
|
|
7610
|
+
setHoverVertex(dragInfo.ids[0]);
|
|
6174
7611
|
// redrawing the whole map updates the data layer as well as the overlay layer
|
|
6175
7612
|
// gui.dispatchEvent('map-needs-refresh');
|
|
6176
7613
|
});
|
|
6177
7614
|
|
|
6178
7615
|
hit.on('dragend', function(e) {
|
|
6179
|
-
if (!
|
|
7616
|
+
if (!dragging()) return;
|
|
6180
7617
|
// kludge to get dataset to recalculate internal bounding boxes
|
|
6181
7618
|
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
6182
7619
|
clearHoverVertex();
|
|
6183
|
-
|
|
6184
|
-
draggedVertexIds = null;
|
|
6185
|
-
activeShapeId = -1;
|
|
6186
|
-
// redraw data layer
|
|
7620
|
+
gui.dispatchEvent('vertex_dragend', dragInfo);
|
|
6187
7621
|
gui.dispatchEvent('map-needs-refresh');
|
|
7622
|
+
dragInfo = null;
|
|
6188
7623
|
});
|
|
6189
7624
|
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
7625
|
+
hit.on('dblclick', function(e) {
|
|
7626
|
+
if (!active()) return;
|
|
7627
|
+
var info = findDraggableVertices(e); // same selection criteria as for dragging
|
|
7628
|
+
if (!info) return;
|
|
7629
|
+
var target = hit.getHitTarget();
|
|
7630
|
+
var vId = info.ids[0];
|
|
7631
|
+
if (internal.vertexIsArcStart(vId, target.arcs) ||
|
|
7632
|
+
internal.vertexIsArcEnd(vId, target.arcs)) {
|
|
7633
|
+
// TODO: support removing arc endpoints
|
|
7634
|
+
return;
|
|
7635
|
+
}
|
|
7636
|
+
gui.dispatchEvent('vertex_delete', {
|
|
7637
|
+
vertex_id: vId
|
|
7638
|
+
});
|
|
7639
|
+
internal.deleteVertex(target.arcs, vId);
|
|
7640
|
+
clearHoverVertex();
|
|
7641
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
6195
7642
|
});
|
|
6196
7643
|
|
|
6197
7644
|
// highlight hit vertex in path edit mode
|
|
6198
7645
|
hit.on('hover', function(e) {
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
7646
|
+
activeMidpoint = null;
|
|
7647
|
+
if (!active() || dragging()) return; // no hover effect while dragging
|
|
7648
|
+
var info = findDraggableVertices(e);
|
|
7649
|
+
if (info) {
|
|
7650
|
+
// hovering near a vertex: highlight the vertex
|
|
7651
|
+
setHoverVertex(info.ids[0]);
|
|
6203
7652
|
return;
|
|
6204
7653
|
}
|
|
7654
|
+
// if hovering near a segment midpoint: show the midpoint and save midpoint info
|
|
7655
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6205
7656
|
var target = hit.getHitTarget();
|
|
6206
7657
|
var shp = target.layer.shapes[e.id];
|
|
6207
|
-
var
|
|
6208
|
-
|
|
6209
|
-
|
|
7658
|
+
var midpoint = findNearestMidpoint(p, shp, target.arcs);
|
|
7659
|
+
if (midpoint &&
|
|
7660
|
+
midpoint.distance / ext.getPixelSize() < MIDPOINT_THRESHOLD &&
|
|
7661
|
+
target.arcs.isFlat()) { // vertex insertion not supported with simplification
|
|
7662
|
+
hit.setHoverVertex(midpoint.point);
|
|
7663
|
+
activeMidpoint = midpoint;
|
|
7664
|
+
return;
|
|
7665
|
+
}
|
|
7666
|
+
// pointer is not over a vertex or midpoint: clear hover effect
|
|
6210
7667
|
clearHoverVertex();
|
|
6211
7668
|
}, null, 100);
|
|
7669
|
+
}
|
|
6212
7670
|
|
|
7671
|
+
// Given a location @p (e.g. corresponding to the mouse pointer location),
|
|
7672
|
+
// find the midpoint of two vertices on @shp suitable for inserting a new vertex,
|
|
7673
|
+
// but only if:
|
|
7674
|
+
// 1. point @p is closer to the midpoint than either adjacent vertex
|
|
7675
|
+
// 2. the segment containing @p is longer than a minimum distance in pixels.
|
|
7676
|
+
//
|
|
7677
|
+
function findNearestMidpoint(p, shp, arcs) {
|
|
7678
|
+
// var v1 = internal.findNearestVertex(p[0], p[1], shp, arcs);
|
|
7679
|
+
// var v0 = internal.findAdjacentVertex(v1, shp, arcs, -1);
|
|
7680
|
+
// var v2 = internal.findAdjacentVertex(v1, shp, arcs, 1);
|
|
7681
|
+
var minDist = Infinity, v;
|
|
7682
|
+
internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
|
|
7683
|
+
var x1 = xx[i],
|
|
7684
|
+
y1 = yy[i],
|
|
7685
|
+
x2 = xx[j],
|
|
7686
|
+
y2 = yy[j],
|
|
7687
|
+
cx = (x1 + x2) / 2,
|
|
7688
|
+
cy = (y1 + y2) / 2,
|
|
7689
|
+
dist = geom.distance2D(cx, cy, p[0], p[1]);
|
|
7690
|
+
if (dist < minDist) {
|
|
7691
|
+
minDist = dist;
|
|
7692
|
+
v = {
|
|
7693
|
+
i: (i < j ? i : j) + 1, // insertion point
|
|
7694
|
+
segment: [i, j],
|
|
7695
|
+
point: [cx, cy],
|
|
7696
|
+
distance: dist
|
|
7697
|
+
};
|
|
7698
|
+
}
|
|
7699
|
+
});
|
|
7700
|
+
return v || null;
|
|
6213
7701
|
}
|
|
6214
7702
|
|
|
6215
7703
|
function initInteractiveEditing(gui, ext, hit) {
|
|
@@ -6252,7 +7740,7 @@
|
|
|
6252
7740
|
},
|
|
6253
7741
|
referenceStyle = { // outline style for reference layers
|
|
6254
7742
|
type: 'outline',
|
|
6255
|
-
strokeColors: [null, '#
|
|
7743
|
+
strokeColors: [null, '#78c110'], // upped saturation from #86c927
|
|
6256
7744
|
strokeWidth: 0.85,
|
|
6257
7745
|
dotColor: "#73ba20",
|
|
6258
7746
|
dotSize: 1
|
|
@@ -6333,7 +7821,7 @@
|
|
|
6333
7821
|
}
|
|
6334
7822
|
|
|
6335
7823
|
function getDefaultStyle(lyr, baseStyle) {
|
|
6336
|
-
var style = utils.extend({}, baseStyle);
|
|
7824
|
+
var style = utils$1.extend({}, baseStyle);
|
|
6337
7825
|
// reduce the dot size of large point layers
|
|
6338
7826
|
if (lyr.geometry_type == 'point' && style.dotSize > 0) {
|
|
6339
7827
|
style.dotSize *= getDotScale$1(lyr);
|
|
@@ -6399,11 +7887,12 @@
|
|
|
6399
7887
|
var topId = o.id; // pinned id (if pinned) or hover id
|
|
6400
7888
|
var topIdx = -1;
|
|
6401
7889
|
var styler = function(style, i) {
|
|
6402
|
-
utils.extend(style, i === topIdx ? topStyle: baseStyle);
|
|
7890
|
+
utils$1.extend(style, i === topIdx ? topStyle: baseStyle);
|
|
6403
7891
|
// kludge to show vertices when editing path shapes
|
|
6404
7892
|
if (o.mode == 'vertices') {
|
|
6405
7893
|
style.vertices = true;
|
|
6406
7894
|
style.vertex_overlay = o.hit_coordinates || null;
|
|
7895
|
+
style.selected_points = o.selected_points || null;
|
|
6407
7896
|
style.fillColor = null;
|
|
6408
7897
|
}
|
|
6409
7898
|
};
|
|
@@ -6412,7 +7901,7 @@
|
|
|
6412
7901
|
var ids = o.ids.filter(function(i) {
|
|
6413
7902
|
return i != o.id; // move selected id to the end
|
|
6414
7903
|
});
|
|
6415
|
-
if (o.id > -1) {
|
|
7904
|
+
if (o.id > -1) { // pinned or hover style
|
|
6416
7905
|
topStyle = getSelectedFeatureStyle(lyr, o);
|
|
6417
7906
|
topIdx = ids.length;
|
|
6418
7907
|
ids.push(o.id); // put the pinned/hover feature last in the render order
|
|
@@ -6518,7 +8007,7 @@
|
|
|
6518
8007
|
if (lyr.geometry_type == 'point') {
|
|
6519
8008
|
return fields.indexOf('r') > -1; // require 'r' field for point symbols
|
|
6520
8009
|
}
|
|
6521
|
-
return utils.difference(fields, ['opacity', 'class']).length > 0;
|
|
8010
|
+
return utils$1.difference(fields, ['opacity', 'class']).length > 0;
|
|
6522
8011
|
}
|
|
6523
8012
|
|
|
6524
8013
|
|
|
@@ -6675,7 +8164,7 @@
|
|
|
6675
8164
|
}
|
|
6676
8165
|
|
|
6677
8166
|
function maxAbs() {
|
|
6678
|
-
return Math.max.apply(null, utils.toArray(arguments).map(Math.abs));
|
|
8167
|
+
return Math.max.apply(null, utils$1.toArray(arguments).map(Math.abs));
|
|
6679
8168
|
}
|
|
6680
8169
|
|
|
6681
8170
|
function limitScale(scale) {
|
|
@@ -6729,7 +8218,7 @@
|
|
|
6729
8218
|
}
|
|
6730
8219
|
}
|
|
6731
8220
|
|
|
6732
|
-
utils.inherit(MapExtent, EventDispatcher);
|
|
8221
|
+
utils$1.inherit(MapExtent, EventDispatcher);
|
|
6733
8222
|
|
|
6734
8223
|
// TODO: consider moving this upstream
|
|
6735
8224
|
function getArcsForRendering(obj, ext) {
|
|
@@ -6878,21 +8367,23 @@
|
|
|
6878
8367
|
var t = getScaledTransform(_ext);
|
|
6879
8368
|
var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
|
|
6880
8369
|
var color = style.strokeColor || 'black';
|
|
6881
|
-
var radius2 = radius *
|
|
8370
|
+
var radius2 = radius * 1.7;
|
|
8371
|
+
var i, j, p;
|
|
6882
8372
|
_ctx.beginPath();
|
|
6883
8373
|
_ctx.fillStyle = color;
|
|
6884
|
-
for (
|
|
8374
|
+
for (i=0; i<shapes.length; i++) {
|
|
6885
8375
|
var shp = shapes[i];
|
|
6886
8376
|
if (!shp || filter && !filter(shp)) continue;
|
|
6887
|
-
for (
|
|
8377
|
+
for (j=0; j<shp.length; j++) {
|
|
6888
8378
|
iter.init(shp[j]);
|
|
6889
8379
|
while (iter.hasNext()) {
|
|
6890
8380
|
drawCircle(iter.x * t.mx + t.bx, iter.y * t.my + t.by, radius, _ctx);
|
|
6891
8381
|
}
|
|
6892
8382
|
}
|
|
6893
8383
|
}
|
|
8384
|
+
|
|
6894
8385
|
if (style.vertex_overlay) {
|
|
6895
|
-
|
|
8386
|
+
p = style.vertex_overlay;
|
|
6896
8387
|
drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius2, _ctx);
|
|
6897
8388
|
}
|
|
6898
8389
|
_ctx.fill();
|
|
@@ -6919,7 +8410,7 @@
|
|
|
6919
8410
|
key = getStyleKey(style);
|
|
6920
8411
|
if (key in styleIndex === false) {
|
|
6921
8412
|
styleIndex[key] = {
|
|
6922
|
-
style: utils.defaults({}, style),
|
|
8413
|
+
style: utils$1.defaults({}, style),
|
|
6923
8414
|
shapes: []
|
|
6924
8415
|
};
|
|
6925
8416
|
}
|
|
@@ -7259,7 +8750,8 @@
|
|
|
7259
8750
|
if (style.strokeWidth > 0) {
|
|
7260
8751
|
strokeWidth = style.strokeWidth;
|
|
7261
8752
|
if (pixRatio > 1) {
|
|
7262
|
-
// bump up thin lines on retina, but not to more than 1px
|
|
8753
|
+
// bump up thin lines on retina, but not to more than 1px
|
|
8754
|
+
// (tests on Chrome showed much faster rendering of 1px lines)
|
|
7263
8755
|
strokeWidth = strokeWidth < 1 ? 1 : strokeWidth * pixRatio;
|
|
7264
8756
|
}
|
|
7265
8757
|
ctx.lineCap = 'round';
|
|
@@ -7393,7 +8885,7 @@
|
|
|
7393
8885
|
var frame = ext.getFrame(); // frame should be set if we're rendering a furniture layer
|
|
7394
8886
|
var obj = internal.getEmptyLayerForSVG(lyr, {});
|
|
7395
8887
|
if (!frame) {
|
|
7396
|
-
stop('Missing map frame data');
|
|
8888
|
+
stop$1('Missing map frame data');
|
|
7397
8889
|
}
|
|
7398
8890
|
obj.properties.transform = getSvgFurnitureTransform(ext);
|
|
7399
8891
|
obj.properties.class = 'mapshaper-svg-furniture';
|
|
@@ -7421,7 +8913,7 @@
|
|
|
7421
8913
|
var html = '';
|
|
7422
8914
|
// generate a unique id so layer can be identified when symbols are repositioned
|
|
7423
8915
|
// use it as a class name to avoid id collisions
|
|
7424
|
-
var id = utils.getUniqueName();
|
|
8916
|
+
var id = utils$1.getUniqueName();
|
|
7425
8917
|
var classNames = [id, 'mapshaper-svg-layer', 'mapshaper-' + type + '-layer'];
|
|
7426
8918
|
g.setAttribute('class', classNames.join(' '));
|
|
7427
8919
|
target.svg_id = id;
|
|
@@ -7872,7 +9364,7 @@
|
|
|
7872
9364
|
}
|
|
7873
9365
|
|
|
7874
9366
|
if (obj.tabular) {
|
|
7875
|
-
utils.extend(obj, getDisplayLayerForTable(layer.data));
|
|
9367
|
+
utils$1.extend(obj, getDisplayLayerForTable(layer.data));
|
|
7876
9368
|
}
|
|
7877
9369
|
|
|
7878
9370
|
// dynamic reprojection (arcs were already reprojected above)
|
|
@@ -7930,7 +9422,7 @@
|
|
|
7930
9422
|
return ids;
|
|
7931
9423
|
}
|
|
7932
9424
|
|
|
7933
|
-
utils.inherit(MshpMap, EventDispatcher);
|
|
9425
|
+
utils$1.inherit(MshpMap, EventDispatcher);
|
|
7934
9426
|
|
|
7935
9427
|
function MshpMap(gui) {
|
|
7936
9428
|
var opts = gui.options,
|
|
@@ -8024,7 +9516,7 @@
|
|
|
8024
9516
|
this.setDisplayCRS = function(crs) {
|
|
8025
9517
|
// TODO: update bounds of frame layer, if there is a frame layer
|
|
8026
9518
|
var oldCRS = this.getDisplayCRS();
|
|
8027
|
-
var newCRS = utils.isString(crs) ? internal.getCRS(crs) : crs;
|
|
9519
|
+
var newCRS = utils$1.isString(crs) ? internal.getCRS(crs) : crs;
|
|
8028
9520
|
// TODO: handle case that old and new CRS are the same
|
|
8029
9521
|
_dynamicCRS = newCRS;
|
|
8030
9522
|
if (!_activeLyr) return; // stop here if no layers have been selected
|
|
@@ -8152,7 +9644,7 @@
|
|
|
8152
9644
|
function updateOverlayLayer(e) {
|
|
8153
9645
|
var style = getOverlayStyle(_activeLyr.layer, e);
|
|
8154
9646
|
if (style) {
|
|
8155
|
-
_overlayLyr = utils.defaults({
|
|
9647
|
+
_overlayLyr = utils$1.defaults({
|
|
8156
9648
|
layer: filterLayerByIds(_activeLyr.layer, style.ids),
|
|
8157
9649
|
style: style
|
|
8158
9650
|
}, _activeLyr);
|
|
@@ -8317,7 +9809,7 @@
|
|
|
8317
9809
|
// kludge to hide ghosted layers when reference layers are present
|
|
8318
9810
|
// TODO: consider never showing ghosted layers (which appear after
|
|
8319
9811
|
// commands like dissolve and filter).
|
|
8320
|
-
mapLayer.style = utils.defaults({
|
|
9812
|
+
mapLayer.style = utils$1.defaults({
|
|
8321
9813
|
strokeColors: [null, mapLayer.style.strokeColors[1]]
|
|
8322
9814
|
}, mapLayer.style);
|
|
8323
9815
|
}
|
|
@@ -8373,7 +9865,7 @@
|
|
|
8373
9865
|
|
|
8374
9866
|
function GuiInstance(container, opts) {
|
|
8375
9867
|
var gui = new ModeSwitcher();
|
|
8376
|
-
opts = utils.extend({
|
|
9868
|
+
opts = utils$1.extend({
|
|
8377
9869
|
// defaults
|
|
8378
9870
|
homeControl: true,
|
|
8379
9871
|
zoomControl: true,
|