mapshaper 0.5.82 → 0.5.86
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 +13 -0
- package/mapshaper.js +396 -190
- package/package.json +1 -1
- package/www/mapshaper-gui.js +2125 -293
- package/www/mapshaper.js +396 -190
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
|
}
|
|
@@ -224,7 +322,7 @@
|
|
|
224
322
|
}
|
|
225
323
|
parsed = internal.parseCommands(str);
|
|
226
324
|
if (!parsed.length || parsed[0].name != cmd) {
|
|
227
|
-
stop("Unable to parse command line options");
|
|
325
|
+
stop$1("Unable to parse command line options");
|
|
228
326
|
}
|
|
229
327
|
return parsed[0].options;
|
|
230
328
|
};
|
|
@@ -293,7 +391,7 @@
|
|
|
293
391
|
evt = new EventData(this.type);
|
|
294
392
|
evt.target = this.target;
|
|
295
393
|
} else if (evt.target != this.target || evt.type != this.type) {
|
|
296
|
-
error("[Handler] event target/type have changed.");
|
|
394
|
+
error$1("[Handler] event target/type have changed.");
|
|
297
395
|
}
|
|
298
396
|
this.callback.call(this.listener, evt);
|
|
299
397
|
};
|
|
@@ -302,7 +400,7 @@
|
|
|
302
400
|
this.type = type;
|
|
303
401
|
this.target = target;
|
|
304
402
|
if (data) {
|
|
305
|
-
utils.defaults(this, data);
|
|
403
|
+
utils$1.defaults(this, data);
|
|
306
404
|
this.data = data;
|
|
307
405
|
}
|
|
308
406
|
}
|
|
@@ -532,12 +630,12 @@
|
|
|
532
630
|
try {
|
|
533
631
|
els = root.querySelectorAll(selector);
|
|
534
632
|
} catch (e) {
|
|
535
|
-
error("Invalid selector:", selector);
|
|
633
|
+
error$1("Invalid selector:", selector);
|
|
536
634
|
}
|
|
537
635
|
} else {
|
|
538
|
-
error("This browser doesn't support CSS query selectors");
|
|
636
|
+
error$1("This browser doesn't support CSS query selectors");
|
|
539
637
|
}
|
|
540
|
-
return utils.toArray(els);
|
|
638
|
+
return utils$1.toArray(els);
|
|
541
639
|
};
|
|
542
640
|
|
|
543
641
|
// Converts dash-separated names (e.g. background-color) to camelCase (e.g. backgroundColor)
|
|
@@ -574,7 +672,7 @@
|
|
|
574
672
|
};
|
|
575
673
|
|
|
576
674
|
function El(ref) {
|
|
577
|
-
if (!ref) error("Element() needs a reference");
|
|
675
|
+
if (!ref) error$1("Element() needs a reference");
|
|
578
676
|
if (ref instanceof El) {
|
|
579
677
|
return ref;
|
|
580
678
|
}
|
|
@@ -583,7 +681,7 @@
|
|
|
583
681
|
}
|
|
584
682
|
|
|
585
683
|
var node;
|
|
586
|
-
if (utils.isString(ref)) {
|
|
684
|
+
if (utils$1.isString(ref)) {
|
|
587
685
|
if (ref[0] == '<') {
|
|
588
686
|
var parent = El('div').html(ref).node();
|
|
589
687
|
node = parent.childNodes.length == 1 ? parent.childNodes[0] : parent;
|
|
@@ -595,13 +693,13 @@
|
|
|
595
693
|
} else if (ref.tagName) {
|
|
596
694
|
node = ref;
|
|
597
695
|
}
|
|
598
|
-
if (!node) error("Unmatched element selector:", ref);
|
|
696
|
+
if (!node) error$1("Unmatched element selector:", ref);
|
|
599
697
|
this.el = node;
|
|
600
698
|
}
|
|
601
699
|
|
|
602
|
-
utils.inherit(El, EventDispatcher);
|
|
700
|
+
utils$1.inherit(El, EventDispatcher);
|
|
603
701
|
|
|
604
|
-
utils.extend(El.prototype, {
|
|
702
|
+
utils$1.extend(El.prototype, {
|
|
605
703
|
|
|
606
704
|
clone: function() {
|
|
607
705
|
var el = this.el.cloneNode(true);
|
|
@@ -610,7 +708,7 @@
|
|
|
610
708
|
// can ...
|
|
611
709
|
el = El('div').addClass(el.className).html(el.innerHTML).node();
|
|
612
710
|
}
|
|
613
|
-
el.id = utils.getUniqueName();
|
|
711
|
+
el.id = utils$1.getUniqueName();
|
|
614
712
|
this.el = el;
|
|
615
713
|
return this;
|
|
616
714
|
},
|
|
@@ -640,11 +738,11 @@
|
|
|
640
738
|
if (val != null) {
|
|
641
739
|
El.setStyle(this.el, css, val);
|
|
642
740
|
}
|
|
643
|
-
else if (utils.isString(css)) {
|
|
741
|
+
else if (utils$1.isString(css)) {
|
|
644
742
|
addCSS(this.el, css);
|
|
645
743
|
}
|
|
646
|
-
else if (utils.isObject(css)) {
|
|
647
|
-
utils.forEachProperty(css, function(val, key) {
|
|
744
|
+
else if (utils$1.isObject(css)) {
|
|
745
|
+
utils$1.forEachProperty(css, function(val, key) {
|
|
648
746
|
El.setStyle(this.el, key, val);
|
|
649
747
|
}, this);
|
|
650
748
|
}
|
|
@@ -652,7 +750,7 @@
|
|
|
652
750
|
},
|
|
653
751
|
|
|
654
752
|
attr: function(obj, value) {
|
|
655
|
-
if (utils.isString(obj)) {
|
|
753
|
+
if (utils$1.isString(obj)) {
|
|
656
754
|
if (arguments.length == 1) {
|
|
657
755
|
return this.el.getAttribute(obj);
|
|
658
756
|
}
|
|
@@ -736,7 +834,7 @@
|
|
|
736
834
|
},
|
|
737
835
|
|
|
738
836
|
text: function(str) {
|
|
739
|
-
this.html(utils.htmlEscape(str));
|
|
837
|
+
this.html(utils$1.htmlEscape(str));
|
|
740
838
|
return this;
|
|
741
839
|
},
|
|
742
840
|
|
|
@@ -826,7 +924,7 @@
|
|
|
826
924
|
El.prototype.__on = El.prototype.on;
|
|
827
925
|
El.prototype.on = function(type, func, ctx) {
|
|
828
926
|
if (ctx) {
|
|
829
|
-
error("[El#on()] Third argument no longer supported.");
|
|
927
|
+
error$1("[El#on()] Third argument no longer supported.");
|
|
830
928
|
}
|
|
831
929
|
if (this.constructor == El) {
|
|
832
930
|
this.el.addEventListener(type, func);
|
|
@@ -882,7 +980,7 @@
|
|
|
882
980
|
}
|
|
883
981
|
|
|
884
982
|
this.value = function(str) {
|
|
885
|
-
if (utils.isString(str)) {
|
|
983
|
+
if (utils$1.isString(str)) {
|
|
886
984
|
el.node().textContent = str;
|
|
887
985
|
} else {
|
|
888
986
|
return el.node().textContent;
|
|
@@ -890,7 +988,7 @@
|
|
|
890
988
|
};
|
|
891
989
|
}
|
|
892
990
|
|
|
893
|
-
utils.inherit(ClickText2, EventDispatcher);
|
|
991
|
+
utils$1.inherit(ClickText2, EventDispatcher);
|
|
894
992
|
|
|
895
993
|
// @ref reference to a text input element
|
|
896
994
|
function ClickText(ref) {
|
|
@@ -961,9 +1059,9 @@
|
|
|
961
1059
|
// return _parser ? _parser(valStr) : parseFloat(valStr);
|
|
962
1060
|
return _value;
|
|
963
1061
|
}
|
|
964
|
-
var val = utils.clamp(arg, _min, _max);
|
|
1062
|
+
var val = utils$1.clamp(arg, _min, _max);
|
|
965
1063
|
if (!_validator(val)) {
|
|
966
|
-
error("ClickText#value() invalid value:", arg);
|
|
1064
|
+
error$1("ClickText#value() invalid value:", arg);
|
|
967
1065
|
} else {
|
|
968
1066
|
_value = val;
|
|
969
1067
|
}
|
|
@@ -972,14 +1070,14 @@
|
|
|
972
1070
|
};
|
|
973
1071
|
}
|
|
974
1072
|
|
|
975
|
-
utils.inherit(ClickText, EventDispatcher);
|
|
1073
|
+
utils$1.inherit(ClickText, EventDispatcher);
|
|
976
1074
|
|
|
977
1075
|
|
|
978
1076
|
function Checkbox(ref) {
|
|
979
1077
|
var _el = El(ref);
|
|
980
1078
|
}
|
|
981
1079
|
|
|
982
|
-
utils.inherit(Checkbox, EventDispatcher);
|
|
1080
|
+
utils$1.inherit(Checkbox, EventDispatcher);
|
|
983
1081
|
|
|
984
1082
|
function SimpleButton(ref) {
|
|
985
1083
|
var _el = El(ref),
|
|
@@ -1008,7 +1106,7 @@
|
|
|
1008
1106
|
}
|
|
1009
1107
|
}
|
|
1010
1108
|
|
|
1011
|
-
utils.inherit(SimpleButton, EventDispatcher);
|
|
1109
|
+
utils$1.inherit(SimpleButton, EventDispatcher);
|
|
1012
1110
|
|
|
1013
1111
|
// @cb function(<FileList>)
|
|
1014
1112
|
function DropControl(gui, el, cb) {
|
|
@@ -1256,7 +1354,7 @@
|
|
|
1256
1354
|
function receiveFiles(files) {
|
|
1257
1355
|
var prevSize = queuedFiles.length;
|
|
1258
1356
|
useQuickView = useQuickView || overQuickView;
|
|
1259
|
-
files = handleZipFiles(utils.toArray(files));
|
|
1357
|
+
files = handleZipFiles(utils$1.toArray(files));
|
|
1260
1358
|
addFilesToQueue(files);
|
|
1261
1359
|
if (queuedFiles.length === 0) return;
|
|
1262
1360
|
gui.enterMode('import');
|
|
@@ -1271,7 +1369,7 @@
|
|
|
1271
1369
|
}
|
|
1272
1370
|
|
|
1273
1371
|
function filesMayContainPaths(files) {
|
|
1274
|
-
return utils.some(files, function(f) {
|
|
1372
|
+
return utils$1.some(files, function(f) {
|
|
1275
1373
|
var type = internal.guessInputFileType(f.name);
|
|
1276
1374
|
return type == 'shp' || type == 'json' || internal.isZipFile(f.name);
|
|
1277
1375
|
});
|
|
@@ -1375,7 +1473,7 @@
|
|
|
1375
1473
|
lyr = dataset.layers[0];
|
|
1376
1474
|
lyr.data = new internal.ShapefileTable(content, importOpts.encoding);
|
|
1377
1475
|
if (lyr.shapes && lyr.data.size() != lyr.shapes.length) {
|
|
1378
|
-
stop("Different number of records in .shp and .dbf files");
|
|
1476
|
+
stop$1("Different number of records in .shp and .dbf files");
|
|
1379
1477
|
}
|
|
1380
1478
|
if (!lyr.geometry_type) {
|
|
1381
1479
|
// kludge: trigger display of table cells if .shp has null geometry
|
|
@@ -1440,7 +1538,7 @@
|
|
|
1440
1538
|
}
|
|
1441
1539
|
|
|
1442
1540
|
function handleImportError(e, fileName) {
|
|
1443
|
-
var msg = utils.isString(e) ? e : e.message;
|
|
1541
|
+
var msg = utils$1.isString(e) ? e : e.message;
|
|
1444
1542
|
if (fileName) {
|
|
1445
1543
|
msg = "Error importing <i>" + fileName + "</i><br>" + msg;
|
|
1446
1544
|
}
|
|
@@ -1498,7 +1596,7 @@
|
|
|
1498
1596
|
|
|
1499
1597
|
function downloadFiles(paths) {
|
|
1500
1598
|
var items = prepFilesForDownload(paths);
|
|
1501
|
-
utils.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1599
|
+
utils$1.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1502
1600
|
if (err) {
|
|
1503
1601
|
gui.alert(err);
|
|
1504
1602
|
} else if (!files.length) {
|
|
@@ -1594,7 +1692,7 @@
|
|
|
1594
1692
|
var defaults = {
|
|
1595
1693
|
space: 7
|
|
1596
1694
|
};
|
|
1597
|
-
opts = utils.extend(defaults, opts);
|
|
1695
|
+
opts = utils$1.extend(defaults, opts);
|
|
1598
1696
|
|
|
1599
1697
|
var _pct = 0;
|
|
1600
1698
|
var _track,
|
|
@@ -1647,7 +1745,7 @@
|
|
|
1647
1745
|
};
|
|
1648
1746
|
|
|
1649
1747
|
function setHandlePos(x, fire) {
|
|
1650
|
-
x = utils.clamp(x, 0, size());
|
|
1748
|
+
x = utils$1.clamp(x, 0, size());
|
|
1651
1749
|
var pct = x / size();
|
|
1652
1750
|
if (pct != _pct) {
|
|
1653
1751
|
_pct = pct;
|
|
@@ -1662,7 +1760,7 @@
|
|
|
1662
1760
|
}
|
|
1663
1761
|
}
|
|
1664
1762
|
|
|
1665
|
-
utils.inherit(Slider, EventDispatcher);
|
|
1763
|
+
utils$1.inherit(Slider, EventDispatcher);
|
|
1666
1764
|
|
|
1667
1765
|
/*
|
|
1668
1766
|
How changes in the simplify control should affect other components
|
|
@@ -1730,7 +1828,7 @@
|
|
|
1730
1828
|
slider.on('change', function(e) {
|
|
1731
1829
|
var pct = fromSliderPct(e.pct);
|
|
1732
1830
|
text.value(pct);
|
|
1733
|
-
pct = utils.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1831
|
+
pct = utils$1.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1734
1832
|
onChange(pct);
|
|
1735
1833
|
});
|
|
1736
1834
|
slider.on('start', function(e) {
|
|
@@ -1751,7 +1849,7 @@
|
|
|
1751
1849
|
else if (pct < 0.01) decimals = 3;
|
|
1752
1850
|
else if (pct < 1) decimals = 2;
|
|
1753
1851
|
else if (pct < 100) decimals = 1;
|
|
1754
|
-
return utils.formatNumberForDisplay(pct, decimals) + "%";
|
|
1852
|
+
return utils$1.formatNumberForDisplay(pct, decimals) + "%";
|
|
1755
1853
|
});
|
|
1756
1854
|
|
|
1757
1855
|
text.parser(function(s) {
|
|
@@ -2003,7 +2101,7 @@
|
|
|
2003
2101
|
|
|
2004
2102
|
// Replace error function in mapshaper lib
|
|
2005
2103
|
var error = function() {
|
|
2006
|
-
stop.apply(null, utils.toArray(arguments));
|
|
2104
|
+
stop.apply(null, utils$1.toArray(arguments));
|
|
2007
2105
|
};
|
|
2008
2106
|
|
|
2009
2107
|
var message = function() {
|
|
@@ -2017,11 +2115,11 @@
|
|
|
2017
2115
|
// replace CLI version of writeFiles()
|
|
2018
2116
|
internal.replaceWriteFiles(function(files, opts, done) {
|
|
2019
2117
|
var filename;
|
|
2020
|
-
if (!utils.isArray(files) || files.length === 0) {
|
|
2118
|
+
if (!utils$1.isArray(files) || files.length === 0) {
|
|
2021
2119
|
done("Nothing to export");
|
|
2022
2120
|
} else if (GUI.canSaveToServer() && !opts.save_to_download_folder) {
|
|
2023
|
-
var paths = internal.getOutputPaths(utils.pluck(files, 'filename'), opts);
|
|
2024
|
-
var data = utils.pluck(files, 'content');
|
|
2121
|
+
var paths = internal.getOutputPaths(utils$1.pluck(files, 'filename'), opts);
|
|
2122
|
+
var data = utils$1.pluck(files, 'content');
|
|
2025
2123
|
saveFilesToServer(paths, data, function(err) {
|
|
2026
2124
|
var msg;
|
|
2027
2125
|
if (err) {
|
|
@@ -2040,7 +2138,7 @@
|
|
|
2040
2138
|
} else if (files.length == 1) {
|
|
2041
2139
|
saveBlobToDownloadFolder(files[0].filename, new Blob([files[0].content]), done);
|
|
2042
2140
|
} else {
|
|
2043
|
-
filename = internal.getCommonFileBase(utils.pluck(files, 'filename')) || "output";
|
|
2141
|
+
filename = internal.getCommonFileBase(utils$1.pluck(files, 'filename')) || "output";
|
|
2044
2142
|
saveZipFile(filename + ".zip", files, done);
|
|
2045
2143
|
}
|
|
2046
2144
|
});
|
|
@@ -2062,10 +2160,10 @@
|
|
|
2062
2160
|
// try to match import filename of this dataset
|
|
2063
2161
|
if (d.info.input_files[0] == src) return d;
|
|
2064
2162
|
// try to match name of a layer in this dataset
|
|
2065
|
-
lyr = utils.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2163
|
+
lyr = utils$1.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2066
2164
|
return lyr ? internal.isolateLayer(lyr, d) : null;
|
|
2067
2165
|
}, null);
|
|
2068
|
-
if (!retn) stop("Missing data layer [" + src + "]");
|
|
2166
|
+
if (!retn) stop$1("Missing data layer [" + src + "]");
|
|
2069
2167
|
return retn;
|
|
2070
2168
|
}
|
|
2071
2169
|
|
|
@@ -2074,7 +2172,7 @@
|
|
|
2074
2172
|
// Return a copy with layers duplicated, so changes won't affect original layers
|
|
2075
2173
|
// This makes an (unsafe) assumption that the dataset arcs won't be changed...
|
|
2076
2174
|
// need to rethink this.
|
|
2077
|
-
return utils.defaults({
|
|
2175
|
+
return utils$1.defaults({
|
|
2078
2176
|
layers: dataset.layers.map(internal.copyLayer)
|
|
2079
2177
|
}, dataset);
|
|
2080
2178
|
});
|
|
@@ -2146,7 +2244,7 @@
|
|
|
2146
2244
|
}
|
|
2147
2245
|
|
|
2148
2246
|
function projectPointsForDisplay(lyr, src, dest) {
|
|
2149
|
-
var copy = utils.extend({}, lyr);
|
|
2247
|
+
var copy = utils$1.extend({}, lyr);
|
|
2150
2248
|
var proj = internal.getProjTransform2(src, dest);
|
|
2151
2249
|
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
2152
2250
|
internal.projectPointLayer(copy, proj);
|
|
@@ -2544,7 +2642,7 @@
|
|
|
2544
2642
|
} else if (cmd == 'history') {
|
|
2545
2643
|
toLog(gui.session.toCommandLineString());
|
|
2546
2644
|
} else if (cmd == 'layers') {
|
|
2547
|
-
message("Available layers:",
|
|
2645
|
+
message$1("Available layers:",
|
|
2548
2646
|
internal.getFormattedLayerList(model));
|
|
2549
2647
|
} else if (cmd == 'close' || cmd == 'exit' || cmd == 'quit') {
|
|
2550
2648
|
turnOff();
|
|
@@ -2633,7 +2731,7 @@
|
|
|
2633
2731
|
}
|
|
2634
2732
|
|
|
2635
2733
|
function onError(err) {
|
|
2636
|
-
if (utils.isString(err)) {
|
|
2734
|
+
if (utils$1.isString(err)) {
|
|
2637
2735
|
consoleStop(err);
|
|
2638
2736
|
} else if (err.name == 'UserError') {
|
|
2639
2737
|
// stop() has already been called, don't need to log
|
|
@@ -2648,7 +2746,7 @@
|
|
|
2648
2746
|
function consoleStop() {
|
|
2649
2747
|
var msg = GUI.formatMessageArgs(arguments);
|
|
2650
2748
|
consoleWarning(msg);
|
|
2651
|
-
throw new UserError(msg);
|
|
2749
|
+
throw new UserError$1(msg);
|
|
2652
2750
|
}
|
|
2653
2751
|
|
|
2654
2752
|
function consoleWarning() {
|
|
@@ -2812,7 +2910,7 @@
|
|
|
2812
2910
|
// console.log("first intersection:", internal.getIntersectionDebugData(XX[0], arcs));
|
|
2813
2911
|
pointLyr = {geometry_type: 'point', shapes: [internal.getIntersectionPoints(XX)]};
|
|
2814
2912
|
map.setIntersectionLayer(pointLyr, {layers:[pointLyr]});
|
|
2815
|
-
readout.html(utils.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils.pluralSuffix(n)));
|
|
2913
|
+
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)));
|
|
2816
2914
|
readout.findChild('.close-btn').on('click', dismiss);
|
|
2817
2915
|
} else {
|
|
2818
2916
|
map.setIntersectionLayer(null);
|
|
@@ -2821,7 +2919,7 @@
|
|
|
2821
2919
|
}
|
|
2822
2920
|
}
|
|
2823
2921
|
|
|
2824
|
-
utils.inherit(RepairControl, EventDispatcher);
|
|
2922
|
+
utils$1.inherit(RepairControl, EventDispatcher);
|
|
2825
2923
|
|
|
2826
2924
|
function filterLayerByIds(lyr, ids) {
|
|
2827
2925
|
var shapes;
|
|
@@ -2829,7 +2927,7 @@
|
|
|
2829
2927
|
shapes = ids.map(function(id) {
|
|
2830
2928
|
return lyr.shapes[id];
|
|
2831
2929
|
});
|
|
2832
|
-
return utils.defaults({shapes: shapes, data: null}, lyr);
|
|
2930
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
2833
2931
|
}
|
|
2834
2932
|
return lyr;
|
|
2835
2933
|
}
|
|
@@ -2882,7 +2980,7 @@
|
|
|
2882
2980
|
});
|
|
2883
2981
|
|
|
2884
2982
|
internal.writeFiles = function() {
|
|
2885
|
-
error(unsupportedMsg);
|
|
2983
|
+
error$1(unsupportedMsg);
|
|
2886
2984
|
};
|
|
2887
2985
|
} else {
|
|
2888
2986
|
new SimpleButton(menu.findChild('.save-btn').addClass('default-btn')).on('click', onExportClick);
|
|
@@ -2918,7 +3016,7 @@
|
|
|
2918
3016
|
setTimeout(function() {
|
|
2919
3017
|
exportMenuSelection(layers, function(err) {
|
|
2920
3018
|
if (err) {
|
|
2921
|
-
if (utils.isString(err)) {
|
|
3019
|
+
if (utils$1.isString(err)) {
|
|
2922
3020
|
gui.alert(err);
|
|
2923
3021
|
} else {
|
|
2924
3022
|
// stack seems to change if Error is logged directly
|
|
@@ -2965,7 +3063,7 @@
|
|
|
2965
3063
|
// without changing its name elsewhere
|
|
2966
3064
|
layer: Object.assign({}, o.layer)
|
|
2967
3065
|
};
|
|
2968
|
-
var html = utils.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
3066
|
+
var html = utils$1.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
2969
3067
|
// return {layer: o.layer, html: html};
|
|
2970
3068
|
var el = El('div').html(html).addClass('layer-item');
|
|
2971
3069
|
var box = el.findChild('input').node();
|
|
@@ -3075,9 +3173,9 @@
|
|
|
3075
3173
|
|
|
3076
3174
|
function initFormatMenu() {
|
|
3077
3175
|
var defaults = ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'svg'];
|
|
3078
|
-
var formats = utils.uniq(defaults.concat(getInputFormats()));
|
|
3176
|
+
var formats = utils$1.uniq(defaults.concat(getInputFormats()));
|
|
3079
3177
|
var items = formats.map(function(fmt) {
|
|
3080
|
-
return utils.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3178
|
+
return utils$1.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3081
3179
|
' class="radio">%s</label></div>', fmt, internal.getFormatName(fmt));
|
|
3082
3180
|
});
|
|
3083
3181
|
menu.findChild('.export-formats').html(items.join('\n'));
|
|
@@ -3240,7 +3338,7 @@
|
|
|
3240
3338
|
// can be used as unique identifiers for caching rendered HTML, and as
|
|
3241
3339
|
// an id for layer menu event handlers
|
|
3242
3340
|
if (!lyr.menu_id || uniqIds[lyr.menu_id]) {
|
|
3243
|
-
lyr.menu_id = utils.getUniqueName();
|
|
3341
|
+
lyr.menu_id = utils$1.getUniqueName();
|
|
3244
3342
|
}
|
|
3245
3343
|
uniqIds[lyr.menu_id] = true;
|
|
3246
3344
|
if (isPinnable(lyr)) pinnableCount++;
|
|
@@ -3374,204 +3472,1948 @@
|
|
|
3374
3472
|
map.redraw();
|
|
3375
3473
|
});
|
|
3376
3474
|
|
|
3377
|
-
// catch click event on pin button
|
|
3378
|
-
GUI.onClick(entry.findChild('img.unpinned'), function(e) {
|
|
3379
|
-
e.stopPropagation();
|
|
3380
|
-
});
|
|
3381
|
-
}
|
|
3475
|
+
// catch click event on pin button
|
|
3476
|
+
GUI.onClick(entry.findChild('img.unpinned'), function(e) {
|
|
3477
|
+
e.stopPropagation();
|
|
3478
|
+
});
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
// init name editor
|
|
3482
|
+
new ClickText2(entry.findChild('.layer-name'))
|
|
3483
|
+
.on('change', function(e) {
|
|
3484
|
+
var target = findLayerById(id);
|
|
3485
|
+
var str = cleanLayerName(this.value());
|
|
3486
|
+
this.value(formatLayerNameForDisplay(str));
|
|
3487
|
+
target.layer.name = str;
|
|
3488
|
+
gui.session.layerRenamed(target.layer, str);
|
|
3489
|
+
updateMenuBtn();
|
|
3490
|
+
});
|
|
3491
|
+
|
|
3492
|
+
// init click-to-select
|
|
3493
|
+
GUI.onClick(entry, function() {
|
|
3494
|
+
var target = findLayerById(id);
|
|
3495
|
+
// don't select if user is typing or dragging
|
|
3496
|
+
if (!GUI.getInputElement() && !dragging) {
|
|
3497
|
+
gui.clearMode();
|
|
3498
|
+
if (!map.isActiveLayer(target.layer)) {
|
|
3499
|
+
model.selectLayer(target.layer, target.dataset);
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
});
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
function describeLyr(lyr) {
|
|
3506
|
+
var n = internal.getFeatureCount(lyr),
|
|
3507
|
+
str, type;
|
|
3508
|
+
if (lyr.data && !lyr.shapes) {
|
|
3509
|
+
type = 'data record';
|
|
3510
|
+
} else if (lyr.geometry_type) {
|
|
3511
|
+
type = lyr.geometry_type + ' feature';
|
|
3512
|
+
}
|
|
3513
|
+
if (type) {
|
|
3514
|
+
str = utils$1.format('%,d %s%s', n, type, utils$1.pluralSuffix(n));
|
|
3515
|
+
} else {
|
|
3516
|
+
str = "[empty]";
|
|
3517
|
+
}
|
|
3518
|
+
return str;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
function getWarnings(lyr, dataset) {
|
|
3522
|
+
var file = internal.getLayerSourceFile(lyr, dataset);
|
|
3523
|
+
var missing = [];
|
|
3524
|
+
var msg;
|
|
3525
|
+
if (utils$1.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
|
|
3526
|
+
if (!lyr.data) {
|
|
3527
|
+
missing.push('.dbf');
|
|
3528
|
+
}
|
|
3529
|
+
if (!dataset.info.prj && !dataset.info.crs) {
|
|
3530
|
+
missing.push('.prj');
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
if (missing.length) {
|
|
3534
|
+
msg = 'missing ' + missing.join(' and ') + ' data';
|
|
3535
|
+
}
|
|
3536
|
+
return msg;
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
function describeSrc(lyr, dataset) {
|
|
3540
|
+
return internal.getLayerSourceFile(lyr, dataset);
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
|
|
3544
|
+
function isPinnable(lyr) {
|
|
3545
|
+
return internal.layerHasGeometry(lyr) || internal.layerHasFurniture(lyr);
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
|
|
3549
|
+
|
|
3550
|
+
function rowHTML(c1, c2, cname) {
|
|
3551
|
+
return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
3552
|
+
'<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
function SessionHistory(gui) {
|
|
3557
|
+
var commands = [];
|
|
3558
|
+
// commands that can be ignored when checking for unsaved changes
|
|
3559
|
+
var nonEditingCommands = 'i,target,info,version,verbose,projections,inspect,help,h,encodings,calc'.split(',');
|
|
3560
|
+
|
|
3561
|
+
this.unsavedChanges = function() {
|
|
3562
|
+
var cmd, cmdName;
|
|
3563
|
+
for (var i=commands.length - 1; i >= 0; i--) {
|
|
3564
|
+
cmdName = getCommandName(commands[i]);
|
|
3565
|
+
if (cmdName == 'o') break;
|
|
3566
|
+
if (nonEditingCommands.includes(cmdName)) continue;
|
|
3567
|
+
return true;
|
|
3568
|
+
}
|
|
3569
|
+
return false;
|
|
3570
|
+
};
|
|
3571
|
+
|
|
3572
|
+
this.fileImported = function(file, optStr) {
|
|
3573
|
+
var cmd = '-i ' + file;
|
|
3574
|
+
if (optStr) {
|
|
3575
|
+
cmd += ' ' + optStr;
|
|
3576
|
+
}
|
|
3577
|
+
commands.push(cmd);
|
|
3578
|
+
};
|
|
3579
|
+
|
|
3580
|
+
this.layerRenamed = function(lyr, name) {
|
|
3581
|
+
var currTarget = getCurrentTarget();
|
|
3582
|
+
var layerTarget = getTargetFromLayer(lyr);
|
|
3583
|
+
if (currTarget == layerTarget) {
|
|
3584
|
+
commands.push('-rename-layers ' + name);
|
|
3585
|
+
} else {
|
|
3586
|
+
commands.push('-rename-layers ' + name + ' target=' + layerTarget);
|
|
3587
|
+
commands.push('-target ' + currTarget);
|
|
3588
|
+
}
|
|
3589
|
+
};
|
|
3590
|
+
|
|
3591
|
+
this.consoleCommands = function(str) {
|
|
3592
|
+
commands.push(str); // todo: split commands?
|
|
3593
|
+
};
|
|
3594
|
+
|
|
3595
|
+
this.simplificationApplied = function(optStr) {
|
|
3596
|
+
commands.push('-simplify ' + optStr);
|
|
3597
|
+
};
|
|
3598
|
+
|
|
3599
|
+
this.simplificationRepair = function() {
|
|
3600
|
+
// TODO: improve this... repair does not necessarily apply to most recent
|
|
3601
|
+
// simplification command
|
|
3602
|
+
// consider adding a (hidden) repair command to handle this event
|
|
3603
|
+
var i = indexOfLastCommand('-simplify');
|
|
3604
|
+
if (i > -1) {
|
|
3605
|
+
commands[i] = commands[i].replace(' no-repair', '');
|
|
3606
|
+
}
|
|
3607
|
+
};
|
|
3608
|
+
|
|
3609
|
+
this.updateSimplificationPct = function(pct) {
|
|
3610
|
+
var i = indexOfLastCommand('-simplify');
|
|
3611
|
+
if (i > -1) {
|
|
3612
|
+
commands[i] = commands[i].replace(/percentage=[^ ]+/, 'percentage=' + pct);
|
|
3613
|
+
}
|
|
3614
|
+
};
|
|
3615
|
+
|
|
3616
|
+
this.dataValueUpdated = function(id, field, value) {
|
|
3617
|
+
var cmd = `-each 'd[${JSON.stringify(field)}] = ${JSON.stringify(value)}' where='this.id == ${id}'`;
|
|
3618
|
+
commands.push(cmd);
|
|
3619
|
+
};
|
|
3620
|
+
|
|
3621
|
+
this.layersExported = function(ids, optStr) {
|
|
3622
|
+
var layers = gui.model.getLayers();
|
|
3623
|
+
var cmd = '-o';
|
|
3624
|
+
if (layers.length > 1) {
|
|
3625
|
+
cmd += ' target=' + ids.map(getTargetFromId).join(',');
|
|
3626
|
+
}
|
|
3627
|
+
if (optStr) {
|
|
3628
|
+
cmd += ' ' + optStr;
|
|
3629
|
+
}
|
|
3630
|
+
commands.push(cmd);
|
|
3631
|
+
};
|
|
3632
|
+
|
|
3633
|
+
this.setTargetLayer = function(lyr) {
|
|
3634
|
+
var layers = gui.model.getLayers();
|
|
3635
|
+
if (layers.length > 1) {
|
|
3636
|
+
if (indexOfLastCommand('-target') == commands.length - 1) {
|
|
3637
|
+
commands.pop(); // if last commands was -target, remove it
|
|
3638
|
+
}
|
|
3639
|
+
commands.push('-target ' + getTargetFromLayer(lyr));
|
|
3640
|
+
}
|
|
3641
|
+
};
|
|
3642
|
+
|
|
3643
|
+
this.toCommandLineString = function() {
|
|
3644
|
+
var str = commands.join(' \\\n ');
|
|
3645
|
+
return 'mapshaper ' + str;
|
|
3646
|
+
};
|
|
3647
|
+
|
|
3648
|
+
function getCommandName(cmd) {
|
|
3649
|
+
var rxp = /^-([a-z0-9-]+)/;
|
|
3650
|
+
var match = rxp.exec(cmd);
|
|
3651
|
+
return match ? match[1] : null;
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
function getCurrentTarget() {
|
|
3655
|
+
return getTargetFromLayer(gui.model.getActiveLayer().layer);
|
|
3656
|
+
}
|
|
3657
|
+
|
|
3658
|
+
function indexOfLastCommand(cmd) {
|
|
3659
|
+
return commands.reduce(function(memo, str, i) {
|
|
3660
|
+
return str.indexOf(cmd) === 0 ? i : memo;
|
|
3661
|
+
}, -1);
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
function getTargetFromId(id) {
|
|
3665
|
+
var layers = gui.model.getLayers();
|
|
3666
|
+
return getTargetFromLayer(layers[id - 1].layer);
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
function getTargetFromLayer(lyr) {
|
|
3670
|
+
var id = internal.getLayerTargetId(gui.model, lyr);
|
|
3671
|
+
return internal.formatOptionValue(id);
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
var Buffer = require('buffer').Buffer; // works with browserify
|
|
3676
|
+
|
|
3677
|
+
var uniqCount = 0;
|
|
3678
|
+
function getUniqueName(prefix) {
|
|
3679
|
+
return (prefix || "__id_") + (++uniqCount);
|
|
3680
|
+
}
|
|
3681
|
+
|
|
3682
|
+
function isFunction(obj) {
|
|
3683
|
+
return typeof obj == 'function';
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
function isObject(obj) {
|
|
3687
|
+
return obj === Object(obj); // via underscore
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3690
|
+
function clamp(val, min, max) {
|
|
3691
|
+
return val < min ? min : (val > max ? max : val);
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
function isArray(obj) {
|
|
3695
|
+
return Array.isArray(obj);
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3698
|
+
// Is obj a valid number or NaN? (test if obj is type number)
|
|
3699
|
+
function isNumber(obj) {
|
|
3700
|
+
return obj != null && obj.constructor == Number;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
function isValidNumber(val) {
|
|
3704
|
+
return isNumber(val) && !isNaN(val);
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
// Similar to isFinite() but does not coerce strings or other types
|
|
3708
|
+
function isFiniteNumber(val) {
|
|
3709
|
+
return isValidNumber(val) && val !== Infinity && val !== -Infinity;
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
// This uses type conversion
|
|
3713
|
+
// export function isFiniteNumber(val) {
|
|
3714
|
+
// return val > -Infinity && val < Infinity;
|
|
3715
|
+
// }
|
|
3716
|
+
|
|
3717
|
+
function isNonNegNumber(val) {
|
|
3718
|
+
return isNumber(val) && val >= 0;
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3721
|
+
function isInteger(obj) {
|
|
3722
|
+
return isNumber(obj) && ((obj | 0) === obj);
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3725
|
+
function isEven(obj) {
|
|
3726
|
+
return (obj % 2) === 0;
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3729
|
+
function isOdd(obj) {
|
|
3730
|
+
return (obj % 2) === 1;
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3733
|
+
function isString(obj) {
|
|
3734
|
+
return obj != null && obj.toString === String.prototype.toString;
|
|
3735
|
+
// TODO: replace w/ something better.
|
|
3736
|
+
}
|
|
3737
|
+
|
|
3738
|
+
function isDate(obj) {
|
|
3739
|
+
return !!obj && obj.getTime === Date.prototype.getTime;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3742
|
+
function isBoolean(obj) {
|
|
3743
|
+
return obj === true || obj === false;
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
function formatDateISO(d) {
|
|
3747
|
+
if (!isDate(d)) return '';
|
|
3748
|
+
return d.toISOString().replace(':00.000Z', 'Z');
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3751
|
+
// Convert an array-like object to an Array, or make a copy if @obj is an Array
|
|
3752
|
+
function toArray(obj) {
|
|
3753
|
+
var arr;
|
|
3754
|
+
if (!isArrayLike(obj)) error("toArray() requires an array-like object");
|
|
3755
|
+
try {
|
|
3756
|
+
arr = Array.prototype.slice.call(obj, 0); // breaks in ie8
|
|
3757
|
+
} catch(e) {
|
|
3758
|
+
// support ie8
|
|
3759
|
+
arr = [];
|
|
3760
|
+
for (var i=0, n=obj.length; i<n; i++) {
|
|
3761
|
+
arr[i] = obj[i];
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
return arr;
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
// Array like: has length property, is numerically indexed and mutable.
|
|
3768
|
+
// TODO: try to detect objects with length property but no indexed data elements
|
|
3769
|
+
function isArrayLike(obj) {
|
|
3770
|
+
if (!obj) return false;
|
|
3771
|
+
if (isArray(obj)) return true;
|
|
3772
|
+
if (isString(obj)) return false;
|
|
3773
|
+
if (obj.length === 0) return true;
|
|
3774
|
+
if (obj.length > 0) return true;
|
|
3775
|
+
return false;
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
// See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js
|
|
3779
|
+
function addslashes(str) {
|
|
3780
|
+
return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
// Escape a literal string to use in a regexp.
|
|
3784
|
+
// Ref.: http://simonwillison.net/2006/Jan/20/escape/
|
|
3785
|
+
function regexEscape(str) {
|
|
3786
|
+
return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
|
|
3790
|
+
// See https://github.com/janl/mustache.js/blob/master/mustache.js
|
|
3791
|
+
var entityMap = {
|
|
3792
|
+
'&': '&',
|
|
3793
|
+
'<': '<',
|
|
3794
|
+
'>': '>',
|
|
3795
|
+
'"': '"',
|
|
3796
|
+
"'": ''',
|
|
3797
|
+
'/': '/'
|
|
3798
|
+
};
|
|
3799
|
+
function htmlEscape(s) {
|
|
3800
|
+
return String(s).replace(/[&<>"'\/]/g, function(s) {
|
|
3801
|
+
return entityMap[s];
|
|
3802
|
+
});
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3805
|
+
function defaults(dest) {
|
|
3806
|
+
for (var i=1, n=arguments.length; i<n; i++) {
|
|
3807
|
+
var src = arguments[i] || {};
|
|
3808
|
+
for (var key in src) {
|
|
3809
|
+
if (key in dest === false && src.hasOwnProperty(key)) {
|
|
3810
|
+
dest[key] = src[key];
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
return dest;
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
function extend(o) {
|
|
3818
|
+
var dest = o || {},
|
|
3819
|
+
n = arguments.length,
|
|
3820
|
+
key, i, src;
|
|
3821
|
+
for (i=1; i<n; i++) {
|
|
3822
|
+
src = arguments[i] || {};
|
|
3823
|
+
for (key in src) {
|
|
3824
|
+
if (src.hasOwnProperty(key)) {
|
|
3825
|
+
dest[key] = src[key];
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
return dest;
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
// Pseudoclassical inheritance
|
|
3833
|
+
//
|
|
3834
|
+
// Inherit from a Parent function:
|
|
3835
|
+
// inherit(Child, Parent);
|
|
3836
|
+
// Call parent's constructor (inside child constructor):
|
|
3837
|
+
// this.__super__([args...]);
|
|
3838
|
+
function inherit(targ, src) {
|
|
3839
|
+
var f = function() {
|
|
3840
|
+
if (this.__super__ == f) {
|
|
3841
|
+
// add __super__ of parent to front of lookup chain
|
|
3842
|
+
// so parent class constructor can call its parent using this.__super__
|
|
3843
|
+
this.__super__ = src.prototype.__super__;
|
|
3844
|
+
// call parent constructor function. this.__super__ now points to parent-of-parent
|
|
3845
|
+
src.apply(this, arguments);
|
|
3846
|
+
// remove temp __super__, expose targ.prototype.__super__ again
|
|
3847
|
+
delete this.__super__;
|
|
3848
|
+
}
|
|
3849
|
+
};
|
|
3850
|
+
|
|
3851
|
+
f.prototype = src.prototype || src; // added || src to allow inheriting from objects as well as functions
|
|
3852
|
+
// Extend targ prototype instead of wiping it out --
|
|
3853
|
+
// in case inherit() is called after targ.prototype = {stuff}; statement
|
|
3854
|
+
targ.prototype = extend(new f(), targ.prototype); //
|
|
3855
|
+
targ.prototype.constructor = targ;
|
|
3856
|
+
targ.prototype.__super__ = f;
|
|
3857
|
+
}
|
|
3858
|
+
|
|
3859
|
+
|
|
3860
|
+
// Call @iter on each member of an array (similar to Array#reduce(iter))
|
|
3861
|
+
// iter: function(memo, item, callback)
|
|
3862
|
+
// Call @done when all members have been processed or if an error occurs
|
|
3863
|
+
// done: function(err, memo)
|
|
3864
|
+
// @memo: Initial value
|
|
3865
|
+
//
|
|
3866
|
+
function reduceAsync(arr, memo, iter, done) {
|
|
3867
|
+
var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate;
|
|
3868
|
+
var i=0;
|
|
3869
|
+
next(null, memo);
|
|
3870
|
+
|
|
3871
|
+
function next(err, memo) {
|
|
3872
|
+
// Detach next operation from call stack to prevent overflow
|
|
3873
|
+
// Don't use setTimeout(, 0) if setImmediate is available
|
|
3874
|
+
// (setTimeout() can introduce a long delay if previous operation was slow,
|
|
3875
|
+
// as of Node 0.10.32 -- a bug?)
|
|
3876
|
+
if (err) {
|
|
3877
|
+
return done(err, null);
|
|
3878
|
+
}
|
|
3879
|
+
call(function() {
|
|
3880
|
+
if (i < arr.length === false) {
|
|
3881
|
+
done(null, memo);
|
|
3882
|
+
} else {
|
|
3883
|
+
iter(memo, arr[i++], next);
|
|
3884
|
+
}
|
|
3885
|
+
}, 0);
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
|
|
3889
|
+
|
|
3890
|
+
// Append elements of @src array to @dest array
|
|
3891
|
+
function merge(dest, src) {
|
|
3892
|
+
if (!isArray(dest) || !isArray(src)) {
|
|
3893
|
+
error("Usage: merge(destArray, srcArray);");
|
|
3894
|
+
}
|
|
3895
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
3896
|
+
dest.push(src[i]);
|
|
3897
|
+
}
|
|
3898
|
+
return dest;
|
|
3899
|
+
}
|
|
3900
|
+
|
|
3901
|
+
// Returns elements in arr and not in other
|
|
3902
|
+
// (similar to underscore diff)
|
|
3903
|
+
function difference(arr, other) {
|
|
3904
|
+
var index = arrayToIndex(other);
|
|
3905
|
+
return arr.filter(function(el) {
|
|
3906
|
+
return !Object.prototype.hasOwnProperty.call(index, el);
|
|
3907
|
+
});
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
// Return the intersection of two arrays
|
|
3911
|
+
function intersection(a, b) {
|
|
3912
|
+
return a.filter(function(el) {
|
|
3913
|
+
return b.includes(el);
|
|
3914
|
+
});
|
|
3915
|
+
}
|
|
3916
|
+
|
|
3917
|
+
function indexOf(arr, item) {
|
|
3918
|
+
var nan = item !== item;
|
|
3919
|
+
for (var i = 0, len = arr.length || 0; i < len; i++) {
|
|
3920
|
+
if (arr[i] === item) return i;
|
|
3921
|
+
if (nan && arr[i] !== arr[i]) return i;
|
|
3922
|
+
}
|
|
3923
|
+
return -1;
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
// Test a string or array-like object for existence of substring or element
|
|
3927
|
+
function contains(container, item) {
|
|
3928
|
+
if (isString(container)) {
|
|
3929
|
+
return container.indexOf(item) != -1;
|
|
3930
|
+
}
|
|
3931
|
+
else if (isArrayLike(container)) {
|
|
3932
|
+
return indexOf(container, item) != -1;
|
|
3933
|
+
}
|
|
3934
|
+
error("Expected Array or String argument");
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
function some(arr, test) {
|
|
3938
|
+
return arr.reduce(function(val, item) {
|
|
3939
|
+
return val || test(item); // TODO: short-circuit?
|
|
3940
|
+
}, false);
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
function every(arr, test) {
|
|
3944
|
+
return arr.reduce(function(val, item) {
|
|
3945
|
+
return val && test(item);
|
|
3946
|
+
}, true);
|
|
3947
|
+
}
|
|
3948
|
+
|
|
3949
|
+
function find(arr, test, ctx) {
|
|
3950
|
+
var matches = arr.filter(test, ctx);
|
|
3951
|
+
return matches.length === 0 ? null : matches[0];
|
|
3952
|
+
}
|
|
3953
|
+
|
|
3954
|
+
function range(len, start, inc) {
|
|
3955
|
+
var arr = [],
|
|
3956
|
+
v = start === void 0 ? 0 : start,
|
|
3957
|
+
i = inc === void 0 ? 1 : inc;
|
|
3958
|
+
while(len--) {
|
|
3959
|
+
arr.push(v);
|
|
3960
|
+
v += i;
|
|
3961
|
+
}
|
|
3962
|
+
return arr;
|
|
3963
|
+
}
|
|
3964
|
+
|
|
3965
|
+
function repeat(times, func) {
|
|
3966
|
+
var values = [],
|
|
3967
|
+
val;
|
|
3968
|
+
for (var i=0; i<times; i++) {
|
|
3969
|
+
val = func(i);
|
|
3970
|
+
if (val !== void 0) {
|
|
3971
|
+
values[i] = val;
|
|
3972
|
+
}
|
|
3973
|
+
}
|
|
3974
|
+
return values.length > 0 ? values : void 0;
|
|
3975
|
+
}
|
|
3976
|
+
|
|
3977
|
+
// Calc sum, skip falsy and NaN values
|
|
3978
|
+
// Assumes: no other non-numeric objects in array
|
|
3979
|
+
//
|
|
3980
|
+
function sum(arr, info) {
|
|
3981
|
+
if (!isArrayLike(arr)) error ("sum() expects an array, received:", arr);
|
|
3982
|
+
var tot = 0,
|
|
3983
|
+
nan = 0,
|
|
3984
|
+
val;
|
|
3985
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
3986
|
+
val = arr[i];
|
|
3987
|
+
if (val) {
|
|
3988
|
+
tot += val;
|
|
3989
|
+
} else if (isNaN(val)) {
|
|
3990
|
+
nan++;
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
if (info) {
|
|
3994
|
+
info.nan = nan;
|
|
3995
|
+
}
|
|
3996
|
+
return tot;
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
// Calculate min and max values of an array, ignoring NaN values
|
|
4000
|
+
function getArrayBounds(arr) {
|
|
4001
|
+
var min = Infinity,
|
|
4002
|
+
max = -Infinity,
|
|
4003
|
+
nan = 0, val;
|
|
4004
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4005
|
+
val = arr[i];
|
|
4006
|
+
if (val !== val) nan++;
|
|
4007
|
+
if (val < min) min = val;
|
|
4008
|
+
if (val > max) max = val;
|
|
4009
|
+
}
|
|
4010
|
+
return {
|
|
4011
|
+
min: min,
|
|
4012
|
+
max: max,
|
|
4013
|
+
nan: nan
|
|
4014
|
+
};
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
// export function uniq(src) {
|
|
4018
|
+
// var index = {};
|
|
4019
|
+
// return src.reduce(function(memo, el) {
|
|
4020
|
+
// if (el in index === false) {
|
|
4021
|
+
// index[el] = true;
|
|
4022
|
+
// memo.push(el);
|
|
4023
|
+
// }
|
|
4024
|
+
// return memo;
|
|
4025
|
+
// }, []);
|
|
4026
|
+
// }
|
|
4027
|
+
|
|
4028
|
+
function uniq(src) {
|
|
4029
|
+
var index = new Set();
|
|
4030
|
+
var arr = [];
|
|
4031
|
+
var item;
|
|
4032
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
4033
|
+
item = src[i];
|
|
4034
|
+
if (!index.has(item)) {
|
|
4035
|
+
arr.push(item);
|
|
4036
|
+
index.add(item);
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
return arr;
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
function pluck(arr, key) {
|
|
4043
|
+
return arr.map(function(obj) {
|
|
4044
|
+
return obj[key];
|
|
4045
|
+
});
|
|
4046
|
+
}
|
|
4047
|
+
|
|
4048
|
+
function countValues(arr) {
|
|
4049
|
+
return arr.reduce(function(memo, val) {
|
|
4050
|
+
memo[val] = (val in memo) ? memo[val] + 1 : 1;
|
|
4051
|
+
return memo;
|
|
4052
|
+
}, {});
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
function indexOn(arr, k) {
|
|
4056
|
+
return arr.reduce(function(index, o) {
|
|
4057
|
+
index[o[k]] = o;
|
|
4058
|
+
return index;
|
|
4059
|
+
}, {});
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
function groupBy(arr, k) {
|
|
4063
|
+
return arr.reduce(function(index, o) {
|
|
4064
|
+
var keyval = o[k];
|
|
4065
|
+
if (keyval in index) {
|
|
4066
|
+
index[keyval].push(o);
|
|
4067
|
+
} else {
|
|
4068
|
+
index[keyval] = [o];
|
|
4069
|
+
}
|
|
4070
|
+
return index;
|
|
4071
|
+
}, {});
|
|
4072
|
+
}
|
|
4073
|
+
|
|
4074
|
+
function arrayToIndex(arr, val) {
|
|
4075
|
+
var init = arguments.length > 1;
|
|
4076
|
+
return arr.reduce(function(index, key) {
|
|
4077
|
+
index[key] = init ? val : true;
|
|
4078
|
+
return index;
|
|
4079
|
+
}, {});
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
// Support for iterating over array-like objects, like typed arrays
|
|
4083
|
+
function forEach(arr, func, ctx) {
|
|
4084
|
+
if (!isArrayLike(arr)) {
|
|
4085
|
+
throw new Error("#forEach() takes an array-like argument. " + arr);
|
|
4086
|
+
}
|
|
4087
|
+
for (var i=0, n=arr.length; i < n; i++) {
|
|
4088
|
+
func.call(ctx, arr[i], i);
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
function forEachProperty(o, func, ctx) {
|
|
4093
|
+
Object.keys(o).forEach(function(key) {
|
|
4094
|
+
func.call(ctx, o[key], key);
|
|
4095
|
+
});
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
function initializeArray(arr, init) {
|
|
4099
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4100
|
+
arr[i] = init;
|
|
4101
|
+
}
|
|
4102
|
+
return arr;
|
|
4103
|
+
}
|
|
4104
|
+
|
|
4105
|
+
function replaceArray(arr, arr2) {
|
|
4106
|
+
arr.splice(0, arr.length);
|
|
4107
|
+
for (var i=0, n=arr2.length; i<n; i++) {
|
|
4108
|
+
arr.push(arr2[i]);
|
|
4109
|
+
}
|
|
4110
|
+
}
|
|
4111
|
+
|
|
4112
|
+
function repeatString(src, n) {
|
|
4113
|
+
var str = "";
|
|
4114
|
+
for (var i=0; i<n; i++)
|
|
4115
|
+
str += src;
|
|
4116
|
+
return str;
|
|
4117
|
+
}
|
|
4118
|
+
|
|
4119
|
+
function splitLines(str) {
|
|
4120
|
+
return str.split(/\r?\n/);
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
function pluralSuffix(count) {
|
|
4124
|
+
return count != 1 ? 's' : '';
|
|
4125
|
+
}
|
|
4126
|
+
|
|
4127
|
+
function endsWith(str, ending) {
|
|
4128
|
+
return str.indexOf(ending, str.length - ending.length) !== -1;
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
function lpad(str, size, pad) {
|
|
4132
|
+
pad = pad || ' ';
|
|
4133
|
+
str = String(str);
|
|
4134
|
+
return repeatString(pad, size - str.length) + str;
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
function rpad(str, size, pad) {
|
|
4138
|
+
pad = pad || ' ';
|
|
4139
|
+
str = String(str);
|
|
4140
|
+
return str + repeatString(pad, size - str.length);
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
function trim(str) {
|
|
4144
|
+
return ltrim(rtrim(str));
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4147
|
+
var ltrimRxp = /^\s+/;
|
|
4148
|
+
function ltrim(str) {
|
|
4149
|
+
return str.replace(ltrimRxp, '');
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
var rtrimRxp = /\s+$/;
|
|
4153
|
+
function rtrim(str) {
|
|
4154
|
+
return str.replace(rtrimRxp, '');
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
function addThousandsSep(str) {
|
|
4158
|
+
var fmt = '',
|
|
4159
|
+
start = str[0] == '-' ? 1 : 0,
|
|
4160
|
+
dec = str.indexOf('.'),
|
|
4161
|
+
end = str.length,
|
|
4162
|
+
ins = (dec == -1 ? end : dec) - 3;
|
|
4163
|
+
while (ins > start) {
|
|
4164
|
+
fmt = ',' + str.substring(ins, end) + fmt;
|
|
4165
|
+
end = ins;
|
|
4166
|
+
ins -= 3;
|
|
4167
|
+
}
|
|
4168
|
+
return str.substring(0, end) + fmt;
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
function numToStr(num, decimals) {
|
|
4172
|
+
return decimals >= 0 ? num.toFixed(decimals) : String(num);
|
|
4173
|
+
}
|
|
4174
|
+
|
|
4175
|
+
function formatNumber(val) {
|
|
4176
|
+
return val + '';
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
function formatIntlNumber(val) {
|
|
4180
|
+
var str = formatNumber(val);
|
|
4181
|
+
return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4184
|
+
function formatNumberForDisplay(num, decimals, nullStr, showPos) {
|
|
4185
|
+
var fmt;
|
|
4186
|
+
if (isNaN(num)) {
|
|
4187
|
+
fmt = nullStr || '-';
|
|
4188
|
+
} else {
|
|
4189
|
+
fmt = numToStr(num, decimals);
|
|
4190
|
+
fmt = addThousandsSep(fmt);
|
|
4191
|
+
if (showPos && parseFloat(fmt) > 0) {
|
|
4192
|
+
fmt = "+" + fmt;
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
return fmt;
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
function shuffle(arr) {
|
|
4199
|
+
var tmp, i, j;
|
|
4200
|
+
for (i = arr.length - 1; i > 0; i--) {
|
|
4201
|
+
j = Math.floor(Math.random() * (i + 1));
|
|
4202
|
+
tmp = arr[i];
|
|
4203
|
+
arr[i] = arr[j];
|
|
4204
|
+
arr[j] = tmp;
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
// Sort an array of objects based on one or more properties.
|
|
4209
|
+
// Usage: sortOn(array, key1, asc?[, key2, asc? ...])
|
|
4210
|
+
//
|
|
4211
|
+
function sortOn(arr) {
|
|
4212
|
+
var comparators = [];
|
|
4213
|
+
for (var i=1; i<arguments.length; i+=2) {
|
|
4214
|
+
comparators.push(getKeyComparator(arguments[i], arguments[i+1]));
|
|
4215
|
+
}
|
|
4216
|
+
arr.sort(function(a, b) {
|
|
4217
|
+
var cmp = 0,
|
|
4218
|
+
i = 0,
|
|
4219
|
+
n = comparators.length;
|
|
4220
|
+
while (i < n && cmp === 0) {
|
|
4221
|
+
cmp = comparators[i](a, b);
|
|
4222
|
+
i++;
|
|
4223
|
+
}
|
|
4224
|
+
return cmp;
|
|
4225
|
+
});
|
|
4226
|
+
return arr;
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4229
|
+
// Sort array of values that can be compared with < > operators (strings, numbers)
|
|
4230
|
+
// null, undefined and NaN are sorted to the end of the array
|
|
4231
|
+
// default order is ascending
|
|
4232
|
+
//
|
|
4233
|
+
function genericSort(arr, ascending) {
|
|
4234
|
+
var compare = getGenericComparator(ascending);
|
|
4235
|
+
Array.prototype.sort.call(arr, compare);
|
|
4236
|
+
return arr;
|
|
4237
|
+
}
|
|
4238
|
+
|
|
4239
|
+
function getSortedIds(arr, asc) {
|
|
4240
|
+
var ids = range(arr.length);
|
|
4241
|
+
sortArrayIndex(ids, arr, asc);
|
|
4242
|
+
return ids;
|
|
4243
|
+
}
|
|
4244
|
+
|
|
4245
|
+
function sortArrayIndex(ids, arr, asc) {
|
|
4246
|
+
var compare = getGenericComparator(asc);
|
|
4247
|
+
ids.sort(function(i, j) {
|
|
4248
|
+
// added i, j comparison to guarantee that sort is stable
|
|
4249
|
+
var cmp = compare(arr[i], arr[j]);
|
|
4250
|
+
return cmp > 0 || cmp === 0 && i > j ? 1 : -1;
|
|
4251
|
+
});
|
|
4252
|
+
}
|
|
4253
|
+
|
|
4254
|
+
function reorderArray(arr, idxs) {
|
|
4255
|
+
var len = idxs.length;
|
|
4256
|
+
var arr2 = [];
|
|
4257
|
+
for (var i=0; i<len; i++) {
|
|
4258
|
+
var idx = idxs[i];
|
|
4259
|
+
if (idx < 0 || idx >= len) error("Out-of-bounds array idx");
|
|
4260
|
+
arr2[i] = arr[idx];
|
|
4261
|
+
}
|
|
4262
|
+
replaceArray(arr, arr2);
|
|
4263
|
+
}
|
|
4264
|
+
|
|
4265
|
+
function getKeyComparator(key, asc) {
|
|
4266
|
+
var compare = getGenericComparator(asc);
|
|
4267
|
+
return function(a, b) {
|
|
4268
|
+
return compare(a[key], b[key]);
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
function getGenericComparator(asc) {
|
|
4273
|
+
asc = asc !== false;
|
|
4274
|
+
return function(a, b) {
|
|
4275
|
+
var retn = 0;
|
|
4276
|
+
if (b == null) {
|
|
4277
|
+
retn = a == null ? 0 : -1;
|
|
4278
|
+
} else if (a == null) {
|
|
4279
|
+
retn = 1;
|
|
4280
|
+
} else if (a < b) {
|
|
4281
|
+
retn = asc ? -1 : 1;
|
|
4282
|
+
} else if (a > b) {
|
|
4283
|
+
retn = asc ? 1 : -1;
|
|
4284
|
+
} else if (a !== a) {
|
|
4285
|
+
retn = 1;
|
|
4286
|
+
} else if (b !== b) {
|
|
4287
|
+
retn = -1;
|
|
4288
|
+
}
|
|
4289
|
+
return retn;
|
|
4290
|
+
};
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
|
|
4294
|
+
// Generic in-place sort (null, NaN, undefined not handled)
|
|
4295
|
+
function quicksort(arr, asc) {
|
|
4296
|
+
quicksortPartition(arr, 0, arr.length-1);
|
|
4297
|
+
if (asc === false) Array.prototype.reverse.call(arr); // Works with typed arrays
|
|
4298
|
+
return arr;
|
|
4299
|
+
}
|
|
4300
|
+
|
|
4301
|
+
// Moved out of quicksort() (saw >100% speedup in Chrome with deep recursion)
|
|
4302
|
+
function quicksortPartition (a, lo, hi) {
|
|
4303
|
+
var i = lo,
|
|
4304
|
+
j = hi,
|
|
4305
|
+
pivot, tmp;
|
|
4306
|
+
while (i < hi) {
|
|
4307
|
+
pivot = a[lo + hi >> 1]; // avoid n^2 performance on sorted arrays
|
|
4308
|
+
while (i <= j) {
|
|
4309
|
+
while (a[i] < pivot) i++;
|
|
4310
|
+
while (a[j] > pivot) j--;
|
|
4311
|
+
if (i <= j) {
|
|
4312
|
+
tmp = a[i];
|
|
4313
|
+
a[i] = a[j];
|
|
4314
|
+
a[j] = tmp;
|
|
4315
|
+
i++;
|
|
4316
|
+
j--;
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
if (lo < j) quicksortPartition(a, lo, j);
|
|
4320
|
+
lo = i;
|
|
4321
|
+
j = hi;
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
|
|
4325
|
+
|
|
4326
|
+
function findRankByValue(arr, value) {
|
|
4327
|
+
if (isNaN(value)) return arr.length;
|
|
4328
|
+
var rank = 1;
|
|
4329
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
4330
|
+
if (value > arr[i]) rank++;
|
|
4331
|
+
}
|
|
4332
|
+
return rank;
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
function findValueByPct(arr, pct) {
|
|
4336
|
+
var rank = Math.ceil((1-pct) * (arr.length));
|
|
4337
|
+
return findValueByRank(arr, rank);
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
// See http://ndevilla.free.fr/median/median/src/wirth.c
|
|
4341
|
+
// Elements of @arr are reordered
|
|
4342
|
+
//
|
|
4343
|
+
function findValueByRank(arr, rank) {
|
|
4344
|
+
if (!arr.length || rank < 1 || rank > arr.length) error("[findValueByRank()] invalid input");
|
|
4345
|
+
|
|
4346
|
+
rank = clamp(rank | 0, 1, arr.length);
|
|
4347
|
+
var k = rank - 1, // conv. rank to array index
|
|
4348
|
+
n = arr.length,
|
|
4349
|
+
l = 0,
|
|
4350
|
+
m = n - 1,
|
|
4351
|
+
i, j, val, tmp;
|
|
4352
|
+
|
|
4353
|
+
while (l < m) {
|
|
4354
|
+
val = arr[k];
|
|
4355
|
+
i = l;
|
|
4356
|
+
j = m;
|
|
4357
|
+
do {
|
|
4358
|
+
while (arr[i] < val) {i++;}
|
|
4359
|
+
while (val < arr[j]) {j--;}
|
|
4360
|
+
if (i <= j) {
|
|
4361
|
+
tmp = arr[i];
|
|
4362
|
+
arr[i] = arr[j];
|
|
4363
|
+
arr[j] = tmp;
|
|
4364
|
+
i++;
|
|
4365
|
+
j--;
|
|
4366
|
+
}
|
|
4367
|
+
} while (i <= j);
|
|
4368
|
+
if (j < k) l = i;
|
|
4369
|
+
if (k < i) m = j;
|
|
4370
|
+
}
|
|
4371
|
+
return arr[k];
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
//
|
|
4375
|
+
//
|
|
4376
|
+
function findMedian(arr) {
|
|
4377
|
+
var n = arr.length,
|
|
4378
|
+
rank = Math.floor(n / 2) + 1,
|
|
4379
|
+
median = findValueByRank(arr, rank);
|
|
4380
|
+
if ((n & 1) == 0) {
|
|
4381
|
+
median = (median + findValueByRank(arr, rank - 1)) / 2;
|
|
4382
|
+
}
|
|
4383
|
+
return median;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
|
|
4387
|
+
function mean(arr) {
|
|
4388
|
+
var count = 0,
|
|
4389
|
+
avg = NaN,
|
|
4390
|
+
val;
|
|
4391
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
4392
|
+
val = arr[i];
|
|
4393
|
+
if (isNaN(val)) continue;
|
|
4394
|
+
avg = ++count == 1 ? val : val / count + (count - 1) / count * avg;
|
|
4395
|
+
}
|
|
4396
|
+
return avg;
|
|
4397
|
+
}
|
|
4398
|
+
|
|
4399
|
+
|
|
4400
|
+
/*
|
|
4401
|
+
A simplified version of printf formatting
|
|
4402
|
+
Format codes: %[flags][width][.precision]type
|
|
4403
|
+
|
|
4404
|
+
supported flags:
|
|
4405
|
+
+ add '+' before positive numbers
|
|
4406
|
+
0 left-pad with '0'
|
|
4407
|
+
' Add thousands separator
|
|
4408
|
+
width: 1 to many
|
|
4409
|
+
precision: .(1 to many)
|
|
4410
|
+
type:
|
|
4411
|
+
s string
|
|
4412
|
+
di integers
|
|
4413
|
+
f decimal numbers
|
|
4414
|
+
xX hexidecimal (unsigned)
|
|
4415
|
+
% literal '%'
|
|
4416
|
+
|
|
4417
|
+
Examples:
|
|
4418
|
+
code val formatted
|
|
4419
|
+
%+d 1 '+1'
|
|
4420
|
+
%4i 32 ' 32'
|
|
4421
|
+
%04i 32 '0032'
|
|
4422
|
+
%x 255 'ff'
|
|
4423
|
+
%.2f 0.125 '0.13'
|
|
4424
|
+
%'f 1000 '1,000'
|
|
4425
|
+
*/
|
|
4426
|
+
|
|
4427
|
+
// Usage: format(formatString, [values])
|
|
4428
|
+
// Tip: When reusing the same format many times, use formatter() for 5x - 10x better performance
|
|
4429
|
+
//
|
|
4430
|
+
function format(fmt) {
|
|
4431
|
+
var fn = formatter(fmt);
|
|
4432
|
+
var str = fn.apply(null, Array.prototype.slice.call(arguments, 1));
|
|
4433
|
+
return str;
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4436
|
+
function formatValue(val, matches) {
|
|
4437
|
+
var flags = matches[1];
|
|
4438
|
+
var padding = matches[2];
|
|
4439
|
+
var decimals = matches[3] ? parseInt(matches[3].substr(1)) : void 0;
|
|
4440
|
+
var type = matches[4];
|
|
4441
|
+
var isString = type == 's',
|
|
4442
|
+
isHex = type == 'x' || type == 'X',
|
|
4443
|
+
isInt = type == 'd' || type == 'i',
|
|
4444
|
+
isFloat = type == 'f',
|
|
4445
|
+
isNumber = !isString;
|
|
4446
|
+
|
|
4447
|
+
var sign = "",
|
|
4448
|
+
padDigits = 0,
|
|
4449
|
+
isZero = false,
|
|
4450
|
+
isNeg = false;
|
|
4451
|
+
|
|
4452
|
+
var str, padChar, padStr;
|
|
4453
|
+
if (isString) {
|
|
4454
|
+
str = String(val);
|
|
4455
|
+
}
|
|
4456
|
+
else if (isHex) {
|
|
4457
|
+
str = val.toString(16);
|
|
4458
|
+
if (type == 'X')
|
|
4459
|
+
str = str.toUpperCase();
|
|
4460
|
+
}
|
|
4461
|
+
else if (isNumber) {
|
|
4462
|
+
// str = formatNumberForDisplay(val, isInt ? 0 : decimals);
|
|
4463
|
+
str = numToStr(val, decimals);
|
|
4464
|
+
if (str[0] == '-') {
|
|
4465
|
+
isNeg = true;
|
|
4466
|
+
str = str.substr(1);
|
|
4467
|
+
}
|
|
4468
|
+
isZero = parseFloat(str) == 0;
|
|
4469
|
+
if (flags.indexOf("'") != -1 || flags.indexOf(',') != -1) {
|
|
4470
|
+
str = addThousandsSep(str);
|
|
4471
|
+
}
|
|
4472
|
+
if (!isZero) { // BUG: sign is added when num rounds to 0
|
|
4473
|
+
if (isNeg) {
|
|
4474
|
+
sign = "\u2212"; // U+2212
|
|
4475
|
+
} else if (flags.indexOf('+') != -1) {
|
|
4476
|
+
sign = '+';
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
|
|
4481
|
+
if (padding) {
|
|
4482
|
+
var strLen = str.length + sign.length;
|
|
4483
|
+
var minWidth = parseInt(padding, 10);
|
|
4484
|
+
if (strLen < minWidth) {
|
|
4485
|
+
padDigits = minWidth - strLen;
|
|
4486
|
+
padChar = flags.indexOf('0') == -1 ? ' ' : '0';
|
|
4487
|
+
padStr = repeatString(padChar, padDigits);
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4491
|
+
if (padDigits == 0) {
|
|
4492
|
+
str = sign + str;
|
|
4493
|
+
} else if (padChar == '0') {
|
|
4494
|
+
str = sign + padStr + str;
|
|
4495
|
+
} else {
|
|
4496
|
+
str = padStr + sign + str;
|
|
4497
|
+
}
|
|
4498
|
+
return str;
|
|
4499
|
+
}
|
|
4500
|
+
|
|
4501
|
+
// Get a function for interpolating formatted values into a string.
|
|
4502
|
+
function formatter(fmt) {
|
|
4503
|
+
var codeRxp = /%([\',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
|
|
4504
|
+
var literals = [],
|
|
4505
|
+
formatCodes = [],
|
|
4506
|
+
startIdx = 0,
|
|
4507
|
+
prefix = "",
|
|
4508
|
+
matches = codeRxp.exec(fmt),
|
|
4509
|
+
literal;
|
|
4510
|
+
|
|
4511
|
+
while (matches) {
|
|
4512
|
+
literal = fmt.substring(startIdx, codeRxp.lastIndex - matches[0].length);
|
|
4513
|
+
if (matches[0] == '%%') {
|
|
4514
|
+
prefix += literal + '%';
|
|
4515
|
+
} else {
|
|
4516
|
+
literals.push(prefix + literal);
|
|
4517
|
+
prefix = '';
|
|
4518
|
+
formatCodes.push(matches);
|
|
4519
|
+
}
|
|
4520
|
+
startIdx = codeRxp.lastIndex;
|
|
4521
|
+
matches = codeRxp.exec(fmt);
|
|
4522
|
+
}
|
|
4523
|
+
literals.push(prefix + fmt.substr(startIdx));
|
|
4524
|
+
|
|
4525
|
+
return function() {
|
|
4526
|
+
var str = literals[0],
|
|
4527
|
+
n = arguments.length;
|
|
4528
|
+
if (n != formatCodes.length) {
|
|
4529
|
+
error("[format()] Data does not match format string; format:", fmt, "data:", arguments);
|
|
4530
|
+
}
|
|
4531
|
+
for (var i=0; i<n; i++) {
|
|
4532
|
+
str += formatValue(arguments[i], formatCodes[i]) + literals[i+1];
|
|
4533
|
+
}
|
|
4534
|
+
return str;
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
function wildcardToRegExp(name) {
|
|
4539
|
+
var rxp = name.split('*').map(function(str) {
|
|
4540
|
+
return regexEscape(str);
|
|
4541
|
+
}).join('.*');
|
|
4542
|
+
return new RegExp('^' + rxp + '$');
|
|
4543
|
+
}
|
|
4544
|
+
|
|
4545
|
+
function createBuffer(arg, arg2) {
|
|
4546
|
+
if (isInteger(arg)) {
|
|
4547
|
+
return Buffer.allocUnsafe ? Buffer.allocUnsafe(arg) : new Buffer(arg);
|
|
4548
|
+
} else {
|
|
4549
|
+
// check allocUnsafe to make sure Buffer.from() will accept strings (it didn't before Node v5.10)
|
|
4550
|
+
return Buffer.from && Buffer.allocUnsafe ? Buffer.from(arg, arg2) : new Buffer(arg, arg2);
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
function expandoBuffer(constructor, rate) {
|
|
4555
|
+
var capacity = 0,
|
|
4556
|
+
k = rate >= 1 ? rate : 1.2,
|
|
4557
|
+
buf;
|
|
4558
|
+
return function(size) {
|
|
4559
|
+
if (size > capacity) {
|
|
4560
|
+
capacity = Math.ceil(size * k);
|
|
4561
|
+
buf = constructor ? new constructor(capacity) : createBuffer(capacity);
|
|
4562
|
+
}
|
|
4563
|
+
return buf;
|
|
4564
|
+
};
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4567
|
+
function copyElements(src, i, dest, j, n, rev) {
|
|
4568
|
+
if (src === dest && j > i) error ("copy error");
|
|
4569
|
+
var inc = 1,
|
|
4570
|
+
offs = 0;
|
|
4571
|
+
if (rev) {
|
|
4572
|
+
inc = -1;
|
|
4573
|
+
offs = n - 1;
|
|
4574
|
+
}
|
|
4575
|
+
for (var k=0; k<n; k++, offs += inc) {
|
|
4576
|
+
dest[k + j] = src[i + offs];
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
function extendBuffer(src, newLen, copyLen) {
|
|
4581
|
+
var len = Math.max(src.length, newLen);
|
|
4582
|
+
var n = copyLen || src.length;
|
|
4583
|
+
var dest = new src.constructor(len);
|
|
4584
|
+
copyElements(src, 0, dest, 0, n);
|
|
4585
|
+
return dest;
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
function mergeNames(name1, name2) {
|
|
4589
|
+
var merged;
|
|
4590
|
+
if (name1 && name2) {
|
|
4591
|
+
merged = findStringPrefix(name1, name2).replace(/[-_]$/, '');
|
|
4592
|
+
}
|
|
4593
|
+
return merged || '';
|
|
4594
|
+
}
|
|
4595
|
+
|
|
4596
|
+
function findStringPrefix(a, b) {
|
|
4597
|
+
var i = 0;
|
|
4598
|
+
for (var n=a.length; i<n; i++) {
|
|
4599
|
+
if (a[i] !== b[i]) break;
|
|
4600
|
+
}
|
|
4601
|
+
return a.substr(0, i);
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4604
|
+
function parsePercent(o) {
|
|
4605
|
+
var str = String(o);
|
|
4606
|
+
var isPct = str.indexOf('%') > 0;
|
|
4607
|
+
var pct;
|
|
4608
|
+
if (isPct) {
|
|
4609
|
+
pct = Number(str.replace('%', '')) / 100;
|
|
4610
|
+
} else {
|
|
4611
|
+
pct = Number(str);
|
|
4612
|
+
}
|
|
4613
|
+
if (!(pct >= 0 && pct <= 1)) {
|
|
4614
|
+
stop(format("Invalid percentage: %s", str));
|
|
4615
|
+
}
|
|
4616
|
+
return pct;
|
|
4617
|
+
}
|
|
4618
|
+
|
|
4619
|
+
function formatVersionedName(name, i) {
|
|
4620
|
+
var suffix = String(i);
|
|
4621
|
+
if (/[0-9]$/.test(name)) {
|
|
4622
|
+
suffix = '-' + suffix;
|
|
4623
|
+
}
|
|
4624
|
+
return name + suffix;
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
function uniqifyNames(names, formatter) {
|
|
4628
|
+
var counts = countValues(names),
|
|
4629
|
+
format = formatter || formatVersionedName,
|
|
4630
|
+
names2 = [];
|
|
4631
|
+
|
|
4632
|
+
names.forEach(function(name) {
|
|
4633
|
+
var i = 0,
|
|
4634
|
+
candidate = name,
|
|
4635
|
+
versionedName;
|
|
4636
|
+
while (
|
|
4637
|
+
names2.indexOf(candidate) > -1 || // candidate name has already been used
|
|
4638
|
+
candidate == name && counts[candidate] > 1 || // duplicate unversioned names
|
|
4639
|
+
candidate != name && counts[candidate] > 0) { // versioned name is a preexisting name
|
|
4640
|
+
i++;
|
|
4641
|
+
versionedName = format(name, i);
|
|
4642
|
+
if (!versionedName || versionedName == candidate) {
|
|
4643
|
+
throw new Error("Naming error"); // catch buggy versioning function
|
|
4644
|
+
}
|
|
4645
|
+
candidate = versionedName;
|
|
4646
|
+
}
|
|
4647
|
+
names2.push(candidate);
|
|
4648
|
+
});
|
|
4649
|
+
return names2;
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
|
|
4653
|
+
// Assume: @raw is string, undefined or null
|
|
4654
|
+
function parseString(raw) {
|
|
4655
|
+
return raw ? raw : "";
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4658
|
+
// Assume: @raw is string, undefined or null
|
|
4659
|
+
// Use null instead of NaN for unparsable values
|
|
4660
|
+
// (in part because if NaN is used, empty strings get converted to "NaN"
|
|
4661
|
+
// when re-exported).
|
|
4662
|
+
function parseNumber(raw) {
|
|
4663
|
+
return parseToNum(raw, cleanNumericString);
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4666
|
+
function parseIntlNumber(raw) {
|
|
4667
|
+
return parseToNum(raw, convertIntlNumString);
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4670
|
+
function parseToNum(raw, clean) {
|
|
4671
|
+
var str = String(raw).trim();
|
|
4672
|
+
var parsed = str ? Number(clean(str)) : NaN;
|
|
4673
|
+
return isNaN(parsed) ? null : parsed;
|
|
4674
|
+
}
|
|
4675
|
+
|
|
4676
|
+
// Remove comma separators from strings
|
|
4677
|
+
function cleanNumericString(str) {
|
|
4678
|
+
return (str.indexOf(',') > 0) ? str.replace(/,([0-9]{3})/g, '$1') : str;
|
|
4679
|
+
}
|
|
4680
|
+
|
|
4681
|
+
function convertIntlNumString(str) {
|
|
4682
|
+
str = str.replace(/[ .]([0-9]{3})/g, '$1');
|
|
4683
|
+
return str.replace(',', '.');
|
|
4684
|
+
}
|
|
4685
|
+
|
|
4686
|
+
function trimQuotes(raw) {
|
|
4687
|
+
var len = raw.length, first, last;
|
|
4688
|
+
if (len >= 2) {
|
|
4689
|
+
first = raw.charAt(0);
|
|
4690
|
+
last = raw.charAt(len-1);
|
|
4691
|
+
if (first == '"' && last == '"' && !raw.includes('","') ||
|
|
4692
|
+
first == "'" && last == "'" && !raw.includes("','")) {
|
|
4693
|
+
return raw.substr(1, len-2);
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
return raw;
|
|
4697
|
+
}
|
|
4698
|
+
|
|
4699
|
+
var context = createContext(); // command context (persist for the current command cycle)
|
|
4700
|
+
|
|
4701
|
+
function runningInBrowser() {
|
|
4702
|
+
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
function getStateVar(key) {
|
|
4706
|
+
return context[key];
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
function setStateVar(key, val) {
|
|
4710
|
+
context[key] = val;
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4713
|
+
function createContext() {
|
|
4714
|
+
return {
|
|
4715
|
+
DEBUG: false,
|
|
4716
|
+
QUIET: false,
|
|
4717
|
+
VERBOSE: false,
|
|
4718
|
+
defs: {},
|
|
4719
|
+
input_files: []
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
// Install a new set of context variables, clear them when an async callback is called.
|
|
4724
|
+
// @cb callback function to wrap
|
|
4725
|
+
// returns wrapped callback function
|
|
4726
|
+
function createAsyncContext(cb) {
|
|
4727
|
+
context = createContext();
|
|
4728
|
+
return function() {
|
|
4729
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4730
|
+
// clear context after cb(), so output/errors can be handled in current context
|
|
4731
|
+
context = createContext();
|
|
4732
|
+
};
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
// Save the current context, restore it when an async callback is called
|
|
4736
|
+
// @cb callback function to wrap
|
|
4737
|
+
// returns wrapped callback function
|
|
4738
|
+
function preserveContext(cb) {
|
|
4739
|
+
var ctx = context;
|
|
4740
|
+
return function() {
|
|
4741
|
+
context = ctx;
|
|
4742
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
var LOGGING = false;
|
|
4747
|
+
var STDOUT = false; // use stdout for status messages
|
|
4748
|
+
|
|
4749
|
+
// These three functions can be reset by GUI using setLoggingFunctions();
|
|
4750
|
+
var _error = function() {
|
|
4751
|
+
var msg = utils.toArray(arguments).join(' ');
|
|
4752
|
+
throw new Error(msg);
|
|
4753
|
+
};
|
|
4754
|
+
|
|
4755
|
+
var _stop = function() {
|
|
4756
|
+
throw new UserError(formatLogArgs(arguments));
|
|
4757
|
+
};
|
|
4758
|
+
|
|
4759
|
+
var _interrupt = function() {
|
|
4760
|
+
throw new NonFatalError(formatLogArgs(arguments));
|
|
4761
|
+
};
|
|
4762
|
+
|
|
4763
|
+
var _message = function() {
|
|
4764
|
+
logArgs(arguments);
|
|
4765
|
+
};
|
|
4766
|
+
|
|
4767
|
+
function enableLogging() {
|
|
4768
|
+
LOGGING = true;
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4771
|
+
function loggingEnabled() {
|
|
4772
|
+
return !!LOGGING;
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
// Handle an unexpected condition (internal error)
|
|
4776
|
+
function error() {
|
|
4777
|
+
_error.apply(null, utils.toArray(arguments));
|
|
4778
|
+
}
|
|
4779
|
+
|
|
4780
|
+
// Handle an error caused by invalid input or misuse of API
|
|
4781
|
+
function stop() {
|
|
4782
|
+
_stop.apply(null, utils.toArray(arguments));
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
function interrupt() {
|
|
4786
|
+
_interrupt.apply(null, utils.toArray(arguments));
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
// Print a status message
|
|
4790
|
+
function message() {
|
|
4791
|
+
_message.apply(null, messageArgs(arguments));
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4794
|
+
// A way for the GUI to replace the CLI logging functions
|
|
4795
|
+
function setLoggingFunctions(message, error, stop) {
|
|
4796
|
+
_message = message;
|
|
4797
|
+
_error = error;
|
|
4798
|
+
_stop = stop;
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
|
|
4802
|
+
// print a message to stdout
|
|
4803
|
+
function print() {
|
|
4804
|
+
STDOUT = true; // tell logArgs() to print to stdout, not stderr
|
|
4805
|
+
message.apply(null, arguments);
|
|
4806
|
+
STDOUT = false;
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
function verbose() {
|
|
4810
|
+
// verbose can be set globally with the -verbose command or separately for each command
|
|
4811
|
+
if (getStateVar('VERBOSE') || getStateVar('verbose')) {
|
|
4812
|
+
message.apply(null, arguments);
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
|
|
4816
|
+
function debug() {
|
|
4817
|
+
if (getStateVar('DEBUG') || getStateVar('debug')) {
|
|
4818
|
+
logArgs(arguments);
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
function printError(err) {
|
|
4823
|
+
var msg;
|
|
4824
|
+
if (!LOGGING) return;
|
|
4825
|
+
if (utils.isString(err)) {
|
|
4826
|
+
err = new UserError(err);
|
|
4827
|
+
}
|
|
4828
|
+
if (err.name == 'NonFatalError') {
|
|
4829
|
+
console.error(messageArgs([err.message]).join(' '));
|
|
4830
|
+
} else if (err.name == 'UserError') {
|
|
4831
|
+
msg = err.message;
|
|
4832
|
+
if (!/Error/.test(msg)) {
|
|
4833
|
+
msg = "Error: " + msg;
|
|
4834
|
+
}
|
|
4835
|
+
console.error(messageArgs([msg]).join(' '));
|
|
4836
|
+
console.error("Run mapshaper -h to view help");
|
|
4837
|
+
} else {
|
|
4838
|
+
// not a user error (i.e. a bug in mapshaper)
|
|
4839
|
+
console.error(err);
|
|
4840
|
+
// throw err;
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
function UserError(msg) {
|
|
4845
|
+
var err = new Error(msg);
|
|
4846
|
+
err.name = 'UserError';
|
|
4847
|
+
return err;
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4850
|
+
function NonFatalError(msg) {
|
|
4851
|
+
var err = new Error(msg);
|
|
4852
|
+
err.name = 'NonFatalError';
|
|
4853
|
+
return err;
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4856
|
+
function formatColumns(arr, alignments) {
|
|
4857
|
+
var widths = arr.reduce(function(memo, line) {
|
|
4858
|
+
return line.map(function(str, i) {
|
|
4859
|
+
return memo ? Math.max(memo[i], str.length) : str.length;
|
|
4860
|
+
});
|
|
4861
|
+
}, null);
|
|
4862
|
+
return arr.map(function(line) {
|
|
4863
|
+
line = line.map(function(str, i) {
|
|
4864
|
+
var rt = alignments && alignments[i] == 'right';
|
|
4865
|
+
var pad = (rt ? str.padStart : str.padEnd).bind(str);
|
|
4866
|
+
return pad(widths[i], ' ');
|
|
4867
|
+
});
|
|
4868
|
+
return ' ' + line.join(' ');
|
|
4869
|
+
}).join('\n');
|
|
4870
|
+
}
|
|
4871
|
+
|
|
4872
|
+
// Format an array of (preferably short) strings in columns for console logging.
|
|
4873
|
+
function formatStringsAsGrid(arr) {
|
|
4874
|
+
// TODO: variable column width
|
|
4875
|
+
var longest = arr.reduce(function(len, str) {
|
|
4876
|
+
return Math.max(len, str.length);
|
|
4877
|
+
}, 0),
|
|
4878
|
+
colWidth = longest + 2,
|
|
4879
|
+
perLine = Math.floor(80 / colWidth) || 1;
|
|
4880
|
+
return arr.reduce(function(memo, name, i) {
|
|
4881
|
+
var col = i % perLine;
|
|
4882
|
+
if (i > 0 && col === 0) memo += '\n';
|
|
4883
|
+
if (col < perLine - 1) { // right-pad all but rightmost column
|
|
4884
|
+
name = utils.rpad(name, colWidth - 2, ' ');
|
|
4885
|
+
}
|
|
4886
|
+
return memo + ' ' + name;
|
|
4887
|
+
}, '');
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
// expose so GUI can use it
|
|
4891
|
+
function formatLogArgs(args) {
|
|
4892
|
+
return utils.toArray(args).join(' ');
|
|
4893
|
+
}
|
|
4894
|
+
|
|
4895
|
+
function messageArgs(args) {
|
|
4896
|
+
var arr = utils.toArray(args);
|
|
4897
|
+
var cmd = getStateVar('current_command');
|
|
4898
|
+
if (cmd && cmd != 'help') {
|
|
4899
|
+
arr.unshift('[' + cmd + ']');
|
|
4900
|
+
}
|
|
4901
|
+
return arr;
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4904
|
+
function logArgs(args) {
|
|
4905
|
+
if (!LOGGING || getStateVar('QUIET') || !utils.isArrayLike(args)) return;
|
|
4906
|
+
var msg = formatLogArgs(args);
|
|
4907
|
+
if (STDOUT) console.log(msg);
|
|
4908
|
+
else console.error(msg);
|
|
4909
|
+
}
|
|
4910
|
+
|
|
4911
|
+
// Utility functions for both paths and points
|
|
4912
|
+
|
|
4913
|
+
// @shp An element of the layer.shapes array
|
|
4914
|
+
// (may be null, or, depending on layer type, an array of points or an array of arrays of arc ids)
|
|
4915
|
+
function cloneShape(shp) {
|
|
4916
|
+
if (!shp) return null;
|
|
4917
|
+
return shp.map(function(part) {
|
|
4918
|
+
return part.concat();
|
|
4919
|
+
});
|
|
4920
|
+
}
|
|
4921
|
+
|
|
4922
|
+
function cloneShapes(arr) {
|
|
4923
|
+
return utils.isArray(arr) ? arr.map(cloneShape) : null;
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4926
|
+
function forEachShapePart(paths, cb) {
|
|
4927
|
+
editShapeParts(paths, cb);
|
|
4928
|
+
}
|
|
4929
|
+
|
|
4930
|
+
// Updates shapes array in-place.
|
|
4931
|
+
// editPart: callback function
|
|
4932
|
+
function editShapes(shapes, editPart) {
|
|
4933
|
+
for (var i=0, n=shapes.length; i<n; i++) {
|
|
4934
|
+
shapes[i] = editShapeParts(shapes[i], editPart);
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
|
|
4938
|
+
// @parts: geometry of a feature (array of paths, array of points or null)
|
|
4939
|
+
// @cb: function(part, i, parts)
|
|
4940
|
+
// If @cb returns an array, it replaces the existing value
|
|
4941
|
+
// If @cb returns null, the path is removed from the feature
|
|
4942
|
+
//
|
|
4943
|
+
function editShapeParts(parts, cb) {
|
|
4944
|
+
if (!parts) return null; // null geometry not edited
|
|
4945
|
+
if (!utils.isArray(parts)) error("Expected an array, received:", parts);
|
|
4946
|
+
var nulls = 0,
|
|
4947
|
+
n = parts.length,
|
|
4948
|
+
retn;
|
|
4949
|
+
|
|
4950
|
+
for (var i=0; i<n; i++) {
|
|
4951
|
+
retn = cb(parts[i], i, parts);
|
|
4952
|
+
if (retn === null) {
|
|
4953
|
+
nulls++;
|
|
4954
|
+
parts[i] = null;
|
|
4955
|
+
} else if (utils.isArray(retn)) {
|
|
4956
|
+
parts[i] = retn;
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
if (nulls == n) {
|
|
4960
|
+
return null;
|
|
4961
|
+
} else if (nulls > 0) {
|
|
4962
|
+
return parts.filter(function(part) {return !!part;});
|
|
4963
|
+
} else {
|
|
4964
|
+
return parts;
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
|
|
4968
|
+
// Get max number of parts in a single shape from an array of shapes.
|
|
4969
|
+
// Caveat: polygon holes are counted as separate parts.
|
|
4970
|
+
function findMaxPartCount(shapes) {
|
|
4971
|
+
var maxCount = 0, shp;
|
|
4972
|
+
for (var i=0, n=shapes.length; i<n; i++) {
|
|
4973
|
+
shp = shapes[i];
|
|
4974
|
+
if (shp && shp.length > maxCount) {
|
|
4975
|
+
maxCount = shp.length;
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
return maxCount;
|
|
4979
|
+
}
|
|
4980
|
+
|
|
4981
|
+
// List of encodings supported by iconv-lite:
|
|
4982
|
+
// https://github.com/ashtuchkin/iconv-lite/wiki/Supported-Encodings
|
|
4983
|
+
|
|
4984
|
+
var iconv = require('iconv-lite');
|
|
4985
|
+
var toUtf8 = getNativeEncoder('utf8');
|
|
4986
|
+
var fromUtf8 = getNativeDecoder('utf8');
|
|
4987
|
+
|
|
4988
|
+
// Return list of supported encodings
|
|
4989
|
+
function getEncodings() {
|
|
4990
|
+
iconv.encodingExists('ascii'); // make iconv load its encodings
|
|
4991
|
+
return Object.keys(iconv.encodings);
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4994
|
+
function validateEncoding(enc) {
|
|
4995
|
+
if (!encodingIsSupported(enc)) {
|
|
4996
|
+
stop("Unknown encoding:", enc, "\nRun the -encodings command see a list of supported encodings");
|
|
4997
|
+
}
|
|
4998
|
+
return enc;
|
|
4999
|
+
}
|
|
5000
|
+
|
|
5001
|
+
function stringsAreAscii(arr) {
|
|
5002
|
+
return stringIsAscii(arr.join(''));
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
function stringIsAscii(str) {
|
|
5006
|
+
var c;
|
|
5007
|
+
for (var i=0, n=str.length; i<n; i++) {
|
|
5008
|
+
c = str.charCodeAt(i);
|
|
5009
|
+
if (c >= 128) return false;
|
|
5010
|
+
}
|
|
5011
|
+
return true;
|
|
5012
|
+
}
|
|
5013
|
+
|
|
5014
|
+
function encodingIsUtf8(enc) {
|
|
5015
|
+
// treating utf-8 as default
|
|
5016
|
+
return !enc || /^utf-?8$/i.test(String(enc));
|
|
5017
|
+
}
|
|
5018
|
+
|
|
5019
|
+
// Identify the most common encodings that are supersets of ascii at the
|
|
5020
|
+
// single-byte level (meaning that bytes in 0 - 0x7f range must be ascii)
|
|
5021
|
+
// (this allows identifying line breaks and other ascii patterns in buffers)
|
|
5022
|
+
function encodingIsAsciiCompat(enc) {
|
|
5023
|
+
enc = standardizeEncodingName(enc);
|
|
5024
|
+
// gb.* selects the Guo Biao encodings
|
|
5025
|
+
// big5 in not compatible -- second byte starts at 0x40
|
|
5026
|
+
return !enc || /^(win|latin|utf8|ascii|iso88|gb)/.test(enc);
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
// Ex. convert UTF-8 to utf8
|
|
5030
|
+
function standardizeEncodingName(enc) {
|
|
5031
|
+
return (enc || '').toLowerCase().replace(/[_-]/g, '');
|
|
5032
|
+
}
|
|
5033
|
+
|
|
5034
|
+
// Similar to Buffer#toString(); tries to speed up utf8 conversion in
|
|
5035
|
+
// web browser (when using browserify Buffer shim)
|
|
5036
|
+
function bufferToString(buf, enc, start, end) {
|
|
5037
|
+
if (start >= 0) {
|
|
5038
|
+
buf = buf.slice(start, end);
|
|
5039
|
+
}
|
|
5040
|
+
return decodeString(buf, enc);
|
|
5041
|
+
}
|
|
5042
|
+
|
|
5043
|
+
function getNativeEncoder(enc) {
|
|
5044
|
+
var encoder = null;
|
|
5045
|
+
enc = standardizeEncodingName(enc);
|
|
5046
|
+
if (enc != 'utf8') {
|
|
5047
|
+
// TODO: support more encodings if TextEncoder is available
|
|
5048
|
+
return null;
|
|
5049
|
+
}
|
|
5050
|
+
if (typeof TextEncoder != 'undefined') {
|
|
5051
|
+
encoder = new TextEncoder(enc);
|
|
5052
|
+
}
|
|
5053
|
+
return function(str) {
|
|
5054
|
+
// Convert Uint8Array from encoder to Buffer (fix for issue #216)
|
|
5055
|
+
return encoder ? Buffer.from(encoder.encode(str).buffer) : utils.createBuffer(str, enc);
|
|
5056
|
+
};
|
|
5057
|
+
}
|
|
5058
|
+
|
|
5059
|
+
function encodeString(str, enc) {
|
|
5060
|
+
// TODO: faster ascii encoding?
|
|
5061
|
+
var buf;
|
|
5062
|
+
if (encodingIsUtf8(enc)) {
|
|
5063
|
+
buf = toUtf8(str);
|
|
5064
|
+
} else {
|
|
5065
|
+
buf = iconv.encode(str, enc);
|
|
5066
|
+
}
|
|
5067
|
+
return buf;
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
function getNativeDecoder(enc) {
|
|
5071
|
+
var decoder = null;
|
|
5072
|
+
enc = standardizeEncodingName(enc);
|
|
5073
|
+
if (enc != 'utf8') {
|
|
5074
|
+
// TODO: support more encodings if TextDecoder is available
|
|
5075
|
+
return null;
|
|
5076
|
+
}
|
|
5077
|
+
if (typeof TextDecoder != 'undefined') {
|
|
5078
|
+
decoder = new TextDecoder(enc);
|
|
5079
|
+
}
|
|
5080
|
+
return function(buf) {
|
|
5081
|
+
return decoder ? decoder.decode(buf) : buf.toString(enc);
|
|
5082
|
+
};
|
|
5083
|
+
}
|
|
5084
|
+
|
|
5085
|
+
// @buf a Node Buffer
|
|
5086
|
+
function decodeString(buf, enc) {
|
|
5087
|
+
var str;
|
|
5088
|
+
if (encodingIsUtf8(enc)) {
|
|
5089
|
+
str = fromUtf8(buf);
|
|
5090
|
+
} else {
|
|
5091
|
+
str = iconv.decode(buf, enc);
|
|
5092
|
+
}
|
|
5093
|
+
return str;
|
|
5094
|
+
}
|
|
5095
|
+
|
|
5096
|
+
function encodingIsSupported(raw) {
|
|
5097
|
+
var enc = standardizeEncodingName(raw);
|
|
5098
|
+
return getEncodings().includes(enc);
|
|
5099
|
+
}
|
|
3382
5100
|
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
gui.session.layerRenamed(target.layer, str);
|
|
3391
|
-
updateMenuBtn();
|
|
3392
|
-
});
|
|
5101
|
+
function trimBOM(str) {
|
|
5102
|
+
// remove BOM if present
|
|
5103
|
+
if (str.charCodeAt(0) == 0xfeff) {
|
|
5104
|
+
str = str.substr(1);
|
|
5105
|
+
}
|
|
5106
|
+
return str;
|
|
5107
|
+
}
|
|
3393
5108
|
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
5109
|
+
function printEncodings() {
|
|
5110
|
+
var encodings = getEncodings().filter(function(name) {
|
|
5111
|
+
// filter out some aliases and non-applicable encodings
|
|
5112
|
+
return !/^(_|cs|internal|ibm|isoir|singlebyte|table|[0-9]|l[0-9]|windows)/.test(name);
|
|
5113
|
+
});
|
|
5114
|
+
encodings.sort();
|
|
5115
|
+
print("Supported encodings:\n" + formatStringsAsGrid(encodings));
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
// Not a general-purpose deep copy function
|
|
5119
|
+
function copyRecord(o) {
|
|
5120
|
+
var o2 = {}, key, val;
|
|
5121
|
+
if (!o) return null;
|
|
5122
|
+
for (key in o) {
|
|
5123
|
+
if (o.hasOwnProperty(key)) {
|
|
5124
|
+
val = o[key];
|
|
5125
|
+
if (val == o) {
|
|
5126
|
+
// avoid infinite recursion if val is a circular reference, by copying all properties except key
|
|
5127
|
+
val = utils.extend({}, val);
|
|
5128
|
+
delete val[key];
|
|
3403
5129
|
}
|
|
3404
|
-
|
|
5130
|
+
o2[key] = val && val.constructor === Object ? copyRecord(val) : val;
|
|
5131
|
+
}
|
|
3405
5132
|
}
|
|
5133
|
+
return o2;
|
|
5134
|
+
}
|
|
3406
5135
|
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
5136
|
+
function getValueType(val) {
|
|
5137
|
+
var type = null;
|
|
5138
|
+
if (utils.isString(val)) {
|
|
5139
|
+
type = 'string';
|
|
5140
|
+
} else if (utils.isNumber(val)) {
|
|
5141
|
+
type = 'number';
|
|
5142
|
+
} else if (utils.isBoolean(val)) {
|
|
5143
|
+
type = 'boolean';
|
|
5144
|
+
} else if (utils.isDate(val)) {
|
|
5145
|
+
type = 'date';
|
|
5146
|
+
} else if (utils.isObject(val)) {
|
|
5147
|
+
type = 'object';
|
|
5148
|
+
}
|
|
5149
|
+
return type;
|
|
5150
|
+
}
|
|
5151
|
+
|
|
5152
|
+
// Fill out a data table with undefined values
|
|
5153
|
+
// The undefined members will disappear when records are exported as JSON,
|
|
5154
|
+
// but will show up when fields are listed using Object.keys()
|
|
5155
|
+
function fixInconsistentFields(records) {
|
|
5156
|
+
var fields = findIncompleteFields(records);
|
|
5157
|
+
patchMissingFields(records, fields);
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
function findIncompleteFields(records) {
|
|
5161
|
+
var counts = {},
|
|
5162
|
+
i, j, keys;
|
|
5163
|
+
for (i=0; i<records.length; i++) {
|
|
5164
|
+
keys = Object.keys(records[i] || {});
|
|
5165
|
+
for (j=0; j<keys.length; j++) {
|
|
5166
|
+
counts[keys[j]] = (counts[keys[j]] | 0) + 1;
|
|
3419
5167
|
}
|
|
3420
|
-
return str;
|
|
3421
5168
|
}
|
|
5169
|
+
return Object.keys(counts).filter(function(k) {return counts[k] < records.length;});
|
|
5170
|
+
}
|
|
3422
5171
|
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
5172
|
+
function patchMissingFields(records, fields) {
|
|
5173
|
+
var rec, i, j, f;
|
|
5174
|
+
for (i=0; i<records.length; i++) {
|
|
5175
|
+
rec = records[i] || (records[i] = {});
|
|
5176
|
+
for (j=0; j<fields.length; j++) {
|
|
5177
|
+
f = fields[j];
|
|
5178
|
+
if (f in rec === false) {
|
|
5179
|
+
rec[f] = undefined;
|
|
3430
5180
|
}
|
|
3431
|
-
if (!dataset.info.prj && !dataset.info.crs) {
|
|
3432
|
-
missing.push('.prj');
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
if (missing.length) {
|
|
3436
|
-
msg = 'missing ' + missing.join(' and ') + ' data';
|
|
3437
5181
|
}
|
|
3438
|
-
return msg;
|
|
3439
5182
|
}
|
|
5183
|
+
}
|
|
3440
5184
|
|
|
3441
|
-
|
|
3442
|
-
|
|
5185
|
+
function fieldListContainsAll(list, fields) {
|
|
5186
|
+
return list.indexOf('*') > -1 || utils.difference(fields, list).length === 0;
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5189
|
+
function getColumnType(key, records) {
|
|
5190
|
+
var type = null,
|
|
5191
|
+
rec;
|
|
5192
|
+
for (var i=0, n=records.length; i<n; i++) {
|
|
5193
|
+
rec = records[i];
|
|
5194
|
+
type = rec ? getValueType(rec[key]) : null;
|
|
5195
|
+
if (type) break;
|
|
3443
5196
|
}
|
|
5197
|
+
return type;
|
|
5198
|
+
}
|
|
5199
|
+
|
|
5200
|
+
function deleteFields(table, test) {
|
|
5201
|
+
table.getFields().forEach(function(name) {
|
|
5202
|
+
if (test(name)) {
|
|
5203
|
+
table.deleteField(name);
|
|
5204
|
+
}
|
|
5205
|
+
});
|
|
5206
|
+
}
|
|
3444
5207
|
|
|
5208
|
+
function isInvalidFieldName(f) {
|
|
5209
|
+
// Reject empty and all-whitespace strings. TODO: consider other criteria
|
|
5210
|
+
return /^\s*$/.test(f);
|
|
5211
|
+
}
|
|
3445
5212
|
|
|
3446
|
-
|
|
3447
|
-
|
|
5213
|
+
// Resolve name conflicts in field names by appending numbers
|
|
5214
|
+
// @fields Array of field names
|
|
5215
|
+
// @maxLen (optional) Maximum chars in name
|
|
5216
|
+
//
|
|
5217
|
+
function getUniqFieldNames(fields, maxLen, encoding) {
|
|
5218
|
+
var used = {};
|
|
5219
|
+
return fields.map(function(name) {
|
|
5220
|
+
var i = 0,
|
|
5221
|
+
validName;
|
|
5222
|
+
do {
|
|
5223
|
+
validName = encoding && encoding != 'ascii' ?
|
|
5224
|
+
adjustEncodedFieldName(name, maxLen, i, encoding) :
|
|
5225
|
+
adjustFieldName(name, maxLen, i);
|
|
5226
|
+
i++;
|
|
5227
|
+
} while ((validName in used) ||
|
|
5228
|
+
// don't replace an existing valid field name with a truncated name
|
|
5229
|
+
name != validName && utils.contains(fields, validName));
|
|
5230
|
+
used[validName] = true;
|
|
5231
|
+
return validName;
|
|
5232
|
+
});
|
|
5233
|
+
}
|
|
5234
|
+
|
|
5235
|
+
function getFieldValues(records, field) {
|
|
5236
|
+
return records.map(function(rec) {
|
|
5237
|
+
return rec ? rec[field] : undefined;
|
|
5238
|
+
});
|
|
5239
|
+
}
|
|
5240
|
+
|
|
5241
|
+
function getUniqFieldValues(records, field) {
|
|
5242
|
+
var index = {};
|
|
5243
|
+
var values = [];
|
|
5244
|
+
records.forEach(function(rec) {
|
|
5245
|
+
var val = rec[field];
|
|
5246
|
+
if (val in index === false) {
|
|
5247
|
+
index[val] = true;
|
|
5248
|
+
values.push(val);
|
|
5249
|
+
}
|
|
5250
|
+
});
|
|
5251
|
+
return values;
|
|
5252
|
+
}
|
|
5253
|
+
|
|
5254
|
+
// Truncate and/or uniqify a name (if relevant params are present)
|
|
5255
|
+
function adjustFieldName(name, maxLen, i) {
|
|
5256
|
+
var name2, suff;
|
|
5257
|
+
maxLen = maxLen || 256;
|
|
5258
|
+
if (!i) {
|
|
5259
|
+
name2 = name.substr(0, maxLen);
|
|
5260
|
+
} else {
|
|
5261
|
+
suff = String(i);
|
|
5262
|
+
if (suff.length == 1) {
|
|
5263
|
+
suff = '_' + suff;
|
|
5264
|
+
}
|
|
5265
|
+
name2 = name.substr(0, maxLen - suff.length) + suff;
|
|
3448
5266
|
}
|
|
5267
|
+
return name2;
|
|
5268
|
+
}
|
|
3449
5269
|
|
|
5270
|
+
// Truncate and/or uniqify a name (if relevant params are present)
|
|
5271
|
+
function adjustEncodedFieldName(name, maxLen, i, encoding) {
|
|
5272
|
+
var suff = i ? String(i) : '';
|
|
5273
|
+
var name2 = name + suff;
|
|
5274
|
+
var buf = encodeString(name2, encoding);
|
|
5275
|
+
if (buf.length > (maxLen || 256)) {
|
|
5276
|
+
name = name.substr(0, name.length - 1);
|
|
5277
|
+
return adjustEncodedFieldName(name, maxLen, i, encoding);
|
|
5278
|
+
}
|
|
5279
|
+
return name2;
|
|
5280
|
+
}
|
|
3450
5281
|
|
|
5282
|
+
function applyFieldOrder(arr, option) {
|
|
5283
|
+
if (option == 'ascending') {
|
|
5284
|
+
arr.sort(function(a, b) {
|
|
5285
|
+
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
|
|
5286
|
+
});
|
|
5287
|
+
}
|
|
5288
|
+
return arr;
|
|
5289
|
+
}
|
|
3451
5290
|
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
5291
|
+
function getFirstNonEmptyRecord(records) {
|
|
5292
|
+
for (var i=0, n=records ? records.length : 0; i<n; i++) {
|
|
5293
|
+
if (records[i]) return records[i];
|
|
3455
5294
|
}
|
|
5295
|
+
return null;
|
|
3456
5296
|
}
|
|
3457
5297
|
|
|
3458
|
-
function
|
|
3459
|
-
var
|
|
3460
|
-
|
|
3461
|
-
|
|
5298
|
+
function findFieldNames(records, order) {
|
|
5299
|
+
var first = getFirstNonEmptyRecord(records);
|
|
5300
|
+
var names = first ? Object.keys(first) : [];
|
|
5301
|
+
return applyFieldOrder(names, order);
|
|
5302
|
+
}
|
|
3462
5303
|
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
cmdName = getCommandName(commands[i]);
|
|
3467
|
-
if (cmdName == 'o') break;
|
|
3468
|
-
if (nonEditingCommands.includes(cmdName)) continue;
|
|
3469
|
-
return true;
|
|
3470
|
-
}
|
|
3471
|
-
return false;
|
|
3472
|
-
};
|
|
5304
|
+
function Undo(gui) {
|
|
5305
|
+
var history, offset, stashedUndo;
|
|
5306
|
+
reset();
|
|
3473
5307
|
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
commands.push(cmd);
|
|
3480
|
-
};
|
|
5308
|
+
function reset() {
|
|
5309
|
+
history = [];
|
|
5310
|
+
stashedUndo = null;
|
|
5311
|
+
offset = 0;
|
|
5312
|
+
}
|
|
3481
5313
|
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
if (currTarget == layerTarget) {
|
|
3486
|
-
commands.push('-rename-layers ' + name);
|
|
3487
|
-
} else {
|
|
3488
|
-
commands.push('-rename-layers ' + name + ' target=' + layerTarget);
|
|
3489
|
-
commands.push('-target ' + currTarget);
|
|
3490
|
-
}
|
|
3491
|
-
};
|
|
5314
|
+
function refreshMap() {
|
|
5315
|
+
gui.dispatchEvent('undo_redo');
|
|
5316
|
+
}
|
|
3492
5317
|
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
}
|
|
5318
|
+
function isUndoEvt(e) {
|
|
5319
|
+
return (e.ctrlKey || e.metaKey) && !e.shiftKey && e.key == 'z';
|
|
5320
|
+
}
|
|
3496
5321
|
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
}
|
|
5322
|
+
function isRedoEvt(e) {
|
|
5323
|
+
return (e.ctrlKey || e.metaKey) && (e.shiftKey && e.key == 'z' || !e.shiftKey && e.key == 'y');
|
|
5324
|
+
}
|
|
3500
5325
|
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
5326
|
+
gui.keyboard.on('keydown', function(evt) {
|
|
5327
|
+
var e = evt.originalEvent,
|
|
5328
|
+
kc = e.keyCode;
|
|
5329
|
+
if (isUndoEvt(e)) {
|
|
5330
|
+
this.undo();
|
|
5331
|
+
e.stopPropagation();
|
|
5332
|
+
e.preventDefault();
|
|
5333
|
+
}
|
|
5334
|
+
if (isRedoEvt(e)) {
|
|
5335
|
+
this.redo();
|
|
5336
|
+
e.stopPropagation();
|
|
5337
|
+
e.preventDefault();
|
|
3508
5338
|
}
|
|
5339
|
+
|
|
5340
|
+
}, this, 10);
|
|
5341
|
+
|
|
5342
|
+
// undo/redo point/symbol dragging
|
|
5343
|
+
//
|
|
5344
|
+
gui.on('symbol_dragstart', function(e) {
|
|
5345
|
+
stashedUndo = this.makePointSetter(e.FID);
|
|
5346
|
+
}, this);
|
|
5347
|
+
|
|
5348
|
+
gui.on('symbol_dragend', function(e) {
|
|
5349
|
+
var redo = this.makePointSetter(e.FID);
|
|
5350
|
+
this.addHistoryState(stashedUndo, redo);
|
|
5351
|
+
}, this);
|
|
5352
|
+
|
|
5353
|
+
// undo/redo label dragging
|
|
5354
|
+
//
|
|
5355
|
+
gui.on('label_dragstart', function(e) {
|
|
5356
|
+
stashedUndo = this.makeDataSetter(e.FID);
|
|
5357
|
+
}, this);
|
|
5358
|
+
|
|
5359
|
+
gui.on('label_dragend', function(e) {
|
|
5360
|
+
var redo = this.makeDataSetter(e.FID);
|
|
5361
|
+
this.addHistoryState(stashedUndo, redo);
|
|
5362
|
+
}, this);
|
|
5363
|
+
|
|
5364
|
+
this.clear = function() {
|
|
5365
|
+
reset();
|
|
3509
5366
|
};
|
|
3510
5367
|
|
|
3511
|
-
this.
|
|
3512
|
-
var
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
5368
|
+
this.makePointSetter = function(i) {
|
|
5369
|
+
var target = gui.model.getActiveLayer();
|
|
5370
|
+
var shp = cloneShape(target.layer.shapes[i]);
|
|
5371
|
+
return function() {
|
|
5372
|
+
target.layer.shapes[i] = shp;
|
|
5373
|
+
};
|
|
3516
5374
|
};
|
|
3517
5375
|
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
5376
|
+
|
|
5377
|
+
this.makeDataSetter = function(id) {
|
|
5378
|
+
var target = gui.model.getActiveLayer();
|
|
5379
|
+
var rec = copyRecord(target.layer.data.getRecordAt(id));
|
|
5380
|
+
return function() {
|
|
5381
|
+
target.layer.data.getRecords()[id] = rec;
|
|
5382
|
+
gui.dispatchEvent('popup-needs-refresh');
|
|
5383
|
+
};
|
|
3521
5384
|
};
|
|
3522
5385
|
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
}
|
|
3529
|
-
if (optStr) {
|
|
3530
|
-
cmd += ' ' + optStr;
|
|
5386
|
+
|
|
5387
|
+
this.addHistoryState = function(undo, redo) {
|
|
5388
|
+
if (offset > 0) {
|
|
5389
|
+
history.splice(-offset);
|
|
5390
|
+
offset = 0;
|
|
3531
5391
|
}
|
|
3532
|
-
|
|
5392
|
+
history.push({undo, redo});
|
|
3533
5393
|
};
|
|
3534
5394
|
|
|
3535
|
-
this.
|
|
3536
|
-
var
|
|
3537
|
-
if (
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
commands.push('-target ' + getTargetFromLayer(lyr));
|
|
5395
|
+
this.undo = function() {
|
|
5396
|
+
var item = getHistoryItem();
|
|
5397
|
+
if (item) {
|
|
5398
|
+
offset++;
|
|
5399
|
+
item.undo();
|
|
5400
|
+
refreshMap();
|
|
3542
5401
|
}
|
|
3543
5402
|
};
|
|
3544
5403
|
|
|
3545
|
-
this.
|
|
3546
|
-
|
|
3547
|
-
|
|
5404
|
+
this.redo = function() {
|
|
5405
|
+
if (offset <= 0) return;
|
|
5406
|
+
offset--;
|
|
5407
|
+
var item = getHistoryItem();
|
|
5408
|
+
item.redo();
|
|
5409
|
+
refreshMap();
|
|
3548
5410
|
};
|
|
3549
5411
|
|
|
3550
|
-
function
|
|
3551
|
-
var
|
|
3552
|
-
|
|
3553
|
-
return match ? match[1] : null;
|
|
3554
|
-
}
|
|
3555
|
-
|
|
3556
|
-
function getCurrentTarget() {
|
|
3557
|
-
return getTargetFromLayer(gui.model.getActiveLayer().layer);
|
|
3558
|
-
}
|
|
3559
|
-
|
|
3560
|
-
function indexOfLastCommand(cmd) {
|
|
3561
|
-
return commands.reduce(function(memo, str, i) {
|
|
3562
|
-
return str.indexOf(cmd) === 0 ? i : memo;
|
|
3563
|
-
}, -1);
|
|
3564
|
-
}
|
|
3565
|
-
|
|
3566
|
-
function getTargetFromId(id) {
|
|
3567
|
-
var layers = gui.model.getLayers();
|
|
3568
|
-
return getTargetFromLayer(layers[id - 1].layer);
|
|
5412
|
+
function getHistoryItem() {
|
|
5413
|
+
var item = history[history.length - offset - 1];
|
|
5414
|
+
return item || null;
|
|
3569
5415
|
}
|
|
3570
5416
|
|
|
3571
|
-
function getTargetFromLayer(lyr) {
|
|
3572
|
-
var id = internal.getLayerTargetId(gui.model, lyr);
|
|
3573
|
-
return internal.formatOptionValue(id);
|
|
3574
|
-
}
|
|
3575
5417
|
}
|
|
3576
5418
|
|
|
3577
5419
|
function SidebarButtons(gui) {
|
|
@@ -3671,7 +5513,7 @@
|
|
|
3671
5513
|
};
|
|
3672
5514
|
}
|
|
3673
5515
|
|
|
3674
|
-
utils.inherit(ModeSwitcher, EventDispatcher);
|
|
5516
|
+
utils$1.inherit(ModeSwitcher, EventDispatcher);
|
|
3675
5517
|
|
|
3676
5518
|
function KeyboardEvents(gui) {
|
|
3677
5519
|
var self = this;
|
|
@@ -3699,7 +5541,7 @@
|
|
|
3699
5541
|
};
|
|
3700
5542
|
}
|
|
3701
5543
|
|
|
3702
|
-
utils.inherit(KeyboardEvents, EventDispatcher);
|
|
5544
|
+
utils$1.inherit(KeyboardEvents, EventDispatcher);
|
|
3703
5545
|
|
|
3704
5546
|
function InteractionMode(gui) {
|
|
3705
5547
|
|
|
@@ -3915,7 +5757,7 @@
|
|
|
3915
5757
|
function Model(gui) {
|
|
3916
5758
|
var self = new internal.Catalog();
|
|
3917
5759
|
var deleteLayer = self.deleteLayer;
|
|
3918
|
-
utils.extend(self, EventDispatcher.prototype);
|
|
5760
|
+
utils$1.extend(self, EventDispatcher.prototype);
|
|
3919
5761
|
|
|
3920
5762
|
// override Catalog method (so -drop command will work in web console)
|
|
3921
5763
|
self.deleteLayer = function(lyr, dataset) {
|
|
@@ -3949,7 +5791,7 @@
|
|
|
3949
5791
|
if (flags.select) {
|
|
3950
5792
|
self.dispatchEvent('select', active);
|
|
3951
5793
|
}
|
|
3952
|
-
self.dispatchEvent('update', utils.extend({flags: flags}, active));
|
|
5794
|
+
self.dispatchEvent('update', utils$1.extend({flags: flags}, active));
|
|
3953
5795
|
};
|
|
3954
5796
|
|
|
3955
5797
|
self.selectLayer = function(lyr, dataset) {
|
|
@@ -3984,7 +5826,7 @@
|
|
|
3984
5826
|
} else if (geoType == 'polygon') {
|
|
3985
5827
|
test = polygonTest;
|
|
3986
5828
|
} else {
|
|
3987
|
-
error("Unexpected geometry type:", geoType);
|
|
5829
|
+
error$1("Unexpected geometry type:", geoType);
|
|
3988
5830
|
}
|
|
3989
5831
|
return test;
|
|
3990
5832
|
|
|
@@ -4051,7 +5893,7 @@
|
|
|
4051
5893
|
for (var i=0; i<cands.length; i++) {
|
|
4052
5894
|
cands[i].dist = geom.getPointToShapeDistance(x, y, cands[i].shape, arcs);
|
|
4053
5895
|
}
|
|
4054
|
-
utils.sortOn(cands, 'dist');
|
|
5896
|
+
utils$1.sortOn(cands, 'dist');
|
|
4055
5897
|
}
|
|
4056
5898
|
|
|
4057
5899
|
function pointTest(x, y) {
|
|
@@ -4077,7 +5919,7 @@
|
|
|
4077
5919
|
}
|
|
4078
5920
|
});
|
|
4079
5921
|
// console.log(hitThreshold, bullseye);
|
|
4080
|
-
return utils.uniq(hits); // multipoint features can register multiple hits
|
|
5922
|
+
return utils$1.uniq(hits); // multipoint features can register multiple hits
|
|
4081
5923
|
}
|
|
4082
5924
|
|
|
4083
5925
|
function getRadiusFunction(style) {
|
|
@@ -4284,9 +6126,9 @@
|
|
|
4284
6126
|
};
|
|
4285
6127
|
var svgData = svgTest(e); // null or a data object
|
|
4286
6128
|
if (svgData) { // mouse is over an SVG symbol
|
|
4287
|
-
utils.extend(data, svgData);
|
|
6129
|
+
utils$1.extend(data, svgData);
|
|
4288
6130
|
// placing symbol id in front of any other hits
|
|
4289
|
-
data.ids = utils.uniq([svgData.targetId].concat(data.ids));
|
|
6131
|
+
data.ids = utils$1.uniq([svgData.targetId].concat(data.ids));
|
|
4290
6132
|
}
|
|
4291
6133
|
data.id = data.ids.length > 0 ? data.ids[0] : -1;
|
|
4292
6134
|
return data;
|
|
@@ -4387,8 +6229,8 @@
|
|
|
4387
6229
|
|
|
4388
6230
|
self.addSelectionIds = function(ids) {
|
|
4389
6231
|
turnOn('selection');
|
|
4390
|
-
selectionIds = utils.uniq(selectionIds.concat(ids));
|
|
4391
|
-
ids = utils.uniq(storedData.ids.concat(ids));
|
|
6232
|
+
selectionIds = utils$1.uniq(selectionIds.concat(ids));
|
|
6233
|
+
ids = utils$1.uniq(storedData.ids.concat(ids));
|
|
4392
6234
|
updateSelectionState({ids: ids});
|
|
4393
6235
|
};
|
|
4394
6236
|
|
|
@@ -4546,7 +6388,7 @@
|
|
|
4546
6388
|
|
|
4547
6389
|
function toggleId(id, ids) {
|
|
4548
6390
|
if (ids.indexOf(id) > -1) {
|
|
4549
|
-
return utils.difference(ids, [id]);
|
|
6391
|
+
return utils$1.difference(ids, [id]);
|
|
4550
6392
|
}
|
|
4551
6393
|
return [id].concat(ids);
|
|
4552
6394
|
}
|
|
@@ -4598,9 +6440,9 @@
|
|
|
4598
6440
|
// d: event data (may be a pointer event object, an ordinary object or null)
|
|
4599
6441
|
function triggerHitEvent(type, d) {
|
|
4600
6442
|
// Merge stored hit data into the event data
|
|
4601
|
-
var eventData = utils.extend({mode: interactionMode}, d || {}, storedData);
|
|
6443
|
+
var eventData = utils$1.extend({mode: interactionMode}, d || {}, storedData);
|
|
4602
6444
|
if (transientIds.length) {
|
|
4603
|
-
eventData.ids = utils.uniq(transientIds.concat(eventData.ids || []));
|
|
6445
|
+
eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
|
|
4604
6446
|
}
|
|
4605
6447
|
self.dispatchEvent(type, eventData);
|
|
4606
6448
|
}
|
|
@@ -4734,7 +6576,7 @@
|
|
|
4734
6576
|
}
|
|
4735
6577
|
}
|
|
4736
6578
|
|
|
4737
|
-
utils.inherit(Timer, EventDispatcher);
|
|
6579
|
+
utils$1.inherit(Timer, EventDispatcher);
|
|
4738
6580
|
|
|
4739
6581
|
function Tween(ease) {
|
|
4740
6582
|
var self = this,
|
|
@@ -4756,7 +6598,7 @@
|
|
|
4756
6598
|
}
|
|
4757
6599
|
}
|
|
4758
6600
|
|
|
4759
|
-
utils.inherit(Tween, EventDispatcher);
|
|
6601
|
+
utils$1.inherit(Tween, EventDispatcher);
|
|
4760
6602
|
|
|
4761
6603
|
Tween.sineInOut = function(n) {
|
|
4762
6604
|
return 0.5 - Math.cos(n * Math.PI) / 2;
|
|
@@ -4824,7 +6666,7 @@
|
|
|
4824
6666
|
update();
|
|
4825
6667
|
}
|
|
4826
6668
|
|
|
4827
|
-
utils.inherit(ElementPosition, EventDispatcher);
|
|
6669
|
+
utils$1.inherit(ElementPosition, EventDispatcher);
|
|
4828
6670
|
|
|
4829
6671
|
function MouseWheelDirection() {
|
|
4830
6672
|
var prevTime = 0;
|
|
@@ -4922,13 +6764,13 @@
|
|
|
4922
6764
|
// Decelerate towards the end of the sustain interval (for smoother zooming)
|
|
4923
6765
|
multiplier *= Tween.quadraticOut(1 - fadeFactor);
|
|
4924
6766
|
}
|
|
4925
|
-
obj = utils.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
6767
|
+
obj = utils$1.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
4926
6768
|
self.dispatchEvent('mousewheel', obj);
|
|
4927
6769
|
}
|
|
4928
6770
|
}
|
|
4929
6771
|
}
|
|
4930
6772
|
|
|
4931
|
-
utils.inherit(MouseWheel, EventDispatcher);
|
|
6773
|
+
utils$1.inherit(MouseWheel, EventDispatcher);
|
|
4932
6774
|
|
|
4933
6775
|
|
|
4934
6776
|
function MouseArea(element, pos) {
|
|
@@ -4982,7 +6824,7 @@
|
|
|
4982
6824
|
};
|
|
4983
6825
|
|
|
4984
6826
|
this.mouseData = function() {
|
|
4985
|
-
return utils.extend({}, _prevEvt);
|
|
6827
|
+
return utils$1.extend({}, _prevEvt);
|
|
4986
6828
|
};
|
|
4987
6829
|
|
|
4988
6830
|
function onAreaDown(e) {
|
|
@@ -5041,7 +6883,7 @@
|
|
|
5041
6883
|
dragX: evt.pageX - _downEvt.pageX,
|
|
5042
6884
|
dragY: evt.pageY - _downEvt.pageY
|
|
5043
6885
|
};
|
|
5044
|
-
_self.dispatchEvent('drag', utils.extend(obj, evt));
|
|
6886
|
+
_self.dispatchEvent('drag', utils$1.extend(obj, evt));
|
|
5045
6887
|
} else {
|
|
5046
6888
|
_self.dispatchEvent('hover', evt);
|
|
5047
6889
|
}
|
|
@@ -5073,7 +6915,7 @@
|
|
|
5073
6915
|
}
|
|
5074
6916
|
}
|
|
5075
6917
|
|
|
5076
|
-
utils.inherit(MouseArea, EventDispatcher);
|
|
6918
|
+
utils$1.inherit(MouseArea, EventDispatcher);
|
|
5077
6919
|
|
|
5078
6920
|
function initVariableClick(node, cb) {
|
|
5079
6921
|
var downEvent = null;
|
|
@@ -5220,7 +7062,7 @@
|
|
|
5220
7062
|
maxScale = 4,
|
|
5221
7063
|
minTime = 100,
|
|
5222
7064
|
maxTime = 800,
|
|
5223
|
-
time = utils.clamp(clickTime || 200, minTime, maxTime),
|
|
7065
|
+
time = utils$1.clamp(clickTime || 200, minTime, maxTime),
|
|
5224
7066
|
k = (time - minTime) / (maxTime - minTime),
|
|
5225
7067
|
scale = minScale + k * (maxScale - minScale);
|
|
5226
7068
|
return 1 + scale * zoomScaleMultiplier;
|
|
@@ -5447,7 +7289,7 @@
|
|
|
5447
7289
|
rows = 0;
|
|
5448
7290
|
// self.hide(); // clean up if panel is already open
|
|
5449
7291
|
el.empty(); // clean up if panel is already open
|
|
5450
|
-
utils.forEachProperty(rec, function(v, k) {
|
|
7292
|
+
utils$1.forEachProperty(rec, function(v, k) {
|
|
5451
7293
|
var type;
|
|
5452
7294
|
// missing GeoJSON fields are set to undefined on import; skip these
|
|
5453
7295
|
if (v !== undefined) {
|
|
@@ -5475,7 +7317,7 @@
|
|
|
5475
7317
|
// Some individual features can have undefined values for some or all of
|
|
5476
7318
|
// their data properties (properties are set to undefined when an input JSON file
|
|
5477
7319
|
// has inconsistent fields, or after force-merging layers with inconsistent fields).
|
|
5478
|
-
el.html(utils.format('<div class="note">This %s is missing attribute data.</div>',
|
|
7320
|
+
el.html(utils$1.format('<div class="note">This %s is missing attribute data.</div>',
|
|
5479
7321
|
table && table.getFields().length > 0 ? 'feature': 'layer'));
|
|
5480
7322
|
}
|
|
5481
7323
|
}
|
|
@@ -5486,7 +7328,7 @@
|
|
|
5486
7328
|
var str = formatInspectorValue(val, type);
|
|
5487
7329
|
var cell = El('tr')
|
|
5488
7330
|
.appendTo(table)
|
|
5489
|
-
.html(utils.format(rowHtml, key, utils.htmlEscape(str)))
|
|
7331
|
+
.html(utils$1.format(rowHtml, key, utils$1.htmlEscape(str)))
|
|
5490
7332
|
.findChild('.value');
|
|
5491
7333
|
setFieldClass(cell, val, type);
|
|
5492
7334
|
if (editable) {
|
|
@@ -5495,7 +7337,7 @@
|
|
|
5495
7337
|
}
|
|
5496
7338
|
|
|
5497
7339
|
function setFieldClass(el, val, type) {
|
|
5498
|
-
var isNum = type ? type == 'number' : utils.isNumber(val);
|
|
7340
|
+
var isNum = type ? type == 'number' : utils$1.isNumber(val);
|
|
5499
7341
|
var isNully = val === undefined || val === null || val !== val;
|
|
5500
7342
|
var isEmpty = val === '';
|
|
5501
7343
|
el.classed('num-field', isNum);
|
|
@@ -5533,7 +7375,7 @@
|
|
|
5533
7375
|
function formatInspectorValue(val, type) {
|
|
5534
7376
|
var str;
|
|
5535
7377
|
if (type == 'date') {
|
|
5536
|
-
str = utils.formatDateISO(val);
|
|
7378
|
+
str = utils$1.formatDateISO(val);
|
|
5537
7379
|
} else if (type == 'object') {
|
|
5538
7380
|
str = val ? JSON.stringify(val) : "";
|
|
5539
7381
|
} else {
|
|
@@ -5732,7 +7574,7 @@
|
|
|
5732
7574
|
// handle either numeric strings or numbers in fields
|
|
5733
7575
|
function applyDelta(rec, key, delta) {
|
|
5734
7576
|
var currVal = rec[key];
|
|
5735
|
-
var isString = utils.isString(currVal);
|
|
7577
|
+
var isString = utils$1.isString(currVal);
|
|
5736
7578
|
var newVal = (+currVal + delta) || 0;
|
|
5737
7579
|
rec[key] = isString ? String(newVal) : newVal;
|
|
5738
7580
|
}
|
|
@@ -5819,6 +7661,7 @@
|
|
|
5819
7661
|
if (e.mode != 'labels') {
|
|
5820
7662
|
stopDragging();
|
|
5821
7663
|
}
|
|
7664
|
+
gui.undo.clear(); // TODO: put this elsewhere?
|
|
5822
7665
|
});
|
|
5823
7666
|
|
|
5824
7667
|
// down event on svg
|
|
@@ -5830,12 +7673,16 @@
|
|
|
5830
7673
|
// 3: on other text -> stop dragging, select new text
|
|
5831
7674
|
|
|
5832
7675
|
hit.on('dragstart', function(e) {
|
|
5833
|
-
if (
|
|
5834
|
-
|
|
7676
|
+
if (e.id >= 0 === false) return;
|
|
7677
|
+
if (labelEditingEnabled() && onLabelDragStart(e)) {
|
|
7678
|
+
triggerGlobalEvent('label_dragstart', e);
|
|
7679
|
+
startDragging();
|
|
5835
7680
|
} else if (locationEditingEnabled()) {
|
|
5836
|
-
|
|
7681
|
+
triggerGlobalEvent('symbol_dragstart', e);
|
|
7682
|
+
startDragging();
|
|
5837
7683
|
} else if (vertexEditingEnabled()) {
|
|
5838
|
-
|
|
7684
|
+
triggerGlobalEvent('vertex_dragstart', e);
|
|
7685
|
+
startDragging();
|
|
5839
7686
|
}
|
|
5840
7687
|
});
|
|
5841
7688
|
|
|
@@ -5851,12 +7698,14 @@
|
|
|
5851
7698
|
|
|
5852
7699
|
hit.on('dragend', function(e) {
|
|
5853
7700
|
if (locationEditingEnabled()) {
|
|
5854
|
-
|
|
7701
|
+
triggerGlobalEvent('symbol_dragend', e);
|
|
5855
7702
|
stopDragging();
|
|
5856
7703
|
} else if (labelEditingEnabled()) {
|
|
7704
|
+
triggerGlobalEvent('label_dragend', e);
|
|
5857
7705
|
stopDragging();
|
|
5858
7706
|
} else if (vertexEditingEnabled()) {
|
|
5859
7707
|
onVertexDragEnd(e);
|
|
7708
|
+
triggerGlobalEvent('vertex_dragend', e);
|
|
5860
7709
|
stopDragging();
|
|
5861
7710
|
}
|
|
5862
7711
|
});
|
|
@@ -5867,18 +7716,6 @@
|
|
|
5867
7716
|
}
|
|
5868
7717
|
});
|
|
5869
7718
|
|
|
5870
|
-
function onLocationDragStart(e) {
|
|
5871
|
-
if (e.id >= 0) {
|
|
5872
|
-
dragging = true;
|
|
5873
|
-
triggerGlobalEvent('symbol_dragstart', e);
|
|
5874
|
-
}
|
|
5875
|
-
}
|
|
5876
|
-
|
|
5877
|
-
function onVertexDragStart(e) {
|
|
5878
|
-
if (e.id >= 0) {
|
|
5879
|
-
dragging = true;
|
|
5880
|
-
}
|
|
5881
|
-
}
|
|
5882
7719
|
|
|
5883
7720
|
function onLocationDrag(e) {
|
|
5884
7721
|
var lyr = hit.getHitTarget().layer;
|
|
@@ -5907,10 +7744,6 @@
|
|
|
5907
7744
|
self.dispatchEvent('location_change'); // signal map to redraw
|
|
5908
7745
|
}
|
|
5909
7746
|
|
|
5910
|
-
function onLocationDragEnd(e) {
|
|
5911
|
-
triggerGlobalEvent('symbol_dragend', e);
|
|
5912
|
-
}
|
|
5913
|
-
|
|
5914
7747
|
function onVertexDragEnd(e) {
|
|
5915
7748
|
// kludge to get dataset to recalculate internal bounding boxes
|
|
5916
7749
|
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
@@ -5953,11 +7786,11 @@
|
|
|
5953
7786
|
function onLabelDragStart(e) {
|
|
5954
7787
|
var textNode = getTextTarget3(e);
|
|
5955
7788
|
var table = hit.getTargetDataTable();
|
|
5956
|
-
if (!textNode || !table) return;
|
|
7789
|
+
if (!textNode || !table) return false;
|
|
5957
7790
|
activeId = e.id;
|
|
5958
7791
|
activeRecord = getLabelRecordById(activeId);
|
|
5959
|
-
dragging = true;
|
|
5960
7792
|
downEvt = e;
|
|
7793
|
+
return true;
|
|
5961
7794
|
}
|
|
5962
7795
|
|
|
5963
7796
|
function onLabelDrag(e) {
|
|
@@ -5965,7 +7798,7 @@
|
|
|
5965
7798
|
var textNode;
|
|
5966
7799
|
if (!dragging) return;
|
|
5967
7800
|
if (e.id != activeId) {
|
|
5968
|
-
error("Mismatched hit ids:", e.id, activeId);
|
|
7801
|
+
error$1("Mismatched hit ids:", e.id, activeId);
|
|
5969
7802
|
}
|
|
5970
7803
|
applyDelta(activeRecord, 'dx', e.dx / scale);
|
|
5971
7804
|
applyDelta(activeRecord, 'dy', e.dy / scale);
|
|
@@ -6082,6 +7915,10 @@
|
|
|
6082
7915
|
// }
|
|
6083
7916
|
}
|
|
6084
7917
|
|
|
7918
|
+
function startDragging() {
|
|
7919
|
+
dragging = true;
|
|
7920
|
+
}
|
|
7921
|
+
|
|
6085
7922
|
function stopDragging() {
|
|
6086
7923
|
dragging = false;
|
|
6087
7924
|
activeId = -1;
|
|
@@ -6098,16 +7935,6 @@
|
|
|
6098
7935
|
return dist <= 4 && elapsed < 300;
|
|
6099
7936
|
}
|
|
6100
7937
|
|
|
6101
|
-
|
|
6102
|
-
// function deselectText(el) {
|
|
6103
|
-
// el.removeAttribute('class');
|
|
6104
|
-
// }
|
|
6105
|
-
|
|
6106
|
-
// function selectText(el) {
|
|
6107
|
-
// el.setAttribute('class', 'selected');
|
|
6108
|
-
// }
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
7938
|
}
|
|
6112
7939
|
|
|
6113
7940
|
var darkStroke = "#334",
|
|
@@ -6213,7 +8040,7 @@
|
|
|
6213
8040
|
}
|
|
6214
8041
|
|
|
6215
8042
|
function getDefaultStyle(lyr, baseStyle) {
|
|
6216
|
-
var style = utils.extend({}, baseStyle);
|
|
8043
|
+
var style = utils$1.extend({}, baseStyle);
|
|
6217
8044
|
// reduce the dot size of large point layers
|
|
6218
8045
|
if (lyr.geometry_type == 'point' && style.dotSize > 0) {
|
|
6219
8046
|
style.dotSize *= getDotScale$1(lyr);
|
|
@@ -6279,7 +8106,7 @@
|
|
|
6279
8106
|
var topId = o.id; // pinned id (if pinned) or hover id
|
|
6280
8107
|
var topIdx = -1;
|
|
6281
8108
|
var styler = function(o, i) {
|
|
6282
|
-
utils.extend(o, i === topIdx ? topStyle: baseStyle);
|
|
8109
|
+
utils$1.extend(o, i === topIdx ? topStyle: baseStyle);
|
|
6283
8110
|
};
|
|
6284
8111
|
var baseStyle = getDefaultStyle(lyr, selectionStyles[geomType]);
|
|
6285
8112
|
var topStyle;
|
|
@@ -6392,7 +8219,7 @@
|
|
|
6392
8219
|
if (lyr.geometry_type == 'point') {
|
|
6393
8220
|
return fields.indexOf('r') > -1; // require 'r' field for point symbols
|
|
6394
8221
|
}
|
|
6395
|
-
return utils.difference(fields, ['opacity', 'class']).length > 0;
|
|
8222
|
+
return utils$1.difference(fields, ['opacity', 'class']).length > 0;
|
|
6396
8223
|
}
|
|
6397
8224
|
|
|
6398
8225
|
|
|
@@ -6548,7 +8375,7 @@
|
|
|
6548
8375
|
}
|
|
6549
8376
|
|
|
6550
8377
|
function maxAbs() {
|
|
6551
|
-
return Math.max.apply(null, utils.toArray(arguments).map(Math.abs));
|
|
8378
|
+
return Math.max.apply(null, utils$1.toArray(arguments).map(Math.abs));
|
|
6552
8379
|
}
|
|
6553
8380
|
|
|
6554
8381
|
function limitScale(scale) {
|
|
@@ -6602,7 +8429,7 @@
|
|
|
6602
8429
|
}
|
|
6603
8430
|
}
|
|
6604
8431
|
|
|
6605
|
-
utils.inherit(MapExtent, EventDispatcher);
|
|
8432
|
+
utils$1.inherit(MapExtent, EventDispatcher);
|
|
6606
8433
|
|
|
6607
8434
|
// TODO: consider moving this upstream
|
|
6608
8435
|
function getArcsForRendering(obj, ext) {
|
|
@@ -6763,7 +8590,7 @@
|
|
|
6763
8590
|
key = getStyleKey(style);
|
|
6764
8591
|
if (key in styleIndex === false) {
|
|
6765
8592
|
styleIndex[key] = {
|
|
6766
|
-
style: utils.defaults({}, style),
|
|
8593
|
+
style: utils$1.defaults({}, style),
|
|
6767
8594
|
shapes: []
|
|
6768
8595
|
};
|
|
6769
8596
|
}
|
|
@@ -7237,7 +9064,7 @@
|
|
|
7237
9064
|
var frame = ext.getFrame(); // frame should be set if we're rendering a furniture layer
|
|
7238
9065
|
var obj = internal.getEmptyLayerForSVG(lyr, {});
|
|
7239
9066
|
if (!frame) {
|
|
7240
|
-
stop('Missing map frame data');
|
|
9067
|
+
stop$1('Missing map frame data');
|
|
7241
9068
|
}
|
|
7242
9069
|
obj.properties.transform = getSvgFurnitureTransform(ext);
|
|
7243
9070
|
obj.properties.class = 'mapshaper-svg-furniture';
|
|
@@ -7265,7 +9092,7 @@
|
|
|
7265
9092
|
var html = '';
|
|
7266
9093
|
// generate a unique id so layer can be identified when symbols are repositioned
|
|
7267
9094
|
// use it as a class name to avoid id collisions
|
|
7268
|
-
var id = utils.getUniqueName();
|
|
9095
|
+
var id = utils$1.getUniqueName();
|
|
7269
9096
|
var classNames = [id, 'mapshaper-svg-layer', 'mapshaper-' + type + '-layer'];
|
|
7270
9097
|
g.setAttribute('class', classNames.join(' '));
|
|
7271
9098
|
target.svg_id = id;
|
|
@@ -7716,7 +9543,7 @@
|
|
|
7716
9543
|
}
|
|
7717
9544
|
|
|
7718
9545
|
if (obj.tabular) {
|
|
7719
|
-
utils.extend(obj, getDisplayLayerForTable(layer.data));
|
|
9546
|
+
utils$1.extend(obj, getDisplayLayerForTable(layer.data));
|
|
7720
9547
|
}
|
|
7721
9548
|
|
|
7722
9549
|
// dynamic reprojection (arcs were already reprojected above)
|
|
@@ -7774,7 +9601,7 @@
|
|
|
7774
9601
|
return ids;
|
|
7775
9602
|
}
|
|
7776
9603
|
|
|
7777
|
-
utils.inherit(MshpMap, EventDispatcher);
|
|
9604
|
+
utils$1.inherit(MshpMap, EventDispatcher);
|
|
7778
9605
|
|
|
7779
9606
|
function MshpMap(gui) {
|
|
7780
9607
|
var opts = gui.options,
|
|
@@ -7812,6 +9639,10 @@
|
|
|
7812
9639
|
_mouse.disable();
|
|
7813
9640
|
});
|
|
7814
9641
|
|
|
9642
|
+
gui.on('undo_redo', function() {
|
|
9643
|
+
drawLayers();
|
|
9644
|
+
});
|
|
9645
|
+
|
|
7815
9646
|
model.on('update', onUpdate);
|
|
7816
9647
|
|
|
7817
9648
|
// Update display of segment intersections
|
|
@@ -7864,7 +9695,7 @@
|
|
|
7864
9695
|
this.setDisplayCRS = function(crs) {
|
|
7865
9696
|
// TODO: update bounds of frame layer, if there is a frame layer
|
|
7866
9697
|
var oldCRS = this.getDisplayCRS();
|
|
7867
|
-
var newCRS = utils.isString(crs) ? internal.getCRS(crs) : crs;
|
|
9698
|
+
var newCRS = utils$1.isString(crs) ? internal.getCRS(crs) : crs;
|
|
7868
9699
|
// TODO: handle case that old and new CRS are the same
|
|
7869
9700
|
_dynamicCRS = newCRS;
|
|
7870
9701
|
if (!_activeLyr) return; // stop here if no layers have been selected
|
|
@@ -7996,7 +9827,7 @@
|
|
|
7996
9827
|
function updateOverlayLayer(e) {
|
|
7997
9828
|
var style = getOverlayStyle(_activeLyr.layer, e);
|
|
7998
9829
|
if (style) {
|
|
7999
|
-
_overlayLyr = utils.defaults({
|
|
9830
|
+
_overlayLyr = utils$1.defaults({
|
|
8000
9831
|
layer: filterLayerByIds(_activeLyr.layer, style.ids),
|
|
8001
9832
|
style: style
|
|
8002
9833
|
}, _activeLyr);
|
|
@@ -8161,7 +9992,7 @@
|
|
|
8161
9992
|
// kludge to hide ghosted layers when reference layers are present
|
|
8162
9993
|
// TODO: consider never showing ghosted layers (which appear after
|
|
8163
9994
|
// commands like dissolve and filter).
|
|
8164
|
-
mapLayer.style = utils.defaults({
|
|
9995
|
+
mapLayer.style = utils$1.defaults({
|
|
8165
9996
|
strokeColors: [null, mapLayer.style.strokeColors[1]]
|
|
8166
9997
|
}, mapLayer.style);
|
|
8167
9998
|
}
|
|
@@ -8217,7 +10048,7 @@
|
|
|
8217
10048
|
|
|
8218
10049
|
function GuiInstance(container, opts) {
|
|
8219
10050
|
var gui = new ModeSwitcher();
|
|
8220
|
-
opts = utils.extend({
|
|
10051
|
+
opts = utils$1.extend({
|
|
8221
10052
|
// defaults
|
|
8222
10053
|
homeControl: true,
|
|
8223
10054
|
zoomControl: true,
|
|
@@ -8235,6 +10066,7 @@
|
|
|
8235
10066
|
gui.map = new MshpMap(gui);
|
|
8236
10067
|
gui.interaction = new InteractionMode(gui);
|
|
8237
10068
|
gui.session = new SessionHistory(gui);
|
|
10069
|
+
gui.undo = new Undo(gui);
|
|
8238
10070
|
|
|
8239
10071
|
gui.showProgressMessage = function(msg) {
|
|
8240
10072
|
if (!gui.progressMessage) {
|