mapshaper 0.5.91 → 0.5.94
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 +1316 -0
- package/bin/mapshaper-gui +16 -9
- package/mapshaper.js +203 -65
- package/package.json +2 -2
- package/www/index.html +1 -1
- package/www/manifest.js +7 -1
- package/www/mapshaper-gui.js +2042 -442
- package/www/mapshaper.js +203 -65
- package/www/nacis/Makefile +0 -22
- package/www/nacis/Makefile.txt +0 -22
- package/www/nacis/images/close.png +0 -0
- package/www/nacis/images/eye.png +0 -0
- package/www/nacis/images/eye2.png +0 -0
- package/www/nacis/index.html +0 -262
- package/www/nacis/manifest.js +0 -27
- package/www/nacis/map.svg +0 -12308
package/www/mapshaper-gui.js
CHANGED
|
@@ -1,16 +1,114 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
+
var utils = /*#__PURE__*/Object.freeze({
|
|
4
|
+
__proto__: null,
|
|
5
|
+
get default () { return utils; },
|
|
6
|
+
get getUniqueName () { return getUniqueName; },
|
|
7
|
+
get isFunction () { return isFunction; },
|
|
8
|
+
get isObject () { return isObject; },
|
|
9
|
+
get clamp () { return clamp; },
|
|
10
|
+
get isArray () { return isArray; },
|
|
11
|
+
get isNumber () { return isNumber; },
|
|
12
|
+
get isValidNumber () { return isValidNumber; },
|
|
13
|
+
get isFiniteNumber () { return isFiniteNumber; },
|
|
14
|
+
get isNonNegNumber () { return isNonNegNumber; },
|
|
15
|
+
get isInteger () { return isInteger; },
|
|
16
|
+
get isEven () { return isEven; },
|
|
17
|
+
get isOdd () { return isOdd; },
|
|
18
|
+
get isString () { return isString; },
|
|
19
|
+
get isDate () { return isDate; },
|
|
20
|
+
get isBoolean () { return isBoolean; },
|
|
21
|
+
get formatDateISO () { return formatDateISO; },
|
|
22
|
+
get toArray () { return toArray; },
|
|
23
|
+
get isArrayLike () { return isArrayLike; },
|
|
24
|
+
get addslashes () { return addslashes; },
|
|
25
|
+
get regexEscape () { return regexEscape; },
|
|
26
|
+
get htmlEscape () { return htmlEscape; },
|
|
27
|
+
get defaults () { return defaults; },
|
|
28
|
+
get extend () { return extend; },
|
|
29
|
+
get inherit () { return inherit; },
|
|
30
|
+
get reduceAsync () { return reduceAsync; },
|
|
31
|
+
get merge () { return merge; },
|
|
32
|
+
get difference () { return difference; },
|
|
33
|
+
get intersection () { return intersection; },
|
|
34
|
+
get indexOf () { return indexOf; },
|
|
35
|
+
get contains () { return contains; },
|
|
36
|
+
get some () { return some; },
|
|
37
|
+
get every () { return every; },
|
|
38
|
+
get find () { return find; },
|
|
39
|
+
get range () { return range; },
|
|
40
|
+
get repeat () { return repeat; },
|
|
41
|
+
get sum () { return sum; },
|
|
42
|
+
get getArrayBounds () { return getArrayBounds; },
|
|
43
|
+
get uniq () { return uniq; },
|
|
44
|
+
get pluck () { return pluck; },
|
|
45
|
+
get countValues () { return countValues; },
|
|
46
|
+
get indexOn () { return indexOn; },
|
|
47
|
+
get groupBy () { return groupBy; },
|
|
48
|
+
get arrayToIndex () { return arrayToIndex; },
|
|
49
|
+
get forEach () { return forEach; },
|
|
50
|
+
get forEachProperty () { return forEachProperty; },
|
|
51
|
+
get initializeArray () { return initializeArray; },
|
|
52
|
+
get replaceArray () { return replaceArray; },
|
|
53
|
+
get repeatString () { return repeatString; },
|
|
54
|
+
get splitLines () { return splitLines; },
|
|
55
|
+
get pluralSuffix () { return pluralSuffix; },
|
|
56
|
+
get endsWith () { return endsWith; },
|
|
57
|
+
get lpad () { return lpad; },
|
|
58
|
+
get rpad () { return rpad; },
|
|
59
|
+
get trim () { return trim; },
|
|
60
|
+
get ltrim () { return ltrim; },
|
|
61
|
+
get rtrim () { return rtrim; },
|
|
62
|
+
get addThousandsSep () { return addThousandsSep; },
|
|
63
|
+
get numToStr () { return numToStr; },
|
|
64
|
+
get formatNumber () { return formatNumber; },
|
|
65
|
+
get formatIntlNumber () { return formatIntlNumber; },
|
|
66
|
+
get formatNumberForDisplay () { return formatNumberForDisplay; },
|
|
67
|
+
get shuffle () { return shuffle; },
|
|
68
|
+
get sortOn () { return sortOn; },
|
|
69
|
+
get genericSort () { return genericSort; },
|
|
70
|
+
get getSortedIds () { return getSortedIds; },
|
|
71
|
+
get sortArrayIndex () { return sortArrayIndex; },
|
|
72
|
+
get reorderArray () { return reorderArray; },
|
|
73
|
+
get getKeyComparator () { return getKeyComparator; },
|
|
74
|
+
get getGenericComparator () { return getGenericComparator; },
|
|
75
|
+
get quicksort () { return quicksort; },
|
|
76
|
+
get quicksortPartition () { return quicksortPartition; },
|
|
77
|
+
get findRankByValue () { return findRankByValue; },
|
|
78
|
+
get findValueByPct () { return findValueByPct; },
|
|
79
|
+
get findValueByRank () { return findValueByRank; },
|
|
80
|
+
get findMedian () { return findMedian; },
|
|
81
|
+
get mean () { return mean; },
|
|
82
|
+
get format () { return format; },
|
|
83
|
+
get formatter () { return formatter; },
|
|
84
|
+
get wildcardToRegExp () { return wildcardToRegExp; },
|
|
85
|
+
get createBuffer () { return createBuffer; },
|
|
86
|
+
get expandoBuffer () { return expandoBuffer; },
|
|
87
|
+
get copyElements () { return copyElements; },
|
|
88
|
+
get extendBuffer () { return extendBuffer; },
|
|
89
|
+
get mergeNames () { return mergeNames; },
|
|
90
|
+
get findStringPrefix () { return findStringPrefix; },
|
|
91
|
+
get parsePercent () { return parsePercent; },
|
|
92
|
+
get formatVersionedName () { return formatVersionedName; },
|
|
93
|
+
get uniqifyNames () { return uniqifyNames; },
|
|
94
|
+
get parseString () { return parseString; },
|
|
95
|
+
get parseNumber () { return parseNumber; },
|
|
96
|
+
get parseIntlNumber () { return parseIntlNumber; },
|
|
97
|
+
get cleanNumericString () { return cleanNumericString; },
|
|
98
|
+
get trimQuotes () { return trimQuotes; }
|
|
99
|
+
});
|
|
100
|
+
|
|
3
101
|
var api = window.mapshaper; // assuming mapshaper is in global scope
|
|
4
102
|
var mapshaper = api,
|
|
5
|
-
utils = api.utils,
|
|
103
|
+
utils$1 = api.utils,
|
|
6
104
|
cli = api.cli,
|
|
7
105
|
geom = api.geom,
|
|
8
106
|
internal = api.internal,
|
|
9
107
|
Bounds = internal.Bounds,
|
|
10
|
-
UserError = internal.UserError,
|
|
11
|
-
message = internal.message, // stop, error and message are overridden in gui-proxy.js
|
|
12
|
-
stop = internal.stop,
|
|
13
|
-
error = internal.error;
|
|
108
|
+
UserError$1 = internal.UserError,
|
|
109
|
+
message$1 = internal.message, // stop, error and message are overridden in gui-proxy.js
|
|
110
|
+
stop$1 = internal.stop,
|
|
111
|
+
error$1 = internal.error;
|
|
14
112
|
|
|
15
113
|
api.enableLogging();
|
|
16
114
|
|
|
@@ -46,7 +144,7 @@
|
|
|
46
144
|
|
|
47
145
|
html = '<table>';
|
|
48
146
|
if (catalog.title) {
|
|
49
|
-
html += utils.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
|
|
147
|
+
html += utils$1.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
|
|
50
148
|
}
|
|
51
149
|
while (row < rows) {
|
|
52
150
|
html += renderRow(items.slice(row * cols, row * cols + cols));
|
|
@@ -111,7 +209,7 @@
|
|
|
111
209
|
|
|
112
210
|
function renderCell(item, i) {
|
|
113
211
|
var template = '<td data-id="%d"><h4 class="title">%s</h4><div class="subtitle">%s</div></td>';
|
|
114
|
-
return utils.format(template, i, item.title, item.subtitle || '');
|
|
212
|
+
return utils$1.format(template, i, item.title, item.subtitle || '');
|
|
115
213
|
}
|
|
116
214
|
|
|
117
215
|
}
|
|
@@ -228,7 +326,7 @@
|
|
|
228
326
|
}
|
|
229
327
|
parsed = internal.parseCommands(str);
|
|
230
328
|
if (!parsed.length || parsed[0].name != cmd) {
|
|
231
|
-
stop("Unable to parse command line options");
|
|
329
|
+
stop$1("Unable to parse command line options");
|
|
232
330
|
}
|
|
233
331
|
return parsed[0].options;
|
|
234
332
|
};
|
|
@@ -321,7 +419,7 @@
|
|
|
321
419
|
evt = new EventData(this.type);
|
|
322
420
|
evt.target = this.target;
|
|
323
421
|
} else if (evt.target != this.target || evt.type != this.type) {
|
|
324
|
-
error("[Handler] event target/type have changed.");
|
|
422
|
+
error$1("[Handler] event target/type have changed.");
|
|
325
423
|
}
|
|
326
424
|
this.callback.call(this.listener, evt);
|
|
327
425
|
};
|
|
@@ -330,7 +428,7 @@
|
|
|
330
428
|
this.type = type;
|
|
331
429
|
this.target = target;
|
|
332
430
|
if (data) {
|
|
333
|
-
utils.defaults(this, data);
|
|
431
|
+
utils$1.defaults(this, data);
|
|
334
432
|
this.data = data;
|
|
335
433
|
}
|
|
336
434
|
}
|
|
@@ -560,12 +658,12 @@
|
|
|
560
658
|
try {
|
|
561
659
|
els = root.querySelectorAll(selector);
|
|
562
660
|
} catch (e) {
|
|
563
|
-
error("Invalid selector:", selector);
|
|
661
|
+
error$1("Invalid selector:", selector);
|
|
564
662
|
}
|
|
565
663
|
} else {
|
|
566
|
-
error("This browser doesn't support CSS query selectors");
|
|
664
|
+
error$1("This browser doesn't support CSS query selectors");
|
|
567
665
|
}
|
|
568
|
-
return utils.toArray(els);
|
|
666
|
+
return utils$1.toArray(els);
|
|
569
667
|
};
|
|
570
668
|
|
|
571
669
|
// Converts dash-separated names (e.g. background-color) to camelCase (e.g. backgroundColor)
|
|
@@ -602,7 +700,7 @@
|
|
|
602
700
|
};
|
|
603
701
|
|
|
604
702
|
function El(ref) {
|
|
605
|
-
if (!ref) error("Element() needs a reference");
|
|
703
|
+
if (!ref) error$1("Element() needs a reference");
|
|
606
704
|
if (ref instanceof El) {
|
|
607
705
|
return ref;
|
|
608
706
|
}
|
|
@@ -611,7 +709,7 @@
|
|
|
611
709
|
}
|
|
612
710
|
|
|
613
711
|
var node;
|
|
614
|
-
if (utils.isString(ref)) {
|
|
712
|
+
if (utils$1.isString(ref)) {
|
|
615
713
|
if (ref[0] == '<') {
|
|
616
714
|
var parent = El('div').html(ref).node();
|
|
617
715
|
node = parent.childNodes.length == 1 ? parent.childNodes[0] : parent;
|
|
@@ -623,13 +721,13 @@
|
|
|
623
721
|
} else if (ref.tagName) {
|
|
624
722
|
node = ref;
|
|
625
723
|
}
|
|
626
|
-
if (!node) error("Unmatched element selector:", ref);
|
|
724
|
+
if (!node) error$1("Unmatched element selector:", ref);
|
|
627
725
|
this.el = node;
|
|
628
726
|
}
|
|
629
727
|
|
|
630
|
-
utils.inherit(El, EventDispatcher);
|
|
728
|
+
utils$1.inherit(El, EventDispatcher);
|
|
631
729
|
|
|
632
|
-
utils.extend(El.prototype, {
|
|
730
|
+
utils$1.extend(El.prototype, {
|
|
633
731
|
|
|
634
732
|
clone: function() {
|
|
635
733
|
var el = this.el.cloneNode(true);
|
|
@@ -638,7 +736,7 @@
|
|
|
638
736
|
// can ...
|
|
639
737
|
el = El('div').addClass(el.className).html(el.innerHTML).node();
|
|
640
738
|
}
|
|
641
|
-
el.id = utils.getUniqueName();
|
|
739
|
+
el.id = utils$1.getUniqueName();
|
|
642
740
|
this.el = el;
|
|
643
741
|
return this;
|
|
644
742
|
},
|
|
@@ -668,11 +766,11 @@
|
|
|
668
766
|
if (val != null) {
|
|
669
767
|
El.setStyle(this.el, css, val);
|
|
670
768
|
}
|
|
671
|
-
else if (utils.isString(css)) {
|
|
769
|
+
else if (utils$1.isString(css)) {
|
|
672
770
|
addCSS(this.el, css);
|
|
673
771
|
}
|
|
674
|
-
else if (utils.isObject(css)) {
|
|
675
|
-
utils.forEachProperty(css, function(val, key) {
|
|
772
|
+
else if (utils$1.isObject(css)) {
|
|
773
|
+
utils$1.forEachProperty(css, function(val, key) {
|
|
676
774
|
El.setStyle(this.el, key, val);
|
|
677
775
|
}, this);
|
|
678
776
|
}
|
|
@@ -680,7 +778,7 @@
|
|
|
680
778
|
},
|
|
681
779
|
|
|
682
780
|
attr: function(obj, value) {
|
|
683
|
-
if (utils.isString(obj)) {
|
|
781
|
+
if (utils$1.isString(obj)) {
|
|
684
782
|
if (arguments.length == 1) {
|
|
685
783
|
return this.el.getAttribute(obj);
|
|
686
784
|
}
|
|
@@ -764,7 +862,7 @@
|
|
|
764
862
|
},
|
|
765
863
|
|
|
766
864
|
text: function(str) {
|
|
767
|
-
this.html(utils.htmlEscape(str));
|
|
865
|
+
this.html(utils$1.htmlEscape(str));
|
|
768
866
|
return this;
|
|
769
867
|
},
|
|
770
868
|
|
|
@@ -854,7 +952,7 @@
|
|
|
854
952
|
El.prototype.__on = El.prototype.on;
|
|
855
953
|
El.prototype.on = function(type, func, ctx) {
|
|
856
954
|
if (ctx) {
|
|
857
|
-
error("[El#on()] Third argument no longer supported.");
|
|
955
|
+
error$1("[El#on()] Third argument no longer supported.");
|
|
858
956
|
}
|
|
859
957
|
if (this.constructor == El) {
|
|
860
958
|
this.el.addEventListener(type, func);
|
|
@@ -910,7 +1008,7 @@
|
|
|
910
1008
|
}
|
|
911
1009
|
|
|
912
1010
|
this.value = function(str) {
|
|
913
|
-
if (utils.isString(str)) {
|
|
1011
|
+
if (utils$1.isString(str)) {
|
|
914
1012
|
el.node().textContent = str;
|
|
915
1013
|
} else {
|
|
916
1014
|
return el.node().textContent;
|
|
@@ -918,7 +1016,7 @@
|
|
|
918
1016
|
};
|
|
919
1017
|
}
|
|
920
1018
|
|
|
921
|
-
utils.inherit(ClickText2, EventDispatcher);
|
|
1019
|
+
utils$1.inherit(ClickText2, EventDispatcher);
|
|
922
1020
|
|
|
923
1021
|
// @ref reference to a text input element
|
|
924
1022
|
function ClickText(ref) {
|
|
@@ -989,9 +1087,9 @@
|
|
|
989
1087
|
// return _parser ? _parser(valStr) : parseFloat(valStr);
|
|
990
1088
|
return _value;
|
|
991
1089
|
}
|
|
992
|
-
var val = utils.clamp(arg, _min, _max);
|
|
1090
|
+
var val = utils$1.clamp(arg, _min, _max);
|
|
993
1091
|
if (!_validator(val)) {
|
|
994
|
-
error("ClickText#value() invalid value:", arg);
|
|
1092
|
+
error$1("ClickText#value() invalid value:", arg);
|
|
995
1093
|
} else {
|
|
996
1094
|
_value = val;
|
|
997
1095
|
}
|
|
@@ -1000,14 +1098,14 @@
|
|
|
1000
1098
|
};
|
|
1001
1099
|
}
|
|
1002
1100
|
|
|
1003
|
-
utils.inherit(ClickText, EventDispatcher);
|
|
1101
|
+
utils$1.inherit(ClickText, EventDispatcher);
|
|
1004
1102
|
|
|
1005
1103
|
|
|
1006
1104
|
function Checkbox(ref) {
|
|
1007
1105
|
var _el = El(ref);
|
|
1008
1106
|
}
|
|
1009
1107
|
|
|
1010
|
-
utils.inherit(Checkbox, EventDispatcher);
|
|
1108
|
+
utils$1.inherit(Checkbox, EventDispatcher);
|
|
1011
1109
|
|
|
1012
1110
|
function SimpleButton(ref) {
|
|
1013
1111
|
var _el = El(ref),
|
|
@@ -1036,7 +1134,7 @@
|
|
|
1036
1134
|
}
|
|
1037
1135
|
}
|
|
1038
1136
|
|
|
1039
|
-
utils.inherit(SimpleButton, EventDispatcher);
|
|
1137
|
+
utils$1.inherit(SimpleButton, EventDispatcher);
|
|
1040
1138
|
|
|
1041
1139
|
// @cb function(<FileList>)
|
|
1042
1140
|
function DropControl(gui, el, cb) {
|
|
@@ -1232,6 +1330,7 @@
|
|
|
1232
1330
|
}
|
|
1233
1331
|
}
|
|
1234
1332
|
model.updated({select: true});
|
|
1333
|
+
|
|
1235
1334
|
}
|
|
1236
1335
|
|
|
1237
1336
|
function clearQueuedFiles() {
|
|
@@ -1315,7 +1414,7 @@
|
|
|
1315
1414
|
}
|
|
1316
1415
|
|
|
1317
1416
|
function filesMayContainPaths(files) {
|
|
1318
|
-
return utils.some(files, function(f) {
|
|
1417
|
+
return utils$1.some(files, function(f) {
|
|
1319
1418
|
var type = internal.guessInputFileType(f.name);
|
|
1320
1419
|
return type == 'shp' || type == 'json' || internal.isZipFile(f.name);
|
|
1321
1420
|
});
|
|
@@ -1371,7 +1470,7 @@
|
|
|
1371
1470
|
}
|
|
1372
1471
|
|
|
1373
1472
|
function handleImportError(e, fileName) {
|
|
1374
|
-
var msg = utils.isString(e) ? e : e.message;
|
|
1473
|
+
var msg = utils$1.isString(e) ? e : e.message;
|
|
1375
1474
|
if (fileName) {
|
|
1376
1475
|
msg = "Error importing <i>" + fileName + "</i><br>" + msg;
|
|
1377
1476
|
}
|
|
@@ -1401,7 +1500,7 @@
|
|
|
1401
1500
|
|
|
1402
1501
|
function downloadFiles(paths) {
|
|
1403
1502
|
var items = prepFilesForDownload(paths);
|
|
1404
|
-
utils.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1503
|
+
utils$1.reduceAsync(items, [], downloadNextFile, function(err, files) {
|
|
1405
1504
|
if (err) {
|
|
1406
1505
|
gui.alert(err);
|
|
1407
1506
|
} else if (!files.length) {
|
|
@@ -1567,7 +1666,7 @@
|
|
|
1567
1666
|
var defaults = {
|
|
1568
1667
|
space: 7
|
|
1569
1668
|
};
|
|
1570
|
-
opts = utils.extend(defaults, opts);
|
|
1669
|
+
opts = utils$1.extend(defaults, opts);
|
|
1571
1670
|
|
|
1572
1671
|
var _pct = 0;
|
|
1573
1672
|
var _track,
|
|
@@ -1620,7 +1719,7 @@
|
|
|
1620
1719
|
};
|
|
1621
1720
|
|
|
1622
1721
|
function setHandlePos(x, fire) {
|
|
1623
|
-
x = utils.clamp(x, 0, size());
|
|
1722
|
+
x = utils$1.clamp(x, 0, size());
|
|
1624
1723
|
var pct = x / size();
|
|
1625
1724
|
if (pct != _pct) {
|
|
1626
1725
|
_pct = pct;
|
|
@@ -1635,7 +1734,7 @@
|
|
|
1635
1734
|
}
|
|
1636
1735
|
}
|
|
1637
1736
|
|
|
1638
|
-
utils.inherit(Slider, EventDispatcher);
|
|
1737
|
+
utils$1.inherit(Slider, EventDispatcher);
|
|
1639
1738
|
|
|
1640
1739
|
/*
|
|
1641
1740
|
How changes in the simplify control should affect other components
|
|
@@ -1703,7 +1802,7 @@
|
|
|
1703
1802
|
slider.on('change', function(e) {
|
|
1704
1803
|
var pct = fromSliderPct(e.pct);
|
|
1705
1804
|
text.value(pct);
|
|
1706
|
-
pct = utils.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1805
|
+
pct = utils$1.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
|
|
1707
1806
|
onChange(pct);
|
|
1708
1807
|
});
|
|
1709
1808
|
slider.on('start', function(e) {
|
|
@@ -1724,7 +1823,7 @@
|
|
|
1724
1823
|
else if (pct < 0.01) decimals = 3;
|
|
1725
1824
|
else if (pct < 1) decimals = 2;
|
|
1726
1825
|
else if (pct < 100) decimals = 1;
|
|
1727
|
-
return utils.formatNumberForDisplay(pct, decimals) + "%";
|
|
1826
|
+
return utils$1.formatNumberForDisplay(pct, decimals) + "%";
|
|
1728
1827
|
});
|
|
1729
1828
|
|
|
1730
1829
|
text.parser(function(s) {
|
|
@@ -1976,7 +2075,7 @@
|
|
|
1976
2075
|
|
|
1977
2076
|
// Replace error function in mapshaper lib
|
|
1978
2077
|
var error = function() {
|
|
1979
|
-
stop.apply(null, utils.toArray(arguments));
|
|
2078
|
+
stop.apply(null, utils$1.toArray(arguments));
|
|
1980
2079
|
};
|
|
1981
2080
|
|
|
1982
2081
|
var message = function() {
|
|
@@ -1990,11 +2089,11 @@
|
|
|
1990
2089
|
// replace CLI version of writeFiles()
|
|
1991
2090
|
internal.replaceWriteFiles(function(files, opts, done) {
|
|
1992
2091
|
var filename;
|
|
1993
|
-
if (!utils.isArray(files) || files.length === 0) {
|
|
2092
|
+
if (!utils$1.isArray(files) || files.length === 0) {
|
|
1994
2093
|
done("Nothing to export");
|
|
1995
2094
|
} else if (GUI.canSaveToServer() && !opts.save_to_download_folder) {
|
|
1996
|
-
var paths = internal.getOutputPaths(utils.pluck(files, 'filename'), opts);
|
|
1997
|
-
var data = utils.pluck(files, 'content');
|
|
2095
|
+
var paths = internal.getOutputPaths(utils$1.pluck(files, 'filename'), opts);
|
|
2096
|
+
var data = utils$1.pluck(files, 'content');
|
|
1998
2097
|
saveFilesToServer(paths, data, function(err) {
|
|
1999
2098
|
var msg;
|
|
2000
2099
|
if (err) {
|
|
@@ -2013,7 +2112,7 @@
|
|
|
2013
2112
|
} else if (files.length == 1) {
|
|
2014
2113
|
saveBlobToDownloadFolder(files[0].filename, new Blob([files[0].content]), done);
|
|
2015
2114
|
} else {
|
|
2016
|
-
filename = internal.getCommonFileBase(utils.pluck(files, 'filename')) || "output";
|
|
2115
|
+
filename = internal.getCommonFileBase(utils$1.pluck(files, 'filename')) || "output";
|
|
2017
2116
|
saveZipFile(filename + ".zip", files, done);
|
|
2018
2117
|
}
|
|
2019
2118
|
});
|
|
@@ -2035,10 +2134,10 @@
|
|
|
2035
2134
|
// try to match import filename of this dataset
|
|
2036
2135
|
if (d.info.input_files[0] == src) return d;
|
|
2037
2136
|
// try to match name of a layer in this dataset
|
|
2038
|
-
lyr = utils.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2137
|
+
lyr = utils$1.find(d.layers, function(lyr) {return lyr.name == src;});
|
|
2039
2138
|
return lyr ? internal.isolateLayer(lyr, d) : null;
|
|
2040
2139
|
}, null);
|
|
2041
|
-
if (!retn) stop("Missing data layer [" + src + "]");
|
|
2140
|
+
if (!retn) stop$1("Missing data layer [" + src + "]");
|
|
2042
2141
|
return retn;
|
|
2043
2142
|
}
|
|
2044
2143
|
|
|
@@ -2047,7 +2146,7 @@
|
|
|
2047
2146
|
// Return a copy with layers duplicated, so changes won't affect original layers
|
|
2048
2147
|
// This makes an (unsafe) assumption that the dataset arcs won't be changed...
|
|
2049
2148
|
// need to rethink this.
|
|
2050
|
-
return utils.defaults({
|
|
2149
|
+
return utils$1.defaults({
|
|
2051
2150
|
layers: dataset.layers.map(internal.copyLayer)
|
|
2052
2151
|
}, dataset);
|
|
2053
2152
|
});
|
|
@@ -2119,7 +2218,7 @@
|
|
|
2119
2218
|
}
|
|
2120
2219
|
|
|
2121
2220
|
function projectPointsForDisplay(lyr, src, dest) {
|
|
2122
|
-
var copy = utils.extend({}, lyr);
|
|
2221
|
+
var copy = utils$1.extend({}, lyr);
|
|
2123
2222
|
var proj = internal.getProjTransform2(src, dest);
|
|
2124
2223
|
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
2125
2224
|
internal.projectPointLayer(copy, proj);
|
|
@@ -2187,6 +2286,13 @@
|
|
|
2187
2286
|
// expose this function, so other components can run commands (e.g. box tool)
|
|
2188
2287
|
this.runMapshaperCommands = runMapshaperCommands;
|
|
2189
2288
|
|
|
2289
|
+
this.runInitialCommands = function(str) {
|
|
2290
|
+
str = str.trim();
|
|
2291
|
+
if (!str) return;
|
|
2292
|
+
turnOn();
|
|
2293
|
+
submit(str);
|
|
2294
|
+
};
|
|
2295
|
+
|
|
2190
2296
|
consoleMessage(PROMPT);
|
|
2191
2297
|
gui.keyboard.on('keydown', onKeyDown);
|
|
2192
2298
|
window.addEventListener('beforeunload', saveHistory); // save history if console is open on refresh
|
|
@@ -2517,7 +2623,7 @@
|
|
|
2517
2623
|
} else if (cmd == 'history') {
|
|
2518
2624
|
toLog(gui.session.toCommandLineString());
|
|
2519
2625
|
} else if (cmd == 'layers') {
|
|
2520
|
-
message("Available layers:",
|
|
2626
|
+
message$1("Available layers:",
|
|
2521
2627
|
internal.getFormattedLayerList(model));
|
|
2522
2628
|
} else if (cmd == 'close' || cmd == 'exit' || cmd == 'quit') {
|
|
2523
2629
|
turnOff();
|
|
@@ -2606,7 +2712,7 @@
|
|
|
2606
2712
|
}
|
|
2607
2713
|
|
|
2608
2714
|
function onError(err) {
|
|
2609
|
-
if (utils.isString(err)) {
|
|
2715
|
+
if (utils$1.isString(err)) {
|
|
2610
2716
|
consoleStop(err);
|
|
2611
2717
|
} else if (err.name == 'UserError') {
|
|
2612
2718
|
// stop() has already been called, don't need to log
|
|
@@ -2621,7 +2727,7 @@
|
|
|
2621
2727
|
function consoleStop() {
|
|
2622
2728
|
var msg = GUI.formatMessageArgs(arguments);
|
|
2623
2729
|
consoleWarning(msg);
|
|
2624
|
-
throw new UserError(msg);
|
|
2730
|
+
throw new UserError$1(msg);
|
|
2625
2731
|
}
|
|
2626
2732
|
|
|
2627
2733
|
function consoleWarning() {
|
|
@@ -2785,7 +2891,7 @@
|
|
|
2785
2891
|
// console.log("first intersection:", internal.getIntersectionDebugData(XX[0], arcs));
|
|
2786
2892
|
pointLyr = {geometry_type: 'point', shapes: [internal.getIntersectionPoints(XX)]};
|
|
2787
2893
|
map.setIntersectionLayer(pointLyr, {layers:[pointLyr]});
|
|
2788
|
-
readout.html(utils.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils.pluralSuffix(n)));
|
|
2894
|
+
readout.html(utils$1.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils$1.pluralSuffix(n)));
|
|
2789
2895
|
readout.findChild('.close-btn').on('click', dismiss);
|
|
2790
2896
|
} else {
|
|
2791
2897
|
map.setIntersectionLayer(null);
|
|
@@ -2794,7 +2900,7 @@
|
|
|
2794
2900
|
}
|
|
2795
2901
|
}
|
|
2796
2902
|
|
|
2797
|
-
utils.inherit(RepairControl, EventDispatcher);
|
|
2903
|
+
utils$1.inherit(RepairControl, EventDispatcher);
|
|
2798
2904
|
|
|
2799
2905
|
function filterLayerByIds(lyr, ids) {
|
|
2800
2906
|
var shapes;
|
|
@@ -2802,7 +2908,7 @@
|
|
|
2802
2908
|
shapes = ids.map(function(id) {
|
|
2803
2909
|
return lyr.shapes[id];
|
|
2804
2910
|
});
|
|
2805
|
-
return utils.defaults({shapes: shapes, data: null}, lyr);
|
|
2911
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
2806
2912
|
}
|
|
2807
2913
|
return lyr;
|
|
2808
2914
|
}
|
|
@@ -2855,7 +2961,7 @@
|
|
|
2855
2961
|
});
|
|
2856
2962
|
|
|
2857
2963
|
internal.writeFiles = function() {
|
|
2858
|
-
error(unsupportedMsg);
|
|
2964
|
+
error$1(unsupportedMsg);
|
|
2859
2965
|
};
|
|
2860
2966
|
} else {
|
|
2861
2967
|
new SimpleButton(menu.findChild('.save-btn').addClass('default-btn')).on('click', onExportClick);
|
|
@@ -2891,7 +2997,7 @@
|
|
|
2891
2997
|
setTimeout(function() {
|
|
2892
2998
|
exportMenuSelection(layers, function(err) {
|
|
2893
2999
|
if (err) {
|
|
2894
|
-
if (utils.isString(err)) {
|
|
3000
|
+
if (utils$1.isString(err)) {
|
|
2895
3001
|
gui.alert(err);
|
|
2896
3002
|
} else {
|
|
2897
3003
|
// stack seems to change if Error is logged directly
|
|
@@ -2938,7 +3044,7 @@
|
|
|
2938
3044
|
// without changing its name elsewhere
|
|
2939
3045
|
layer: Object.assign({}, o.layer)
|
|
2940
3046
|
};
|
|
2941
|
-
var html = utils.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
3047
|
+
var html = utils$1.format(template, i + 1, target.layer.name || '[unnamed layer]');
|
|
2942
3048
|
// return {layer: o.layer, html: html};
|
|
2943
3049
|
var el = El('div').html(html).addClass('layer-item');
|
|
2944
3050
|
var box = el.findChild('input').node();
|
|
@@ -3048,9 +3154,9 @@
|
|
|
3048
3154
|
|
|
3049
3155
|
function initFormatMenu() {
|
|
3050
3156
|
var defaults = ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'svg'];
|
|
3051
|
-
var formats = utils.uniq(defaults.concat(getInputFormats()));
|
|
3157
|
+
var formats = utils$1.uniq(defaults.concat(getInputFormats()));
|
|
3052
3158
|
var items = formats.map(function(fmt) {
|
|
3053
|
-
return utils.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3159
|
+
return utils$1.format('<div><label><input type="radio" name="format" value="%s"' +
|
|
3054
3160
|
' class="radio">%s</label></div>', fmt, internal.getFormatName(fmt));
|
|
3055
3161
|
});
|
|
3056
3162
|
menu.findChild('.export-formats').html(items.join('\n'));
|
|
@@ -3213,7 +3319,7 @@
|
|
|
3213
3319
|
// can be used as unique identifiers for caching rendered HTML, and as
|
|
3214
3320
|
// an id for layer menu event handlers
|
|
3215
3321
|
if (!lyr.menu_id || uniqIds[lyr.menu_id]) {
|
|
3216
|
-
lyr.menu_id = utils.getUniqueName();
|
|
3322
|
+
lyr.menu_id = utils$1.getUniqueName();
|
|
3217
3323
|
}
|
|
3218
3324
|
uniqIds[lyr.menu_id] = true;
|
|
3219
3325
|
if (isPinnable(lyr)) pinnableCount++;
|
|
@@ -3386,7 +3492,7 @@
|
|
|
3386
3492
|
type = lyr.geometry_type + ' feature';
|
|
3387
3493
|
}
|
|
3388
3494
|
if (type) {
|
|
3389
|
-
str = utils.format('%,d %s%s', n, type, utils.pluralSuffix(n));
|
|
3495
|
+
str = utils$1.format('%,d %s%s', n, type, utils$1.pluralSuffix(n));
|
|
3390
3496
|
} else {
|
|
3391
3497
|
str = "[empty]";
|
|
3392
3498
|
}
|
|
@@ -3397,7 +3503,7 @@
|
|
|
3397
3503
|
var file = internal.getLayerSourceFile(lyr, dataset);
|
|
3398
3504
|
var missing = [];
|
|
3399
3505
|
var msg;
|
|
3400
|
-
if (utils.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
|
|
3506
|
+
if (utils$1.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
|
|
3401
3507
|
if (!lyr.data) {
|
|
3402
3508
|
missing.push('.dbf');
|
|
3403
3509
|
}
|
|
@@ -3423,7 +3529,7 @@
|
|
|
3423
3529
|
|
|
3424
3530
|
|
|
3425
3531
|
function rowHTML(c1, c2, cname) {
|
|
3426
|
-
return utils.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
3532
|
+
return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
|
|
3427
3533
|
'<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
|
|
3428
3534
|
}
|
|
3429
3535
|
}
|
|
@@ -3549,7 +3655,7 @@
|
|
|
3549
3655
|
|
|
3550
3656
|
// import { cloneShape } from '../paths/mapshaper-shape-utils';
|
|
3551
3657
|
// import { copyRecord } from '../datatable/mapshaper-data-utils';
|
|
3552
|
-
var snapVerticesToPoint
|
|
3658
|
+
var snapVerticesToPoint = internal.snapVerticesToPoint;
|
|
3553
3659
|
var cloneShape = internal.cloneShape;
|
|
3554
3660
|
var copyRecord = internal.copyRecord;
|
|
3555
3661
|
|
|
@@ -3632,6 +3738,18 @@
|
|
|
3632
3738
|
this.addHistoryState(stashedUndo, redo);
|
|
3633
3739
|
}, this);
|
|
3634
3740
|
|
|
3741
|
+
gui.on('vertex_insert', function(e) {
|
|
3742
|
+
var target = gui.model.getActiveLayer();
|
|
3743
|
+
var arcs = target.dataset.arcs;
|
|
3744
|
+
var undo = function() {
|
|
3745
|
+
internal.deleteVertex(arcs, e.vertex_id);
|
|
3746
|
+
};
|
|
3747
|
+
var redo = function() {
|
|
3748
|
+
internal.insertVertex(arcs, e.vertex_id, e.coordinates);
|
|
3749
|
+
};
|
|
3750
|
+
this.addHistoryState(undo, redo);
|
|
3751
|
+
}, this);
|
|
3752
|
+
|
|
3635
3753
|
this.clear = function() {
|
|
3636
3754
|
reset();
|
|
3637
3755
|
};
|
|
@@ -3658,7 +3776,7 @@
|
|
|
3658
3776
|
var arcs = target.dataset.arcs;
|
|
3659
3777
|
var p = internal.getVertexCoords(ids[0], arcs);
|
|
3660
3778
|
return function() {
|
|
3661
|
-
snapVerticesToPoint
|
|
3779
|
+
snapVerticesToPoint(ids, p, arcs, true);
|
|
3662
3780
|
};
|
|
3663
3781
|
};
|
|
3664
3782
|
|
|
@@ -3791,7 +3909,7 @@
|
|
|
3791
3909
|
};
|
|
3792
3910
|
}
|
|
3793
3911
|
|
|
3794
|
-
utils.inherit(ModeSwitcher, EventDispatcher);
|
|
3912
|
+
utils$1.inherit(ModeSwitcher, EventDispatcher);
|
|
3795
3913
|
|
|
3796
3914
|
function KeyboardEvents(gui) {
|
|
3797
3915
|
var self = this;
|
|
@@ -3819,7 +3937,7 @@
|
|
|
3819
3937
|
};
|
|
3820
3938
|
}
|
|
3821
3939
|
|
|
3822
|
-
utils.inherit(KeyboardEvents, EventDispatcher);
|
|
3940
|
+
utils$1.inherit(KeyboardEvents, EventDispatcher);
|
|
3823
3941
|
|
|
3824
3942
|
function InteractionMode(gui) {
|
|
3825
3943
|
|
|
@@ -3845,7 +3963,7 @@
|
|
|
3845
3963
|
data: 'edit attributes',
|
|
3846
3964
|
labels: 'position labels',
|
|
3847
3965
|
location: 'drag points',
|
|
3848
|
-
vertices: '
|
|
3966
|
+
vertices: 'edit vertices',
|
|
3849
3967
|
selection: 'select features',
|
|
3850
3968
|
off: 'turn off'
|
|
3851
3969
|
};
|
|
@@ -4038,79 +4156,1404 @@
|
|
|
4038
4156
|
}
|
|
4039
4157
|
}
|
|
4040
4158
|
|
|
4041
|
-
function Model(gui) {
|
|
4042
|
-
var self = new internal.Catalog();
|
|
4043
|
-
var deleteLayer = self.deleteLayer;
|
|
4044
|
-
utils.extend(self, EventDispatcher.prototype);
|
|
4159
|
+
function Model(gui) {
|
|
4160
|
+
var self = new internal.Catalog();
|
|
4161
|
+
var deleteLayer = self.deleteLayer;
|
|
4162
|
+
utils$1.extend(self, EventDispatcher.prototype);
|
|
4163
|
+
|
|
4164
|
+
// override Catalog method (so -drop command will work in web console)
|
|
4165
|
+
self.deleteLayer = function(lyr, dataset) {
|
|
4166
|
+
var active, flags;
|
|
4167
|
+
deleteLayer.call(self, lyr, dataset);
|
|
4168
|
+
if (self.isEmpty()) {
|
|
4169
|
+
// refresh browser if deleted layer was the last layer
|
|
4170
|
+
window.location.href = window.location.href.toString();
|
|
4171
|
+
} else {
|
|
4172
|
+
// trigger event to update layer list and, if needed, the map view
|
|
4173
|
+
flags = {};
|
|
4174
|
+
active = self.getActiveLayer();
|
|
4175
|
+
if (active.layer != lyr) {
|
|
4176
|
+
flags.select = true;
|
|
4177
|
+
}
|
|
4178
|
+
internal.cleanupArcs(active.dataset);
|
|
4179
|
+
if (internal.layerHasPaths(lyr)) {
|
|
4180
|
+
flags.arc_count = true; // looks like a kludge, try to remove
|
|
4181
|
+
}
|
|
4182
|
+
self.updated(flags, active.layer, active.dataset);
|
|
4183
|
+
}
|
|
4184
|
+
};
|
|
4185
|
+
|
|
4186
|
+
self.updated = function(flags) {
|
|
4187
|
+
var targets = self.getDefaultTargets();
|
|
4188
|
+
var active = self.getActiveLayer();
|
|
4189
|
+
if (internal.countTargetLayers(targets) > 1) {
|
|
4190
|
+
self.setDefaultTarget([active.layer], active.dataset);
|
|
4191
|
+
gui.session.setTargetLayer(active.layer); // add -target command to target single layer
|
|
4192
|
+
}
|
|
4193
|
+
if (flags.select) {
|
|
4194
|
+
self.dispatchEvent('select', active);
|
|
4195
|
+
}
|
|
4196
|
+
self.dispatchEvent('update', utils$1.extend({flags: flags}, active));
|
|
4197
|
+
};
|
|
4198
|
+
|
|
4199
|
+
self.selectLayer = function(lyr, dataset) {
|
|
4200
|
+
if (self.getActiveLayer().layer == lyr) return;
|
|
4201
|
+
self.setDefaultTarget([lyr], dataset);
|
|
4202
|
+
self.updated({select: true});
|
|
4203
|
+
gui.session.setTargetLayer(lyr);
|
|
4204
|
+
};
|
|
4205
|
+
|
|
4206
|
+
self.selectNextLayer = function() {
|
|
4207
|
+
var next = self.findNextLayer(self.getActiveLayer().layer);
|
|
4208
|
+
if (next) self.selectLayer(next.layer, next.dataset);
|
|
4209
|
+
};
|
|
4210
|
+
|
|
4211
|
+
self.selectPrevLayer = function() {
|
|
4212
|
+
var prev = self.findPrevLayer(self.getActiveLayer().layer);
|
|
4213
|
+
if (prev) self.selectLayer(prev.layer, prev.dataset);
|
|
4214
|
+
};
|
|
4215
|
+
|
|
4216
|
+
return self;
|
|
4217
|
+
}
|
|
4218
|
+
|
|
4219
|
+
var Buffer = require('buffer').Buffer; // works with browserify
|
|
4220
|
+
|
|
4221
|
+
var context = createContext(); // command context (persist for the current command cycle)
|
|
4222
|
+
|
|
4223
|
+
function runningInBrowser() {
|
|
4224
|
+
return typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
4225
|
+
}
|
|
4226
|
+
|
|
4227
|
+
function getStateVar(key) {
|
|
4228
|
+
return context[key];
|
|
4229
|
+
}
|
|
4230
|
+
|
|
4231
|
+
function setStateVar(key, val) {
|
|
4232
|
+
context[key] = val;
|
|
4233
|
+
}
|
|
4234
|
+
|
|
4235
|
+
function createContext() {
|
|
4236
|
+
return {
|
|
4237
|
+
DEBUG: false,
|
|
4238
|
+
QUIET: false,
|
|
4239
|
+
VERBOSE: false,
|
|
4240
|
+
defs: {},
|
|
4241
|
+
input_files: []
|
|
4242
|
+
};
|
|
4243
|
+
}
|
|
4244
|
+
|
|
4245
|
+
// Install a new set of context variables, clear them when an async callback is called.
|
|
4246
|
+
// @cb callback function to wrap
|
|
4247
|
+
// returns wrapped callback function
|
|
4248
|
+
function createAsyncContext(cb) {
|
|
4249
|
+
context = createContext();
|
|
4250
|
+
return function() {
|
|
4251
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4252
|
+
// clear context after cb(), so output/errors can be handled in current context
|
|
4253
|
+
context = createContext();
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
// Save the current context, restore it when an async callback is called
|
|
4258
|
+
// @cb callback function to wrap
|
|
4259
|
+
// returns wrapped callback function
|
|
4260
|
+
function preserveContext(cb) {
|
|
4261
|
+
var ctx = context;
|
|
4262
|
+
return function() {
|
|
4263
|
+
context = ctx;
|
|
4264
|
+
cb.apply(null, utils.toArray(arguments));
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
|
|
4268
|
+
var LOGGING = false;
|
|
4269
|
+
var STDOUT = false; // use stdout for status messages
|
|
4270
|
+
|
|
4271
|
+
// These three functions can be reset by GUI using setLoggingFunctions();
|
|
4272
|
+
var _error = function() {
|
|
4273
|
+
var msg = utils.toArray(arguments).join(' ');
|
|
4274
|
+
throw new Error(msg);
|
|
4275
|
+
};
|
|
4276
|
+
|
|
4277
|
+
var _stop = function() {
|
|
4278
|
+
throw new UserError(formatLogArgs(arguments));
|
|
4279
|
+
};
|
|
4280
|
+
|
|
4281
|
+
var _interrupt = function() {
|
|
4282
|
+
throw new NonFatalError(formatLogArgs(arguments));
|
|
4283
|
+
};
|
|
4284
|
+
|
|
4285
|
+
var _message = function() {
|
|
4286
|
+
logArgs(arguments);
|
|
4287
|
+
};
|
|
4288
|
+
|
|
4289
|
+
function enableLogging() {
|
|
4290
|
+
LOGGING = true;
|
|
4291
|
+
}
|
|
4292
|
+
|
|
4293
|
+
function loggingEnabled() {
|
|
4294
|
+
return !!LOGGING;
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
// Handle an unexpected condition (internal error)
|
|
4298
|
+
function error() {
|
|
4299
|
+
_error.apply(null, utils.toArray(arguments));
|
|
4300
|
+
}
|
|
4301
|
+
|
|
4302
|
+
// Handle an error caused by invalid input or misuse of API
|
|
4303
|
+
function stop() {
|
|
4304
|
+
_stop.apply(null, utils.toArray(arguments));
|
|
4305
|
+
}
|
|
4306
|
+
|
|
4307
|
+
function interrupt() {
|
|
4308
|
+
_interrupt.apply(null, utils.toArray(arguments));
|
|
4309
|
+
}
|
|
4310
|
+
|
|
4311
|
+
// Print a status message
|
|
4312
|
+
function message() {
|
|
4313
|
+
_message.apply(null, messageArgs(arguments));
|
|
4314
|
+
}
|
|
4315
|
+
|
|
4316
|
+
// A way for the GUI to replace the CLI logging functions
|
|
4317
|
+
function setLoggingFunctions(message, error, stop) {
|
|
4318
|
+
_message = message;
|
|
4319
|
+
_error = error;
|
|
4320
|
+
_stop = stop;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
|
|
4324
|
+
// print a message to stdout
|
|
4325
|
+
function print() {
|
|
4326
|
+
STDOUT = true; // tell logArgs() to print to stdout, not stderr
|
|
4327
|
+
// calling message() adds the "[command name]" prefix
|
|
4328
|
+
_message(utils.toArray(arguments));
|
|
4329
|
+
STDOUT = false;
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4332
|
+
function verbose() {
|
|
4333
|
+
// verbose can be set globally with the -verbose command or separately for each command
|
|
4334
|
+
if (getStateVar('VERBOSE') || getStateVar('verbose')) {
|
|
4335
|
+
message.apply(null, arguments);
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
|
|
4339
|
+
function debug() {
|
|
4340
|
+
if (getStateVar('DEBUG') || getStateVar('debug')) {
|
|
4341
|
+
logArgs(arguments);
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
|
|
4345
|
+
function printError(err) {
|
|
4346
|
+
var msg;
|
|
4347
|
+
if (!LOGGING) return;
|
|
4348
|
+
if (utils.isString(err)) {
|
|
4349
|
+
err = new UserError(err);
|
|
4350
|
+
}
|
|
4351
|
+
if (err.name == 'NonFatalError') {
|
|
4352
|
+
console.error(messageArgs([err.message]).join(' '));
|
|
4353
|
+
} else if (err.name == 'UserError') {
|
|
4354
|
+
msg = err.message;
|
|
4355
|
+
if (!/Error/.test(msg)) {
|
|
4356
|
+
msg = "Error: " + msg;
|
|
4357
|
+
}
|
|
4358
|
+
console.error(messageArgs([msg]).join(' '));
|
|
4359
|
+
console.error("Run mapshaper -h to view help");
|
|
4360
|
+
} else {
|
|
4361
|
+
// not a user error (i.e. a bug in mapshaper)
|
|
4362
|
+
console.error(err);
|
|
4363
|
+
// throw err;
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4367
|
+
function UserError(msg) {
|
|
4368
|
+
var err = new Error(msg);
|
|
4369
|
+
err.name = 'UserError';
|
|
4370
|
+
return err;
|
|
4371
|
+
}
|
|
4372
|
+
|
|
4373
|
+
function NonFatalError(msg) {
|
|
4374
|
+
var err = new Error(msg);
|
|
4375
|
+
err.name = 'NonFatalError';
|
|
4376
|
+
return err;
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
function formatColumns(arr, alignments) {
|
|
4380
|
+
var widths = arr.reduce(function(memo, line) {
|
|
4381
|
+
return line.map(function(str, i) {
|
|
4382
|
+
return memo ? Math.max(memo[i], str.length) : str.length;
|
|
4383
|
+
});
|
|
4384
|
+
}, null);
|
|
4385
|
+
return arr.map(function(line) {
|
|
4386
|
+
line = line.map(function(str, i) {
|
|
4387
|
+
var rt = alignments && alignments[i] == 'right';
|
|
4388
|
+
var pad = (rt ? str.padStart : str.padEnd).bind(str);
|
|
4389
|
+
return pad(widths[i], ' ');
|
|
4390
|
+
});
|
|
4391
|
+
return ' ' + line.join(' ');
|
|
4392
|
+
}).join('\n');
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
// Format an array of (preferably short) strings in columns for console logging.
|
|
4396
|
+
function formatStringsAsGrid(arr) {
|
|
4397
|
+
// TODO: variable column width
|
|
4398
|
+
var longest = arr.reduce(function(len, str) {
|
|
4399
|
+
return Math.max(len, str.length);
|
|
4400
|
+
}, 0),
|
|
4401
|
+
colWidth = longest + 2,
|
|
4402
|
+
perLine = Math.floor(80 / colWidth) || 1;
|
|
4403
|
+
return arr.reduce(function(memo, name, i) {
|
|
4404
|
+
var col = i % perLine;
|
|
4405
|
+
if (i > 0 && col === 0) memo += '\n';
|
|
4406
|
+
if (col < perLine - 1) { // right-pad all but rightmost column
|
|
4407
|
+
name = utils.rpad(name, colWidth - 2, ' ');
|
|
4408
|
+
}
|
|
4409
|
+
return memo + ' ' + name;
|
|
4410
|
+
}, '');
|
|
4411
|
+
}
|
|
4412
|
+
|
|
4413
|
+
// expose so GUI can use it
|
|
4414
|
+
function formatLogArgs(args) {
|
|
4415
|
+
return utils.toArray(args).join(' ');
|
|
4416
|
+
}
|
|
4417
|
+
|
|
4418
|
+
function messageArgs(args) {
|
|
4419
|
+
var arr = utils.toArray(args);
|
|
4420
|
+
var cmd = getStateVar('current_command');
|
|
4421
|
+
if (cmd && cmd != 'help') {
|
|
4422
|
+
arr.unshift('[' + cmd + ']');
|
|
4423
|
+
}
|
|
4424
|
+
return arr;
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4427
|
+
function logArgs(args) {
|
|
4428
|
+
if (!LOGGING || getStateVar('QUIET') || !utils.isArrayLike(args)) return;
|
|
4429
|
+
var msg = formatLogArgs(args);
|
|
4430
|
+
if (STDOUT) console.log(msg);
|
|
4431
|
+
else console.error(msg);
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
var uniqCount = 0;
|
|
4435
|
+
function getUniqueName(prefix) {
|
|
4436
|
+
return (prefix || "__id_") + (++uniqCount);
|
|
4437
|
+
}
|
|
4438
|
+
|
|
4439
|
+
function isFunction(obj) {
|
|
4440
|
+
return typeof obj == 'function';
|
|
4441
|
+
}
|
|
4442
|
+
|
|
4443
|
+
function isObject(obj) {
|
|
4444
|
+
return obj === Object(obj); // via underscore
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4447
|
+
function clamp(val, min, max) {
|
|
4448
|
+
return val < min ? min : (val > max ? max : val);
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
function isArray(obj) {
|
|
4452
|
+
return Array.isArray(obj);
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
// Is obj a valid number or NaN? (test if obj is type number)
|
|
4456
|
+
function isNumber(obj) {
|
|
4457
|
+
return obj != null && obj.constructor == Number;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
function isValidNumber(val) {
|
|
4461
|
+
return isNumber(val) && !isNaN(val);
|
|
4462
|
+
}
|
|
4463
|
+
|
|
4464
|
+
// Similar to isFinite() but does not coerce strings or other types
|
|
4465
|
+
function isFiniteNumber(val) {
|
|
4466
|
+
return isValidNumber(val) && val !== Infinity && val !== -Infinity;
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
// This uses type conversion
|
|
4470
|
+
// export function isFiniteNumber(val) {
|
|
4471
|
+
// return val > -Infinity && val < Infinity;
|
|
4472
|
+
// }
|
|
4473
|
+
|
|
4474
|
+
function isNonNegNumber(val) {
|
|
4475
|
+
return isNumber(val) && val >= 0;
|
|
4476
|
+
}
|
|
4477
|
+
|
|
4478
|
+
function isInteger(obj) {
|
|
4479
|
+
return isNumber(obj) && ((obj | 0) === obj);
|
|
4480
|
+
}
|
|
4481
|
+
|
|
4482
|
+
function isEven(obj) {
|
|
4483
|
+
return (obj % 2) === 0;
|
|
4484
|
+
}
|
|
4485
|
+
|
|
4486
|
+
function isOdd(obj) {
|
|
4487
|
+
return (obj % 2) === 1;
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
function isString(obj) {
|
|
4491
|
+
return obj != null && obj.toString === String.prototype.toString;
|
|
4492
|
+
// TODO: replace w/ something better.
|
|
4493
|
+
}
|
|
4494
|
+
|
|
4495
|
+
function isDate(obj) {
|
|
4496
|
+
return !!obj && obj.getTime === Date.prototype.getTime;
|
|
4497
|
+
}
|
|
4498
|
+
|
|
4499
|
+
function isBoolean(obj) {
|
|
4500
|
+
return obj === true || obj === false;
|
|
4501
|
+
}
|
|
4502
|
+
|
|
4503
|
+
function formatDateISO(d) {
|
|
4504
|
+
if (!isDate(d)) return '';
|
|
4505
|
+
return d.toISOString().replace(':00.000Z', 'Z');
|
|
4506
|
+
}
|
|
4507
|
+
|
|
4508
|
+
// Convert an array-like object to an Array, or make a copy if @obj is an Array
|
|
4509
|
+
function toArray(obj) {
|
|
4510
|
+
var arr;
|
|
4511
|
+
if (!isArrayLike(obj)) error("toArray() requires an array-like object");
|
|
4512
|
+
try {
|
|
4513
|
+
arr = Array.prototype.slice.call(obj, 0); // breaks in ie8
|
|
4514
|
+
} catch(e) {
|
|
4515
|
+
// support ie8
|
|
4516
|
+
arr = [];
|
|
4517
|
+
for (var i=0, n=obj.length; i<n; i++) {
|
|
4518
|
+
arr[i] = obj[i];
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
return arr;
|
|
4522
|
+
}
|
|
4523
|
+
|
|
4524
|
+
// Array like: has length property, is numerically indexed and mutable.
|
|
4525
|
+
// TODO: try to detect objects with length property but no indexed data elements
|
|
4526
|
+
function isArrayLike(obj) {
|
|
4527
|
+
if (!obj) return false;
|
|
4528
|
+
if (isArray(obj)) return true;
|
|
4529
|
+
if (isString(obj)) return false;
|
|
4530
|
+
if (obj.length === 0) return true;
|
|
4531
|
+
if (obj.length > 0) return true;
|
|
4532
|
+
return false;
|
|
4533
|
+
}
|
|
4534
|
+
|
|
4535
|
+
// See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js
|
|
4536
|
+
function addslashes(str) {
|
|
4537
|
+
return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
// Escape a literal string to use in a regexp.
|
|
4541
|
+
// Ref.: http://simonwillison.net/2006/Jan/20/escape/
|
|
4542
|
+
function regexEscape(str) {
|
|
4543
|
+
return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
4544
|
+
}
|
|
4545
|
+
|
|
4546
|
+
|
|
4547
|
+
// See https://github.com/janl/mustache.js/blob/master/mustache.js
|
|
4548
|
+
var entityMap = {
|
|
4549
|
+
'&': '&',
|
|
4550
|
+
'<': '<',
|
|
4551
|
+
'>': '>',
|
|
4552
|
+
'"': '"',
|
|
4553
|
+
"'": ''',
|
|
4554
|
+
'/': '/'
|
|
4555
|
+
};
|
|
4556
|
+
function htmlEscape(s) {
|
|
4557
|
+
return String(s).replace(/[&<>"'\/]/g, function(s) {
|
|
4558
|
+
return entityMap[s];
|
|
4559
|
+
});
|
|
4560
|
+
}
|
|
4561
|
+
|
|
4562
|
+
function defaults(dest) {
|
|
4563
|
+
for (var i=1, n=arguments.length; i<n; i++) {
|
|
4564
|
+
var src = arguments[i] || {};
|
|
4565
|
+
for (var key in src) {
|
|
4566
|
+
if (key in dest === false && src.hasOwnProperty(key)) {
|
|
4567
|
+
dest[key] = src[key];
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
return dest;
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
function extend(o) {
|
|
4575
|
+
var dest = o || {},
|
|
4576
|
+
n = arguments.length,
|
|
4577
|
+
key, i, src;
|
|
4578
|
+
for (i=1; i<n; i++) {
|
|
4579
|
+
src = arguments[i] || {};
|
|
4580
|
+
for (key in src) {
|
|
4581
|
+
if (src.hasOwnProperty(key)) {
|
|
4582
|
+
dest[key] = src[key];
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
return dest;
|
|
4587
|
+
}
|
|
4588
|
+
|
|
4589
|
+
// Pseudoclassical inheritance
|
|
4590
|
+
//
|
|
4591
|
+
// Inherit from a Parent function:
|
|
4592
|
+
// inherit(Child, Parent);
|
|
4593
|
+
// Call parent's constructor (inside child constructor):
|
|
4594
|
+
// this.__super__([args...]);
|
|
4595
|
+
function inherit(targ, src) {
|
|
4596
|
+
var f = function() {
|
|
4597
|
+
if (this.__super__ == f) {
|
|
4598
|
+
// add __super__ of parent to front of lookup chain
|
|
4599
|
+
// so parent class constructor can call its parent using this.__super__
|
|
4600
|
+
this.__super__ = src.prototype.__super__;
|
|
4601
|
+
// call parent constructor function. this.__super__ now points to parent-of-parent
|
|
4602
|
+
src.apply(this, arguments);
|
|
4603
|
+
// remove temp __super__, expose targ.prototype.__super__ again
|
|
4604
|
+
delete this.__super__;
|
|
4605
|
+
}
|
|
4606
|
+
};
|
|
4607
|
+
|
|
4608
|
+
f.prototype = src.prototype || src; // added || src to allow inheriting from objects as well as functions
|
|
4609
|
+
// Extend targ prototype instead of wiping it out --
|
|
4610
|
+
// in case inherit() is called after targ.prototype = {stuff}; statement
|
|
4611
|
+
targ.prototype = extend(new f(), targ.prototype); //
|
|
4612
|
+
targ.prototype.constructor = targ;
|
|
4613
|
+
targ.prototype.__super__ = f;
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
|
|
4617
|
+
// Call @iter on each member of an array (similar to Array#reduce(iter))
|
|
4618
|
+
// iter: function(memo, item, callback)
|
|
4619
|
+
// Call @done when all members have been processed or if an error occurs
|
|
4620
|
+
// done: function(err, memo)
|
|
4621
|
+
// @memo: Initial value
|
|
4622
|
+
//
|
|
4623
|
+
function reduceAsync(arr, memo, iter, done) {
|
|
4624
|
+
var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate;
|
|
4625
|
+
var i=0;
|
|
4626
|
+
next(null, memo);
|
|
4627
|
+
|
|
4628
|
+
function next(err, memo) {
|
|
4629
|
+
// Detach next operation from call stack to prevent overflow
|
|
4630
|
+
// Don't use setTimeout(, 0) if setImmediate is available
|
|
4631
|
+
// (setTimeout() can introduce a long delay if previous operation was slow,
|
|
4632
|
+
// as of Node 0.10.32 -- a bug?)
|
|
4633
|
+
if (err) {
|
|
4634
|
+
return done(err, null);
|
|
4635
|
+
}
|
|
4636
|
+
call(function() {
|
|
4637
|
+
if (i < arr.length === false) {
|
|
4638
|
+
done(null, memo);
|
|
4639
|
+
} else {
|
|
4640
|
+
iter(memo, arr[i++], next);
|
|
4641
|
+
}
|
|
4642
|
+
}, 0);
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4646
|
+
|
|
4647
|
+
// Append elements of @src array to @dest array
|
|
4648
|
+
function merge(dest, src) {
|
|
4649
|
+
if (!isArray(dest) || !isArray(src)) {
|
|
4650
|
+
error("Usage: merge(destArray, srcArray);");
|
|
4651
|
+
}
|
|
4652
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
4653
|
+
dest.push(src[i]);
|
|
4654
|
+
}
|
|
4655
|
+
return dest;
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4658
|
+
// Returns elements in arr and not in other
|
|
4659
|
+
// (similar to underscore diff)
|
|
4660
|
+
function difference(arr, other) {
|
|
4661
|
+
var index = arrayToIndex(other);
|
|
4662
|
+
return arr.filter(function(el) {
|
|
4663
|
+
return !Object.prototype.hasOwnProperty.call(index, el);
|
|
4664
|
+
});
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
// Return the intersection of two arrays
|
|
4668
|
+
function intersection(a, b) {
|
|
4669
|
+
return a.filter(function(el) {
|
|
4670
|
+
return b.includes(el);
|
|
4671
|
+
});
|
|
4672
|
+
}
|
|
4673
|
+
|
|
4674
|
+
function indexOf(arr, item) {
|
|
4675
|
+
var nan = item !== item;
|
|
4676
|
+
for (var i = 0, len = arr.length || 0; i < len; i++) {
|
|
4677
|
+
if (arr[i] === item) return i;
|
|
4678
|
+
if (nan && arr[i] !== arr[i]) return i;
|
|
4679
|
+
}
|
|
4680
|
+
return -1;
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
// Test a string or array-like object for existence of substring or element
|
|
4684
|
+
function contains(container, item) {
|
|
4685
|
+
if (isString(container)) {
|
|
4686
|
+
return container.indexOf(item) != -1;
|
|
4687
|
+
}
|
|
4688
|
+
else if (isArrayLike(container)) {
|
|
4689
|
+
return indexOf(container, item) != -1;
|
|
4690
|
+
}
|
|
4691
|
+
error("Expected Array or String argument");
|
|
4692
|
+
}
|
|
4693
|
+
|
|
4694
|
+
function some(arr, test) {
|
|
4695
|
+
return arr.reduce(function(val, item) {
|
|
4696
|
+
return val || test(item); // TODO: short-circuit?
|
|
4697
|
+
}, false);
|
|
4698
|
+
}
|
|
4699
|
+
|
|
4700
|
+
function every(arr, test) {
|
|
4701
|
+
return arr.reduce(function(val, item) {
|
|
4702
|
+
return val && test(item);
|
|
4703
|
+
}, true);
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
function find(arr, test, ctx) {
|
|
4707
|
+
var matches = arr.filter(test, ctx);
|
|
4708
|
+
return matches.length === 0 ? null : matches[0];
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4711
|
+
function range(len, start, inc) {
|
|
4712
|
+
var arr = [],
|
|
4713
|
+
v = start === void 0 ? 0 : start,
|
|
4714
|
+
i = inc === void 0 ? 1 : inc;
|
|
4715
|
+
while(len--) {
|
|
4716
|
+
arr.push(v);
|
|
4717
|
+
v += i;
|
|
4718
|
+
}
|
|
4719
|
+
return arr;
|
|
4720
|
+
}
|
|
4721
|
+
|
|
4722
|
+
function repeat(times, func) {
|
|
4723
|
+
var values = [],
|
|
4724
|
+
val;
|
|
4725
|
+
for (var i=0; i<times; i++) {
|
|
4726
|
+
val = func(i);
|
|
4727
|
+
if (val !== void 0) {
|
|
4728
|
+
values[i] = val;
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
return values.length > 0 ? values : void 0;
|
|
4732
|
+
}
|
|
4733
|
+
|
|
4734
|
+
// Calc sum, skip falsy and NaN values
|
|
4735
|
+
// Assumes: no other non-numeric objects in array
|
|
4736
|
+
//
|
|
4737
|
+
function sum(arr, info) {
|
|
4738
|
+
if (!isArrayLike(arr)) error ("sum() expects an array, received:", arr);
|
|
4739
|
+
var tot = 0,
|
|
4740
|
+
nan = 0,
|
|
4741
|
+
val;
|
|
4742
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
4743
|
+
val = arr[i];
|
|
4744
|
+
if (val) {
|
|
4745
|
+
tot += val;
|
|
4746
|
+
} else if (isNaN(val)) {
|
|
4747
|
+
nan++;
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
if (info) {
|
|
4751
|
+
info.nan = nan;
|
|
4752
|
+
}
|
|
4753
|
+
return tot;
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
// Calculate min and max values of an array, ignoring NaN values
|
|
4757
|
+
function getArrayBounds(arr) {
|
|
4758
|
+
var min = Infinity,
|
|
4759
|
+
max = -Infinity,
|
|
4760
|
+
nan = 0, val;
|
|
4761
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4762
|
+
val = arr[i];
|
|
4763
|
+
if (val !== val) nan++;
|
|
4764
|
+
if (val < min) min = val;
|
|
4765
|
+
if (val > max) max = val;
|
|
4766
|
+
}
|
|
4767
|
+
return {
|
|
4768
|
+
min: min,
|
|
4769
|
+
max: max,
|
|
4770
|
+
nan: nan
|
|
4771
|
+
};
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4774
|
+
// export function uniq(src) {
|
|
4775
|
+
// var index = {};
|
|
4776
|
+
// return src.reduce(function(memo, el) {
|
|
4777
|
+
// if (el in index === false) {
|
|
4778
|
+
// index[el] = true;
|
|
4779
|
+
// memo.push(el);
|
|
4780
|
+
// }
|
|
4781
|
+
// return memo;
|
|
4782
|
+
// }, []);
|
|
4783
|
+
// }
|
|
4784
|
+
|
|
4785
|
+
function uniq(src) {
|
|
4786
|
+
var index = new Set();
|
|
4787
|
+
var arr = [];
|
|
4788
|
+
var item;
|
|
4789
|
+
for (var i=0, n=src.length; i<n; i++) {
|
|
4790
|
+
item = src[i];
|
|
4791
|
+
if (!index.has(item)) {
|
|
4792
|
+
arr.push(item);
|
|
4793
|
+
index.add(item);
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
return arr;
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
function pluck(arr, key) {
|
|
4800
|
+
return arr.map(function(obj) {
|
|
4801
|
+
return obj[key];
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4805
|
+
function countValues(arr) {
|
|
4806
|
+
return arr.reduce(function(memo, val) {
|
|
4807
|
+
memo[val] = (val in memo) ? memo[val] + 1 : 1;
|
|
4808
|
+
return memo;
|
|
4809
|
+
}, {});
|
|
4810
|
+
}
|
|
4811
|
+
|
|
4812
|
+
function indexOn(arr, k) {
|
|
4813
|
+
return arr.reduce(function(index, o) {
|
|
4814
|
+
index[o[k]] = o;
|
|
4815
|
+
return index;
|
|
4816
|
+
}, {});
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4819
|
+
function groupBy(arr, k) {
|
|
4820
|
+
return arr.reduce(function(index, o) {
|
|
4821
|
+
var keyval = o[k];
|
|
4822
|
+
if (keyval in index) {
|
|
4823
|
+
index[keyval].push(o);
|
|
4824
|
+
} else {
|
|
4825
|
+
index[keyval] = [o];
|
|
4826
|
+
}
|
|
4827
|
+
return index;
|
|
4828
|
+
}, {});
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
function arrayToIndex(arr, val) {
|
|
4832
|
+
var init = arguments.length > 1;
|
|
4833
|
+
return arr.reduce(function(index, key) {
|
|
4834
|
+
index[key] = init ? val : true;
|
|
4835
|
+
return index;
|
|
4836
|
+
}, {});
|
|
4837
|
+
}
|
|
4838
|
+
|
|
4839
|
+
// Support for iterating over array-like objects, like typed arrays
|
|
4840
|
+
function forEach(arr, func, ctx) {
|
|
4841
|
+
if (!isArrayLike(arr)) {
|
|
4842
|
+
throw new Error("#forEach() takes an array-like argument. " + arr);
|
|
4843
|
+
}
|
|
4844
|
+
for (var i=0, n=arr.length; i < n; i++) {
|
|
4845
|
+
func.call(ctx, arr[i], i);
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4849
|
+
function forEachProperty(o, func, ctx) {
|
|
4850
|
+
Object.keys(o).forEach(function(key) {
|
|
4851
|
+
func.call(ctx, o[key], key);
|
|
4852
|
+
});
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4855
|
+
function initializeArray(arr, init) {
|
|
4856
|
+
for (var i=0, len=arr.length; i<len; i++) {
|
|
4857
|
+
arr[i] = init;
|
|
4858
|
+
}
|
|
4859
|
+
return arr;
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4862
|
+
function replaceArray(arr, arr2) {
|
|
4863
|
+
arr.splice(0, arr.length);
|
|
4864
|
+
for (var i=0, n=arr2.length; i<n; i++) {
|
|
4865
|
+
arr.push(arr2[i]);
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
|
|
4869
|
+
function repeatString(src, n) {
|
|
4870
|
+
var str = "";
|
|
4871
|
+
for (var i=0; i<n; i++)
|
|
4872
|
+
str += src;
|
|
4873
|
+
return str;
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
function splitLines(str) {
|
|
4877
|
+
return str.split(/\r?\n/);
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
function pluralSuffix(count) {
|
|
4881
|
+
return count != 1 ? 's' : '';
|
|
4882
|
+
}
|
|
4883
|
+
|
|
4884
|
+
function endsWith(str, ending) {
|
|
4885
|
+
return str.indexOf(ending, str.length - ending.length) !== -1;
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
function lpad(str, size, pad) {
|
|
4889
|
+
pad = pad || ' ';
|
|
4890
|
+
str = String(str);
|
|
4891
|
+
return repeatString(pad, size - str.length) + str;
|
|
4892
|
+
}
|
|
4893
|
+
|
|
4894
|
+
function rpad(str, size, pad) {
|
|
4895
|
+
pad = pad || ' ';
|
|
4896
|
+
str = String(str);
|
|
4897
|
+
return str + repeatString(pad, size - str.length);
|
|
4898
|
+
}
|
|
4899
|
+
|
|
4900
|
+
function trim(str) {
|
|
4901
|
+
return ltrim(rtrim(str));
|
|
4902
|
+
}
|
|
4903
|
+
|
|
4904
|
+
var ltrimRxp = /^\s+/;
|
|
4905
|
+
function ltrim(str) {
|
|
4906
|
+
return str.replace(ltrimRxp, '');
|
|
4907
|
+
}
|
|
4908
|
+
|
|
4909
|
+
var rtrimRxp = /\s+$/;
|
|
4910
|
+
function rtrim(str) {
|
|
4911
|
+
return str.replace(rtrimRxp, '');
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
function addThousandsSep(str) {
|
|
4915
|
+
var fmt = '',
|
|
4916
|
+
start = str[0] == '-' ? 1 : 0,
|
|
4917
|
+
dec = str.indexOf('.'),
|
|
4918
|
+
end = str.length,
|
|
4919
|
+
ins = (dec == -1 ? end : dec) - 3;
|
|
4920
|
+
while (ins > start) {
|
|
4921
|
+
fmt = ',' + str.substring(ins, end) + fmt;
|
|
4922
|
+
end = ins;
|
|
4923
|
+
ins -= 3;
|
|
4924
|
+
}
|
|
4925
|
+
return str.substring(0, end) + fmt;
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4928
|
+
function numToStr(num, decimals) {
|
|
4929
|
+
return decimals >= 0 ? num.toFixed(decimals) : String(num);
|
|
4930
|
+
}
|
|
4931
|
+
|
|
4932
|
+
function formatNumber(val) {
|
|
4933
|
+
return val + '';
|
|
4934
|
+
}
|
|
4935
|
+
|
|
4936
|
+
function formatIntlNumber(val) {
|
|
4937
|
+
var str = formatNumber(val);
|
|
4938
|
+
return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
function formatNumberForDisplay(num, decimals, nullStr, showPos) {
|
|
4942
|
+
var fmt;
|
|
4943
|
+
if (isNaN(num)) {
|
|
4944
|
+
fmt = nullStr || '-';
|
|
4945
|
+
} else {
|
|
4946
|
+
fmt = numToStr(num, decimals);
|
|
4947
|
+
fmt = addThousandsSep(fmt);
|
|
4948
|
+
if (showPos && parseFloat(fmt) > 0) {
|
|
4949
|
+
fmt = "+" + fmt;
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
return fmt;
|
|
4953
|
+
}
|
|
4954
|
+
|
|
4955
|
+
function shuffle(arr) {
|
|
4956
|
+
var tmp, i, j;
|
|
4957
|
+
for (i = arr.length - 1; i > 0; i--) {
|
|
4958
|
+
j = Math.floor(Math.random() * (i + 1));
|
|
4959
|
+
tmp = arr[i];
|
|
4960
|
+
arr[i] = arr[j];
|
|
4961
|
+
arr[j] = tmp;
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
// Sort an array of objects based on one or more properties.
|
|
4966
|
+
// Usage: sortOn(array, key1, asc?[, key2, asc? ...])
|
|
4967
|
+
//
|
|
4968
|
+
function sortOn(arr) {
|
|
4969
|
+
var comparators = [];
|
|
4970
|
+
for (var i=1; i<arguments.length; i+=2) {
|
|
4971
|
+
comparators.push(getKeyComparator(arguments[i], arguments[i+1]));
|
|
4972
|
+
}
|
|
4973
|
+
arr.sort(function(a, b) {
|
|
4974
|
+
var cmp = 0,
|
|
4975
|
+
i = 0,
|
|
4976
|
+
n = comparators.length;
|
|
4977
|
+
while (i < n && cmp === 0) {
|
|
4978
|
+
cmp = comparators[i](a, b);
|
|
4979
|
+
i++;
|
|
4980
|
+
}
|
|
4981
|
+
return cmp;
|
|
4982
|
+
});
|
|
4983
|
+
return arr;
|
|
4984
|
+
}
|
|
4985
|
+
|
|
4986
|
+
// Sort array of values that can be compared with < > operators (strings, numbers)
|
|
4987
|
+
// null, undefined and NaN are sorted to the end of the array
|
|
4988
|
+
// default order is ascending
|
|
4989
|
+
//
|
|
4990
|
+
function genericSort(arr, ascending) {
|
|
4991
|
+
var compare = getGenericComparator(ascending);
|
|
4992
|
+
Array.prototype.sort.call(arr, compare);
|
|
4993
|
+
return arr;
|
|
4994
|
+
}
|
|
4995
|
+
|
|
4996
|
+
function getSortedIds(arr, asc) {
|
|
4997
|
+
var ids = range(arr.length);
|
|
4998
|
+
sortArrayIndex(ids, arr, asc);
|
|
4999
|
+
return ids;
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
function sortArrayIndex(ids, arr, asc) {
|
|
5003
|
+
var compare = getGenericComparator(asc);
|
|
5004
|
+
ids.sort(function(i, j) {
|
|
5005
|
+
// added i, j comparison to guarantee that sort is stable
|
|
5006
|
+
var cmp = compare(arr[i], arr[j]);
|
|
5007
|
+
return cmp > 0 || cmp === 0 && i > j ? 1 : -1;
|
|
5008
|
+
});
|
|
5009
|
+
}
|
|
5010
|
+
|
|
5011
|
+
function reorderArray(arr, idxs) {
|
|
5012
|
+
var len = idxs.length;
|
|
5013
|
+
var arr2 = [];
|
|
5014
|
+
for (var i=0; i<len; i++) {
|
|
5015
|
+
var idx = idxs[i];
|
|
5016
|
+
if (idx < 0 || idx >= len) error("Out-of-bounds array idx");
|
|
5017
|
+
arr2[i] = arr[idx];
|
|
5018
|
+
}
|
|
5019
|
+
replaceArray(arr, arr2);
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
function getKeyComparator(key, asc) {
|
|
5023
|
+
var compare = getGenericComparator(asc);
|
|
5024
|
+
return function(a, b) {
|
|
5025
|
+
return compare(a[key], b[key]);
|
|
5026
|
+
};
|
|
5027
|
+
}
|
|
5028
|
+
|
|
5029
|
+
function getGenericComparator(asc) {
|
|
5030
|
+
asc = asc !== false;
|
|
5031
|
+
return function(a, b) {
|
|
5032
|
+
var retn = 0;
|
|
5033
|
+
if (b == null) {
|
|
5034
|
+
retn = a == null ? 0 : -1;
|
|
5035
|
+
} else if (a == null) {
|
|
5036
|
+
retn = 1;
|
|
5037
|
+
} else if (a < b) {
|
|
5038
|
+
retn = asc ? -1 : 1;
|
|
5039
|
+
} else if (a > b) {
|
|
5040
|
+
retn = asc ? 1 : -1;
|
|
5041
|
+
} else if (a !== a) {
|
|
5042
|
+
retn = 1;
|
|
5043
|
+
} else if (b !== b) {
|
|
5044
|
+
retn = -1;
|
|
5045
|
+
}
|
|
5046
|
+
return retn;
|
|
5047
|
+
};
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
|
|
5051
|
+
// Generic in-place sort (null, NaN, undefined not handled)
|
|
5052
|
+
function quicksort(arr, asc) {
|
|
5053
|
+
quicksortPartition(arr, 0, arr.length-1);
|
|
5054
|
+
if (asc === false) Array.prototype.reverse.call(arr); // Works with typed arrays
|
|
5055
|
+
return arr;
|
|
5056
|
+
}
|
|
5057
|
+
|
|
5058
|
+
// Moved out of quicksort() (saw >100% speedup in Chrome with deep recursion)
|
|
5059
|
+
function quicksortPartition (a, lo, hi) {
|
|
5060
|
+
var i = lo,
|
|
5061
|
+
j = hi,
|
|
5062
|
+
pivot, tmp;
|
|
5063
|
+
while (i < hi) {
|
|
5064
|
+
pivot = a[lo + hi >> 1]; // avoid n^2 performance on sorted arrays
|
|
5065
|
+
while (i <= j) {
|
|
5066
|
+
while (a[i] < pivot) i++;
|
|
5067
|
+
while (a[j] > pivot) j--;
|
|
5068
|
+
if (i <= j) {
|
|
5069
|
+
tmp = a[i];
|
|
5070
|
+
a[i] = a[j];
|
|
5071
|
+
a[j] = tmp;
|
|
5072
|
+
i++;
|
|
5073
|
+
j--;
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
if (lo < j) quicksortPartition(a, lo, j);
|
|
5077
|
+
lo = i;
|
|
5078
|
+
j = hi;
|
|
5079
|
+
}
|
|
5080
|
+
}
|
|
5081
|
+
|
|
5082
|
+
|
|
5083
|
+
function findRankByValue(arr, value) {
|
|
5084
|
+
if (isNaN(value)) return arr.length;
|
|
5085
|
+
var rank = 1;
|
|
5086
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
5087
|
+
if (value > arr[i]) rank++;
|
|
5088
|
+
}
|
|
5089
|
+
return rank;
|
|
5090
|
+
}
|
|
5091
|
+
|
|
5092
|
+
function findValueByPct(arr, pct) {
|
|
5093
|
+
var rank = Math.ceil((1-pct) * (arr.length));
|
|
5094
|
+
return findValueByRank(arr, rank);
|
|
5095
|
+
}
|
|
5096
|
+
|
|
5097
|
+
// See http://ndevilla.free.fr/median/median/src/wirth.c
|
|
5098
|
+
// Elements of @arr are reordered
|
|
5099
|
+
//
|
|
5100
|
+
function findValueByRank(arr, rank) {
|
|
5101
|
+
if (!arr.length || rank < 1 || rank > arr.length) error("[findValueByRank()] invalid input");
|
|
5102
|
+
|
|
5103
|
+
rank = clamp(rank | 0, 1, arr.length);
|
|
5104
|
+
var k = rank - 1, // conv. rank to array index
|
|
5105
|
+
n = arr.length,
|
|
5106
|
+
l = 0,
|
|
5107
|
+
m = n - 1,
|
|
5108
|
+
i, j, val, tmp;
|
|
5109
|
+
|
|
5110
|
+
while (l < m) {
|
|
5111
|
+
val = arr[k];
|
|
5112
|
+
i = l;
|
|
5113
|
+
j = m;
|
|
5114
|
+
do {
|
|
5115
|
+
while (arr[i] < val) {i++;}
|
|
5116
|
+
while (val < arr[j]) {j--;}
|
|
5117
|
+
if (i <= j) {
|
|
5118
|
+
tmp = arr[i];
|
|
5119
|
+
arr[i] = arr[j];
|
|
5120
|
+
arr[j] = tmp;
|
|
5121
|
+
i++;
|
|
5122
|
+
j--;
|
|
5123
|
+
}
|
|
5124
|
+
} while (i <= j);
|
|
5125
|
+
if (j < k) l = i;
|
|
5126
|
+
if (k < i) m = j;
|
|
5127
|
+
}
|
|
5128
|
+
return arr[k];
|
|
5129
|
+
}
|
|
5130
|
+
|
|
5131
|
+
//
|
|
5132
|
+
//
|
|
5133
|
+
function findMedian(arr) {
|
|
5134
|
+
var n = arr.length,
|
|
5135
|
+
rank = Math.floor(n / 2) + 1,
|
|
5136
|
+
median = findValueByRank(arr, rank);
|
|
5137
|
+
if ((n & 1) == 0) {
|
|
5138
|
+
median = (median + findValueByRank(arr, rank - 1)) / 2;
|
|
5139
|
+
}
|
|
5140
|
+
return median;
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
|
|
5144
|
+
function mean(arr) {
|
|
5145
|
+
var count = 0,
|
|
5146
|
+
avg = NaN,
|
|
5147
|
+
val;
|
|
5148
|
+
for (var i=0, n=arr.length; i<n; i++) {
|
|
5149
|
+
val = arr[i];
|
|
5150
|
+
if (isNaN(val)) continue;
|
|
5151
|
+
avg = ++count == 1 ? val : val / count + (count - 1) / count * avg;
|
|
5152
|
+
}
|
|
5153
|
+
return avg;
|
|
5154
|
+
}
|
|
5155
|
+
|
|
5156
|
+
|
|
5157
|
+
/*
|
|
5158
|
+
A simplified version of printf formatting
|
|
5159
|
+
Format codes: %[flags][width][.precision]type
|
|
5160
|
+
|
|
5161
|
+
supported flags:
|
|
5162
|
+
+ add '+' before positive numbers
|
|
5163
|
+
0 left-pad with '0'
|
|
5164
|
+
' Add thousands separator
|
|
5165
|
+
width: 1 to many
|
|
5166
|
+
precision: .(1 to many)
|
|
5167
|
+
type:
|
|
5168
|
+
s string
|
|
5169
|
+
di integers
|
|
5170
|
+
f decimal numbers
|
|
5171
|
+
xX hexidecimal (unsigned)
|
|
5172
|
+
% literal '%'
|
|
5173
|
+
|
|
5174
|
+
Examples:
|
|
5175
|
+
code val formatted
|
|
5176
|
+
%+d 1 '+1'
|
|
5177
|
+
%4i 32 ' 32'
|
|
5178
|
+
%04i 32 '0032'
|
|
5179
|
+
%x 255 'ff'
|
|
5180
|
+
%.2f 0.125 '0.13'
|
|
5181
|
+
%'f 1000 '1,000'
|
|
5182
|
+
*/
|
|
5183
|
+
|
|
5184
|
+
// Usage: format(formatString, [values])
|
|
5185
|
+
// Tip: When reusing the same format many times, use formatter() for 5x - 10x better performance
|
|
5186
|
+
//
|
|
5187
|
+
function format(fmt) {
|
|
5188
|
+
var fn = formatter(fmt);
|
|
5189
|
+
var str = fn.apply(null, Array.prototype.slice.call(arguments, 1));
|
|
5190
|
+
return str;
|
|
5191
|
+
}
|
|
5192
|
+
|
|
5193
|
+
function formatValue(val, matches) {
|
|
5194
|
+
var flags = matches[1];
|
|
5195
|
+
var padding = matches[2];
|
|
5196
|
+
var decimals = matches[3] ? parseInt(matches[3].substr(1)) : void 0;
|
|
5197
|
+
var type = matches[4];
|
|
5198
|
+
var isString = type == 's',
|
|
5199
|
+
isHex = type == 'x' || type == 'X',
|
|
5200
|
+
isInt = type == 'd' || type == 'i',
|
|
5201
|
+
isFloat = type == 'f',
|
|
5202
|
+
isNumber = !isString;
|
|
5203
|
+
|
|
5204
|
+
var sign = "",
|
|
5205
|
+
padDigits = 0,
|
|
5206
|
+
isZero = false,
|
|
5207
|
+
isNeg = false;
|
|
5208
|
+
|
|
5209
|
+
var str, padChar, padStr;
|
|
5210
|
+
if (isString) {
|
|
5211
|
+
str = String(val);
|
|
5212
|
+
}
|
|
5213
|
+
else if (isHex) {
|
|
5214
|
+
str = val.toString(16);
|
|
5215
|
+
if (type == 'X')
|
|
5216
|
+
str = str.toUpperCase();
|
|
5217
|
+
}
|
|
5218
|
+
else if (isNumber) {
|
|
5219
|
+
// str = formatNumberForDisplay(val, isInt ? 0 : decimals);
|
|
5220
|
+
str = numToStr(val, decimals);
|
|
5221
|
+
if (str[0] == '-') {
|
|
5222
|
+
isNeg = true;
|
|
5223
|
+
str = str.substr(1);
|
|
5224
|
+
}
|
|
5225
|
+
isZero = parseFloat(str) == 0;
|
|
5226
|
+
if (flags.indexOf("'") != -1 || flags.indexOf(',') != -1) {
|
|
5227
|
+
str = addThousandsSep(str);
|
|
5228
|
+
}
|
|
5229
|
+
if (!isZero) { // BUG: sign is added when num rounds to 0
|
|
5230
|
+
if (isNeg) {
|
|
5231
|
+
sign = "\u2212"; // U+2212
|
|
5232
|
+
} else if (flags.indexOf('+') != -1) {
|
|
5233
|
+
sign = '+';
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
|
|
5238
|
+
if (padding) {
|
|
5239
|
+
var strLen = str.length + sign.length;
|
|
5240
|
+
var minWidth = parseInt(padding, 10);
|
|
5241
|
+
if (strLen < minWidth) {
|
|
5242
|
+
padDigits = minWidth - strLen;
|
|
5243
|
+
padChar = flags.indexOf('0') == -1 ? ' ' : '0';
|
|
5244
|
+
padStr = repeatString(padChar, padDigits);
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
|
|
5248
|
+
if (padDigits == 0) {
|
|
5249
|
+
str = sign + str;
|
|
5250
|
+
} else if (padChar == '0') {
|
|
5251
|
+
str = sign + padStr + str;
|
|
5252
|
+
} else {
|
|
5253
|
+
str = padStr + sign + str;
|
|
5254
|
+
}
|
|
5255
|
+
return str;
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
// Get a function for interpolating formatted values into a string.
|
|
5259
|
+
function formatter(fmt) {
|
|
5260
|
+
var codeRxp = /%([\',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
|
|
5261
|
+
var literals = [],
|
|
5262
|
+
formatCodes = [],
|
|
5263
|
+
startIdx = 0,
|
|
5264
|
+
prefix = "",
|
|
5265
|
+
matches = codeRxp.exec(fmt),
|
|
5266
|
+
literal;
|
|
5267
|
+
|
|
5268
|
+
while (matches) {
|
|
5269
|
+
literal = fmt.substring(startIdx, codeRxp.lastIndex - matches[0].length);
|
|
5270
|
+
if (matches[0] == '%%') {
|
|
5271
|
+
prefix += literal + '%';
|
|
5272
|
+
} else {
|
|
5273
|
+
literals.push(prefix + literal);
|
|
5274
|
+
prefix = '';
|
|
5275
|
+
formatCodes.push(matches);
|
|
5276
|
+
}
|
|
5277
|
+
startIdx = codeRxp.lastIndex;
|
|
5278
|
+
matches = codeRxp.exec(fmt);
|
|
5279
|
+
}
|
|
5280
|
+
literals.push(prefix + fmt.substr(startIdx));
|
|
5281
|
+
|
|
5282
|
+
return function() {
|
|
5283
|
+
var str = literals[0],
|
|
5284
|
+
n = arguments.length;
|
|
5285
|
+
if (n != formatCodes.length) {
|
|
5286
|
+
error("[format()] Data does not match format string; format:", fmt, "data:", arguments);
|
|
5287
|
+
}
|
|
5288
|
+
for (var i=0; i<n; i++) {
|
|
5289
|
+
str += formatValue(arguments[i], formatCodes[i]) + literals[i+1];
|
|
5290
|
+
}
|
|
5291
|
+
return str;
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
|
|
5295
|
+
function wildcardToRegExp(name) {
|
|
5296
|
+
var rxp = name.split('*').map(function(str) {
|
|
5297
|
+
return regexEscape(str);
|
|
5298
|
+
}).join('.*');
|
|
5299
|
+
return new RegExp('^' + rxp + '$');
|
|
5300
|
+
}
|
|
5301
|
+
|
|
5302
|
+
function createBuffer(arg, arg2) {
|
|
5303
|
+
if (isInteger(arg)) {
|
|
5304
|
+
return Buffer.allocUnsafe ? Buffer.allocUnsafe(arg) : new Buffer(arg);
|
|
5305
|
+
} else {
|
|
5306
|
+
// check allocUnsafe to make sure Buffer.from() will accept strings (it didn't before Node v5.10)
|
|
5307
|
+
return Buffer.from && Buffer.allocUnsafe ? Buffer.from(arg, arg2) : new Buffer(arg, arg2);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5311
|
+
function expandoBuffer(constructor, rate) {
|
|
5312
|
+
var capacity = 0,
|
|
5313
|
+
k = rate >= 1 ? rate : 1.2,
|
|
5314
|
+
buf;
|
|
5315
|
+
return function(size) {
|
|
5316
|
+
if (size > capacity) {
|
|
5317
|
+
capacity = Math.ceil(size * k);
|
|
5318
|
+
buf = constructor ? new constructor(capacity) : createBuffer(capacity);
|
|
5319
|
+
}
|
|
5320
|
+
return buf;
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5324
|
+
function copyElements(src, i, dest, j, n, rev) {
|
|
5325
|
+
var same = src == dest || src.buffer && src.buffer == dest.buffer;
|
|
5326
|
+
var inc = 1,
|
|
5327
|
+
offs = 0,
|
|
5328
|
+
k;
|
|
5329
|
+
if (rev) {
|
|
5330
|
+
if (same) error('copy error');
|
|
5331
|
+
inc = -1;
|
|
5332
|
+
offs = n - 1;
|
|
5333
|
+
}
|
|
5334
|
+
if (same && j > i) {
|
|
5335
|
+
for (k=n-1; k>=0; k--) {
|
|
5336
|
+
dest[j + k] = src[i + k];
|
|
5337
|
+
}
|
|
5338
|
+
} else {
|
|
5339
|
+
for (k=0; k<n; k++, offs += inc) {
|
|
5340
|
+
dest[k + j] = src[i + offs];
|
|
5341
|
+
}
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5344
|
+
|
|
5345
|
+
function extendBuffer(src, newLen, copyLen) {
|
|
5346
|
+
var len = Math.max(src.length, newLen);
|
|
5347
|
+
var n = copyLen || src.length;
|
|
5348
|
+
var dest = new src.constructor(len);
|
|
5349
|
+
copyElements(src, 0, dest, 0, n);
|
|
5350
|
+
return dest;
|
|
5351
|
+
}
|
|
5352
|
+
|
|
5353
|
+
function mergeNames(name1, name2) {
|
|
5354
|
+
var merged;
|
|
5355
|
+
if (name1 && name2) {
|
|
5356
|
+
merged = findStringPrefix(name1, name2).replace(/[-_]$/, '');
|
|
5357
|
+
}
|
|
5358
|
+
return merged || '';
|
|
5359
|
+
}
|
|
5360
|
+
|
|
5361
|
+
function findStringPrefix(a, b) {
|
|
5362
|
+
var i = 0;
|
|
5363
|
+
for (var n=a.length; i<n; i++) {
|
|
5364
|
+
if (a[i] !== b[i]) break;
|
|
5365
|
+
}
|
|
5366
|
+
return a.substr(0, i);
|
|
5367
|
+
}
|
|
5368
|
+
|
|
5369
|
+
function parsePercent(o) {
|
|
5370
|
+
var str = String(o);
|
|
5371
|
+
var isPct = str.indexOf('%') > 0;
|
|
5372
|
+
var pct;
|
|
5373
|
+
if (isPct) {
|
|
5374
|
+
pct = Number(str.replace('%', '')) / 100;
|
|
5375
|
+
} else {
|
|
5376
|
+
pct = Number(str);
|
|
5377
|
+
}
|
|
5378
|
+
if (!(pct >= 0 && pct <= 1)) {
|
|
5379
|
+
stop(format("Invalid percentage: %s", str));
|
|
5380
|
+
}
|
|
5381
|
+
return pct;
|
|
5382
|
+
}
|
|
5383
|
+
|
|
5384
|
+
function formatVersionedName(name, i) {
|
|
5385
|
+
var suffix = String(i);
|
|
5386
|
+
if (/[0-9]$/.test(name)) {
|
|
5387
|
+
suffix = '-' + suffix;
|
|
5388
|
+
}
|
|
5389
|
+
return name + suffix;
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
function uniqifyNames(names, formatter) {
|
|
5393
|
+
var counts = countValues(names),
|
|
5394
|
+
format = formatter || formatVersionedName,
|
|
5395
|
+
names2 = [];
|
|
4045
5396
|
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
flags.select = true;
|
|
4059
|
-
}
|
|
4060
|
-
internal.cleanupArcs(active.dataset);
|
|
4061
|
-
if (internal.layerHasPaths(lyr)) {
|
|
4062
|
-
flags.arc_count = true; // looks like a kludge, try to remove
|
|
5397
|
+
names.forEach(function(name) {
|
|
5398
|
+
var i = 0,
|
|
5399
|
+
candidate = name,
|
|
5400
|
+
versionedName;
|
|
5401
|
+
while (
|
|
5402
|
+
names2.indexOf(candidate) > -1 || // candidate name has already been used
|
|
5403
|
+
candidate == name && counts[candidate] > 1 || // duplicate unversioned names
|
|
5404
|
+
candidate != name && counts[candidate] > 0) { // versioned name is a preexisting name
|
|
5405
|
+
i++;
|
|
5406
|
+
versionedName = format(name, i);
|
|
5407
|
+
if (!versionedName || versionedName == candidate) {
|
|
5408
|
+
throw new Error("Naming error"); // catch buggy versioning function
|
|
4063
5409
|
}
|
|
4064
|
-
|
|
5410
|
+
candidate = versionedName;
|
|
4065
5411
|
}
|
|
4066
|
-
|
|
5412
|
+
names2.push(candidate);
|
|
5413
|
+
});
|
|
5414
|
+
return names2;
|
|
5415
|
+
}
|
|
4067
5416
|
|
|
4068
|
-
self.updated = function(flags) {
|
|
4069
|
-
var targets = self.getDefaultTargets();
|
|
4070
|
-
var active = self.getActiveLayer();
|
|
4071
|
-
if (internal.countTargetLayers(targets) > 1) {
|
|
4072
|
-
self.setDefaultTarget([active.layer], active.dataset);
|
|
4073
|
-
gui.session.setTargetLayer(active.layer); // add -target command to target single layer
|
|
4074
|
-
}
|
|
4075
|
-
if (flags.select) {
|
|
4076
|
-
self.dispatchEvent('select', active);
|
|
4077
|
-
}
|
|
4078
|
-
self.dispatchEvent('update', utils.extend({flags: flags}, active));
|
|
4079
|
-
};
|
|
4080
5417
|
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
gui.session.setTargetLayer(lyr);
|
|
4086
|
-
};
|
|
5418
|
+
// Assume: @raw is string, undefined or null
|
|
5419
|
+
function parseString(raw) {
|
|
5420
|
+
return raw ? raw : "";
|
|
5421
|
+
}
|
|
4087
5422
|
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
5423
|
+
// Assume: @raw is string, undefined or null
|
|
5424
|
+
// Use null instead of NaN for unparsable values
|
|
5425
|
+
// (in part because if NaN is used, empty strings get converted to "NaN"
|
|
5426
|
+
// when re-exported).
|
|
5427
|
+
function parseNumber(raw) {
|
|
5428
|
+
return parseToNum(raw, cleanNumericString);
|
|
5429
|
+
}
|
|
4092
5430
|
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
};
|
|
5431
|
+
function parseIntlNumber(raw) {
|
|
5432
|
+
return parseToNum(raw, convertIntlNumString);
|
|
5433
|
+
}
|
|
4097
5434
|
|
|
4098
|
-
|
|
5435
|
+
function parseToNum(raw, clean) {
|
|
5436
|
+
var str = String(raw).trim();
|
|
5437
|
+
var parsed = str ? Number(clean(str)) : NaN;
|
|
5438
|
+
return isNaN(parsed) ? null : parsed;
|
|
5439
|
+
}
|
|
5440
|
+
|
|
5441
|
+
// Remove comma separators from strings
|
|
5442
|
+
function cleanNumericString(str) {
|
|
5443
|
+
return (str.indexOf(',') > 0) ? str.replace(/,([0-9]{3})/g, '$1') : str;
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
function convertIntlNumString(str) {
|
|
5447
|
+
str = str.replace(/[ .]([0-9]{3})/g, '$1');
|
|
5448
|
+
return str.replace(',', '.');
|
|
5449
|
+
}
|
|
5450
|
+
|
|
5451
|
+
function trimQuotes(raw) {
|
|
5452
|
+
var len = raw.length, first, last;
|
|
5453
|
+
if (len >= 2) {
|
|
5454
|
+
first = raw.charAt(0);
|
|
5455
|
+
last = raw.charAt(len-1);
|
|
5456
|
+
if (first == '"' && last == '"' && !raw.includes('","') ||
|
|
5457
|
+
first == "'" && last == "'" && !raw.includes("','")) {
|
|
5458
|
+
return raw.substr(1, len-2);
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
return raw;
|
|
5462
|
+
}
|
|
5463
|
+
|
|
5464
|
+
function absArcId(arcId) {
|
|
5465
|
+
return arcId >= 0 ? arcId : ~arcId;
|
|
4099
5466
|
}
|
|
4100
5467
|
|
|
4101
|
-
function
|
|
5468
|
+
function calcArcBounds(xx, yy, start, len) {
|
|
5469
|
+
var i = start | 0,
|
|
5470
|
+
n = isNaN(len) ? xx.length - i : len + i,
|
|
5471
|
+
x, y, xmin, ymin, xmax, ymax;
|
|
5472
|
+
if (n > 0) {
|
|
5473
|
+
xmin = xmax = xx[i];
|
|
5474
|
+
ymin = ymax = yy[i];
|
|
5475
|
+
}
|
|
5476
|
+
for (i++; i<n; i++) {
|
|
5477
|
+
x = xx[i];
|
|
5478
|
+
y = yy[i];
|
|
5479
|
+
if (x < xmin) xmin = x;
|
|
5480
|
+
if (x > xmax) xmax = x;
|
|
5481
|
+
if (y < ymin) ymin = y;
|
|
5482
|
+
if (y > ymax) ymax = y;
|
|
5483
|
+
}
|
|
5484
|
+
return [xmin, ymin, xmax, ymax];
|
|
5485
|
+
}
|
|
5486
|
+
|
|
5487
|
+
function deleteVertex(arcs, i) {
|
|
5488
|
+
var data = arcs.getVertexData();
|
|
5489
|
+
var nn = data.nn;
|
|
5490
|
+
var n = data.xx.length;
|
|
5491
|
+
// avoid re-allocating memory
|
|
5492
|
+
var xx2 = new Float64Array(data.xx.buffer, 0, n-1);
|
|
5493
|
+
var yy2 = new Float64Array(data.yy.buffer, 0, n-1);
|
|
5494
|
+
var count = 0;
|
|
5495
|
+
var found = false;
|
|
5496
|
+
for (var j=0; j<nn.length; j++) {
|
|
5497
|
+
count += nn[j];
|
|
5498
|
+
if (count >= i && !found) { // TODO: confirm this
|
|
5499
|
+
nn[j] = nn[j] - 1;
|
|
5500
|
+
found = true;
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
utils.copyElements(data.xx, 0, xx2, 0, i);
|
|
5504
|
+
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
5505
|
+
utils.copyElements(data.xx, i+1, xx2, i, n-i-1);
|
|
5506
|
+
utils.copyElements(data.yy, i+1, yy2, i, n-i-1);
|
|
5507
|
+
arcs.updateVertexData(nn, xx2, yy2, null);
|
|
5508
|
+
}
|
|
5509
|
+
|
|
5510
|
+
function insertVertex(arcs, i, p) {
|
|
5511
|
+
// TODO: add extra bytes to the buffers, to reduce new memory allocation
|
|
5512
|
+
var data = arcs.getVertexData();
|
|
5513
|
+
var nn = data.nn;
|
|
5514
|
+
var n = data.xx.length;
|
|
5515
|
+
var count = 0;
|
|
5516
|
+
var found = false;
|
|
5517
|
+
var xx2, yy2;
|
|
5518
|
+
// avoid re-allocating memory on each insertion
|
|
5519
|
+
if (data.xx.buffer.byteLength >= data.xx.length * 8 + 8) {
|
|
5520
|
+
xx2 = new Float64Array(data.xx.buffer, 0, n+1);
|
|
5521
|
+
yy2 = new Float64Array(data.yy.buffer, 0, n+1);
|
|
5522
|
+
} else {
|
|
5523
|
+
xx2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
|
|
5524
|
+
yy2 = new Float64Array(new ArrayBuffer((n + 20) * 8), 0, n+1);
|
|
5525
|
+
}
|
|
5526
|
+
for (var j=0; j<nn.length; j++) {
|
|
5527
|
+
count += nn[j];
|
|
5528
|
+
if (count >= i && !found) { // TODO: confirm this
|
|
5529
|
+
nn[j] = nn[j] + 1;
|
|
5530
|
+
found = true;
|
|
5531
|
+
}
|
|
5532
|
+
}
|
|
5533
|
+
utils.copyElements(data.xx, 0, xx2, 0, i);
|
|
5534
|
+
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
5535
|
+
utils.copyElements(data.xx, i, xx2, i+1, n-i);
|
|
5536
|
+
utils.copyElements(data.yy, i, yy2, i+1, n-i);
|
|
5537
|
+
xx2[i] = p[0];
|
|
5538
|
+
yy2[i] = p[1];
|
|
5539
|
+
arcs.updateVertexData(nn, xx2, yy2, null);
|
|
5540
|
+
}
|
|
5541
|
+
|
|
5542
|
+
function getShapeHitTest(displayLayer, ext, interactionMode) {
|
|
4102
5543
|
var geoType = displayLayer.layer.geometry_type;
|
|
4103
5544
|
var test;
|
|
4104
5545
|
if (geoType == 'point' && displayLayer.style.type == 'styled') {
|
|
4105
5546
|
test = getGraduatedCircleTest(getRadiusFunction(displayLayer.style));
|
|
4106
5547
|
} else if (geoType == 'point') {
|
|
4107
5548
|
test = pointTest;
|
|
5549
|
+
} else if (interactionMode == 'vertices') {
|
|
5550
|
+
test = vertexTest;
|
|
4108
5551
|
} else if (geoType == 'polyline') {
|
|
4109
5552
|
test = polylineTest;
|
|
4110
5553
|
} else if (geoType == 'polygon') {
|
|
4111
5554
|
test = polygonTest;
|
|
4112
5555
|
} else {
|
|
4113
|
-
error("Unexpected geometry type:", geoType);
|
|
5556
|
+
error$1("Unexpected geometry type:", geoType);
|
|
4114
5557
|
}
|
|
4115
5558
|
return test;
|
|
4116
5559
|
|
|
@@ -4130,14 +5573,14 @@
|
|
|
4130
5573
|
}
|
|
4131
5574
|
|
|
4132
5575
|
function polygonTest(x, y) {
|
|
4133
|
-
var maxDist = getZoomAdjustedHitBuffer(
|
|
5576
|
+
var maxDist = getZoomAdjustedHitBuffer(10, 1),
|
|
4134
5577
|
cands = findHitCandidates(x, y, maxDist),
|
|
4135
5578
|
hits = [],
|
|
4136
5579
|
cand, hitId;
|
|
4137
5580
|
for (var i=0; i<cands.length; i++) {
|
|
4138
5581
|
cand = cands[i];
|
|
4139
5582
|
if (geom.testPointInPolygon(x, y, cand.shape, displayLayer.arcs)) {
|
|
4140
|
-
hits.push(cand
|
|
5583
|
+
hits.push(cand);
|
|
4141
5584
|
}
|
|
4142
5585
|
}
|
|
4143
5586
|
if (cands.length > 0 && hits.length === 0) {
|
|
@@ -4145,7 +5588,9 @@
|
|
|
4145
5588
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4146
5589
|
hits = pickNearestCandidates(cands, 0, maxDist);
|
|
4147
5590
|
}
|
|
4148
|
-
return
|
|
5591
|
+
return {
|
|
5592
|
+
ids: utils$1.pluck(hits, 'id')
|
|
5593
|
+
};
|
|
4149
5594
|
}
|
|
4150
5595
|
|
|
4151
5596
|
function pickNearestCandidates(sorted, bufDist, maxDist) {
|
|
@@ -4160,24 +5605,43 @@
|
|
|
4160
5605
|
} else if (cand.dist - minDist > bufDist) {
|
|
4161
5606
|
break;
|
|
4162
5607
|
}
|
|
4163
|
-
hits.push(cand
|
|
5608
|
+
hits.push(cand);
|
|
4164
5609
|
}
|
|
4165
5610
|
return hits;
|
|
4166
5611
|
}
|
|
4167
5612
|
|
|
5613
|
+
function vertexTest(x, y) {
|
|
5614
|
+
var maxDist = getZoomAdjustedHitBuffer(20, 2),
|
|
5615
|
+
bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
|
|
5616
|
+
cands = findHitCandidates(x, y, maxDist);
|
|
5617
|
+
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
5618
|
+
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
5619
|
+
var arcs = cands.map(function(cand) { return absArcId(cand.info.arcId); });
|
|
5620
|
+
return {
|
|
5621
|
+
arcs: utils$1.uniq(arcs),
|
|
5622
|
+
ids: utils$1.pluck(cands, 'id')
|
|
5623
|
+
};
|
|
5624
|
+
}
|
|
5625
|
+
|
|
4168
5626
|
function polylineTest(x, y) {
|
|
4169
5627
|
var maxDist = getZoomAdjustedHitBuffer(15, 2),
|
|
4170
5628
|
bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
|
|
4171
5629
|
cands = findHitCandidates(x, y, maxDist);
|
|
4172
5630
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4173
|
-
|
|
5631
|
+
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
5632
|
+
return {
|
|
5633
|
+
ids: utils$1.pluck(cands, 'id')
|
|
5634
|
+
};
|
|
4174
5635
|
}
|
|
4175
5636
|
|
|
4176
5637
|
function sortByDistance(x, y, cands, arcs) {
|
|
5638
|
+
var cand;
|
|
4177
5639
|
for (var i=0; i<cands.length; i++) {
|
|
4178
|
-
|
|
5640
|
+
cand = cands[i];
|
|
5641
|
+
cand.info = geom.getPointToShapeInfo(x, y, cands[i].shape, arcs);
|
|
5642
|
+
cand.dist = cand.info.distance;
|
|
4179
5643
|
}
|
|
4180
|
-
utils.sortOn(cands, 'dist');
|
|
5644
|
+
utils$1.sortOn(cands, 'dist');
|
|
4181
5645
|
}
|
|
4182
5646
|
|
|
4183
5647
|
function pointTest(x, y) {
|
|
@@ -4203,7 +5667,9 @@
|
|
|
4203
5667
|
}
|
|
4204
5668
|
});
|
|
4205
5669
|
// console.log(hitThreshold, bullseye);
|
|
4206
|
-
return
|
|
5670
|
+
return {
|
|
5671
|
+
ids: utils$1.uniq(hits) // multipoint features can register multiple hits
|
|
5672
|
+
};
|
|
4207
5673
|
}
|
|
4208
5674
|
|
|
4209
5675
|
function getRadiusFunction(style) {
|
|
@@ -4257,7 +5723,9 @@
|
|
|
4257
5723
|
hits.push(id);
|
|
4258
5724
|
}
|
|
4259
5725
|
});
|
|
4260
|
-
return
|
|
5726
|
+
return {
|
|
5727
|
+
ids: hits
|
|
5728
|
+
};
|
|
4261
5729
|
};
|
|
4262
5730
|
}
|
|
4263
5731
|
|
|
@@ -4394,25 +5862,23 @@
|
|
|
4394
5862
|
|
|
4395
5863
|
}
|
|
4396
5864
|
|
|
4397
|
-
function getPointerHitTest(mapLayer, ext) {
|
|
5865
|
+
function getPointerHitTest(mapLayer, ext, interactionMode) {
|
|
4398
5866
|
var shapeTest, svgTest, targetLayer;
|
|
4399
5867
|
if (!mapLayer || !internal.layerHasGeometry(mapLayer.layer)) {
|
|
4400
|
-
return
|
|
5868
|
+
return function() {return {ids: []};};
|
|
4401
5869
|
}
|
|
4402
|
-
shapeTest = getShapeHitTest(mapLayer, ext);
|
|
5870
|
+
shapeTest = getShapeHitTest(mapLayer, ext, interactionMode);
|
|
4403
5871
|
svgTest = getSvgHitTest(mapLayer);
|
|
4404
5872
|
|
|
4405
5873
|
// e: pointer event
|
|
4406
5874
|
return function(e) {
|
|
4407
5875
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
4408
|
-
var data = {
|
|
4409
|
-
ids: shapeTest(p[0], p[1]) || []
|
|
4410
|
-
};
|
|
5876
|
+
var data = shapeTest(p[0], p[1]) || {ids:[]};
|
|
4411
5877
|
var svgData = svgTest(e); // null or a data object
|
|
4412
5878
|
if (svgData) { // mouse is over an SVG symbol
|
|
4413
|
-
utils.extend(data, svgData);
|
|
5879
|
+
utils$1.extend(data, svgData);
|
|
4414
5880
|
// placing symbol id in front of any other hits
|
|
4415
|
-
data.ids = utils.uniq([svgData.targetId].concat(data.ids));
|
|
5881
|
+
data.ids = utils$1.uniq([svgData.targetId].concat(data.ids));
|
|
4416
5882
|
}
|
|
4417
5883
|
data.id = data.ids.length > 0 ? data.ids[0] : -1;
|
|
4418
5884
|
return data;
|
|
@@ -4467,22 +5933,25 @@
|
|
|
4467
5933
|
}, !!'capture'); // preempt the layer control's arrow key handler
|
|
4468
5934
|
|
|
4469
5935
|
self.setLayer = function(mapLayer) {
|
|
4470
|
-
hitTest = getPointerHitTest(mapLayer, ext);
|
|
4471
|
-
if (!hitTest) {
|
|
4472
|
-
hitTest = function() {return {ids: []};};
|
|
4473
|
-
}
|
|
4474
5936
|
targetLayer = mapLayer;
|
|
5937
|
+
updateHitTest();
|
|
4475
5938
|
};
|
|
4476
5939
|
|
|
5940
|
+
function updateHitTest() {
|
|
5941
|
+
hitTest = getPointerHitTest(targetLayer, ext, interactionMode);
|
|
5942
|
+
}
|
|
5943
|
+
|
|
4477
5944
|
function turnOn(mode) {
|
|
4478
5945
|
interactionMode = mode;
|
|
4479
5946
|
active = true;
|
|
5947
|
+
updateHitTest();
|
|
4480
5948
|
}
|
|
4481
5949
|
|
|
4482
5950
|
function turnOff() {
|
|
4483
5951
|
if (active) {
|
|
4484
5952
|
updateSelectionState(null); // no hit data, no event
|
|
4485
5953
|
active = false;
|
|
5954
|
+
hitTest = null;
|
|
4486
5955
|
}
|
|
4487
5956
|
}
|
|
4488
5957
|
|
|
@@ -4513,8 +5982,8 @@
|
|
|
4513
5982
|
|
|
4514
5983
|
self.addSelectionIds = function(ids) {
|
|
4515
5984
|
turnOn('selection');
|
|
4516
|
-
selectionIds = utils.uniq(selectionIds.concat(ids));
|
|
4517
|
-
ids = utils.uniq(storedData.ids.concat(ids));
|
|
5985
|
+
selectionIds = utils$1.uniq(selectionIds.concat(ids));
|
|
5986
|
+
ids = utils$1.uniq(storedData.ids.concat(ids));
|
|
4518
5987
|
updateSelectionState({ids: ids});
|
|
4519
5988
|
};
|
|
4520
5989
|
|
|
@@ -4526,6 +5995,32 @@
|
|
|
4526
5995
|
}
|
|
4527
5996
|
};
|
|
4528
5997
|
|
|
5998
|
+
self.setHoverVertex = function(p) {
|
|
5999
|
+
var p2 = storedData.hit_coordinates;
|
|
6000
|
+
if (!active || !p) return;
|
|
6001
|
+
if (p2 && p2[0] == p[0] && p2[1] == p[1]) return;
|
|
6002
|
+
storedData.hit_coordinates = p;
|
|
6003
|
+
triggerHitEvent('change');
|
|
6004
|
+
};
|
|
6005
|
+
|
|
6006
|
+
self.setSelectedVertices = function(points) {
|
|
6007
|
+
if (!active) return;
|
|
6008
|
+
storedData.selected_points = points;
|
|
6009
|
+
triggerHitEvent('change');
|
|
6010
|
+
};
|
|
6011
|
+
|
|
6012
|
+
self.clearSelectedVertices = function() {
|
|
6013
|
+
if (!storedData.selected_points) return;
|
|
6014
|
+
delete storedData.selected_points;
|
|
6015
|
+
triggerHitEvent('change');
|
|
6016
|
+
};
|
|
6017
|
+
|
|
6018
|
+
self.clearVertexOverlay = function() {
|
|
6019
|
+
if (!storedData.hit_coordinates) return;
|
|
6020
|
+
delete storedData.hit_coordinates;
|
|
6021
|
+
triggerHitEvent('change');
|
|
6022
|
+
};
|
|
6023
|
+
|
|
4529
6024
|
self.clearSelection = function() {
|
|
4530
6025
|
updateSelectionState(null);
|
|
4531
6026
|
};
|
|
@@ -4673,7 +6168,7 @@
|
|
|
4673
6168
|
|
|
4674
6169
|
function toggleId(id, ids) {
|
|
4675
6170
|
if (ids.indexOf(id) > -1) {
|
|
4676
|
-
return utils.difference(ids, [id]);
|
|
6171
|
+
return utils$1.difference(ids, [id]);
|
|
4677
6172
|
}
|
|
4678
6173
|
return [id].concat(ids);
|
|
4679
6174
|
}
|
|
@@ -4725,9 +6220,9 @@
|
|
|
4725
6220
|
// d: event data (may be a pointer event object, an ordinary object or null)
|
|
4726
6221
|
function triggerHitEvent(type, d) {
|
|
4727
6222
|
// Merge stored hit data into the event data
|
|
4728
|
-
var eventData = utils.extend({mode: interactionMode}, d || {}, storedData);
|
|
6223
|
+
var eventData = utils$1.extend({mode: interactionMode}, d || {}, storedData);
|
|
4729
6224
|
if (transientIds.length) {
|
|
4730
|
-
eventData.ids = utils.uniq(transientIds.concat(eventData.ids || []));
|
|
6225
|
+
eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
|
|
4731
6226
|
}
|
|
4732
6227
|
self.dispatchEvent(type, eventData);
|
|
4733
6228
|
}
|
|
@@ -4861,7 +6356,7 @@
|
|
|
4861
6356
|
}
|
|
4862
6357
|
}
|
|
4863
6358
|
|
|
4864
|
-
utils.inherit(Timer, EventDispatcher);
|
|
6359
|
+
utils$1.inherit(Timer, EventDispatcher);
|
|
4865
6360
|
|
|
4866
6361
|
function Tween(ease) {
|
|
4867
6362
|
var self = this,
|
|
@@ -4883,7 +6378,7 @@
|
|
|
4883
6378
|
}
|
|
4884
6379
|
}
|
|
4885
6380
|
|
|
4886
|
-
utils.inherit(Tween, EventDispatcher);
|
|
6381
|
+
utils$1.inherit(Tween, EventDispatcher);
|
|
4887
6382
|
|
|
4888
6383
|
Tween.sineInOut = function(n) {
|
|
4889
6384
|
return 0.5 - Math.cos(n * Math.PI) / 2;
|
|
@@ -4951,7 +6446,7 @@
|
|
|
4951
6446
|
update();
|
|
4952
6447
|
}
|
|
4953
6448
|
|
|
4954
|
-
utils.inherit(ElementPosition, EventDispatcher);
|
|
6449
|
+
utils$1.inherit(ElementPosition, EventDispatcher);
|
|
4955
6450
|
|
|
4956
6451
|
function MouseWheelDirection() {
|
|
4957
6452
|
var prevTime = 0;
|
|
@@ -5049,13 +6544,13 @@
|
|
|
5049
6544
|
// Decelerate towards the end of the sustain interval (for smoother zooming)
|
|
5050
6545
|
multiplier *= Tween.quadraticOut(1 - fadeFactor);
|
|
5051
6546
|
}
|
|
5052
|
-
obj = utils.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
6547
|
+
obj = utils$1.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
|
|
5053
6548
|
self.dispatchEvent('mousewheel', obj);
|
|
5054
6549
|
}
|
|
5055
6550
|
}
|
|
5056
6551
|
}
|
|
5057
6552
|
|
|
5058
|
-
utils.inherit(MouseWheel, EventDispatcher);
|
|
6553
|
+
utils$1.inherit(MouseWheel, EventDispatcher);
|
|
5059
6554
|
|
|
5060
6555
|
|
|
5061
6556
|
function MouseArea(element, pos) {
|
|
@@ -5109,7 +6604,7 @@
|
|
|
5109
6604
|
};
|
|
5110
6605
|
|
|
5111
6606
|
this.mouseData = function() {
|
|
5112
|
-
return utils.extend({}, _prevEvt);
|
|
6607
|
+
return utils$1.extend({}, _prevEvt);
|
|
5113
6608
|
};
|
|
5114
6609
|
|
|
5115
6610
|
function onAreaDown(e) {
|
|
@@ -5168,7 +6663,7 @@
|
|
|
5168
6663
|
dragX: evt.pageX - _downEvt.pageX,
|
|
5169
6664
|
dragY: evt.pageY - _downEvt.pageY
|
|
5170
6665
|
};
|
|
5171
|
-
_self.dispatchEvent('drag', utils.extend(obj, evt));
|
|
6666
|
+
_self.dispatchEvent('drag', utils$1.extend(obj, evt));
|
|
5172
6667
|
} else {
|
|
5173
6668
|
_self.dispatchEvent('hover', evt);
|
|
5174
6669
|
}
|
|
@@ -5200,7 +6695,7 @@
|
|
|
5200
6695
|
}
|
|
5201
6696
|
}
|
|
5202
6697
|
|
|
5203
|
-
utils.inherit(MouseArea, EventDispatcher);
|
|
6698
|
+
utils$1.inherit(MouseArea, EventDispatcher);
|
|
5204
6699
|
|
|
5205
6700
|
function initVariableClick(node, cb) {
|
|
5206
6701
|
var downEvent = null;
|
|
@@ -5347,7 +6842,7 @@
|
|
|
5347
6842
|
maxScale = 4,
|
|
5348
6843
|
minTime = 100,
|
|
5349
6844
|
maxTime = 800,
|
|
5350
|
-
time = utils.clamp(clickTime || 200, minTime, maxTime),
|
|
6845
|
+
time = utils$1.clamp(clickTime || 200, minTime, maxTime),
|
|
5351
6846
|
k = (time - minTime) / (maxTime - minTime),
|
|
5352
6847
|
scale = minScale + k * (maxScale - minScale);
|
|
5353
6848
|
return 1 + scale * zoomScaleMultiplier;
|
|
@@ -5574,7 +7069,7 @@
|
|
|
5574
7069
|
rows = 0;
|
|
5575
7070
|
// self.hide(); // clean up if panel is already open
|
|
5576
7071
|
el.empty(); // clean up if panel is already open
|
|
5577
|
-
utils.forEachProperty(rec, function(v, k) {
|
|
7072
|
+
utils$1.forEachProperty(rec, function(v, k) {
|
|
5578
7073
|
var type;
|
|
5579
7074
|
// missing GeoJSON fields are set to undefined on import; skip these
|
|
5580
7075
|
if (v !== undefined) {
|
|
@@ -5602,7 +7097,7 @@
|
|
|
5602
7097
|
// Some individual features can have undefined values for some or all of
|
|
5603
7098
|
// their data properties (properties are set to undefined when an input JSON file
|
|
5604
7099
|
// has inconsistent fields, or after force-merging layers with inconsistent fields).
|
|
5605
|
-
el.html(utils.format('<div class="note">This %s is missing attribute data.</div>',
|
|
7100
|
+
el.html(utils$1.format('<div class="note">This %s is missing attribute data.</div>',
|
|
5606
7101
|
table && table.getFields().length > 0 ? 'feature': 'layer'));
|
|
5607
7102
|
}
|
|
5608
7103
|
}
|
|
@@ -5613,7 +7108,7 @@
|
|
|
5613
7108
|
var str = formatInspectorValue(val, type);
|
|
5614
7109
|
var cell = El('tr')
|
|
5615
7110
|
.appendTo(table)
|
|
5616
|
-
.html(utils.format(rowHtml, key, utils.htmlEscape(str)))
|
|
7111
|
+
.html(utils$1.format(rowHtml, key, utils$1.htmlEscape(str)))
|
|
5617
7112
|
.findChild('.value');
|
|
5618
7113
|
setFieldClass(cell, val, type);
|
|
5619
7114
|
if (editable) {
|
|
@@ -5622,7 +7117,7 @@
|
|
|
5622
7117
|
}
|
|
5623
7118
|
|
|
5624
7119
|
function setFieldClass(el, val, type) {
|
|
5625
|
-
var isNum = type ? type == 'number' : utils.isNumber(val);
|
|
7120
|
+
var isNum = type ? type == 'number' : utils$1.isNumber(val);
|
|
5626
7121
|
var isNully = val === undefined || val === null || val !== val;
|
|
5627
7122
|
var isEmpty = val === '';
|
|
5628
7123
|
el.classed('num-field', isNum);
|
|
@@ -5662,7 +7157,7 @@
|
|
|
5662
7157
|
function formatInspectorValue(val, type) {
|
|
5663
7158
|
var str;
|
|
5664
7159
|
if (type == 'date') {
|
|
5665
|
-
str = utils.formatDateISO(val);
|
|
7160
|
+
str = utils$1.formatDateISO(val);
|
|
5666
7161
|
} else if (type == 'object') {
|
|
5667
7162
|
str = val ? JSON.stringify(val) : "";
|
|
5668
7163
|
} else {
|
|
@@ -5861,55 +7356,113 @@
|
|
|
5861
7356
|
// handle either numeric strings or numbers in fields
|
|
5862
7357
|
function applyDelta(rec, key, delta) {
|
|
5863
7358
|
var currVal = rec[key];
|
|
5864
|
-
var isString = utils.isString(currVal);
|
|
7359
|
+
var isString = utils$1.isString(currVal);
|
|
5865
7360
|
var newVal = (+currVal + delta) || 0;
|
|
5866
7361
|
rec[key] = isString ? String(newVal) : newVal;
|
|
5867
7362
|
}
|
|
5868
7363
|
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
var
|
|
5873
|
-
return ext.translateCoords(coords[0], coords[1]);
|
|
5874
|
-
}
|
|
7364
|
+
function initLabelDragging(gui, ext, hit) {
|
|
7365
|
+
var downEvt;
|
|
7366
|
+
var activeId;
|
|
7367
|
+
var activeRecord;
|
|
5875
7368
|
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
if (!coords || coords.length != 1) {
|
|
5879
|
-
return null;
|
|
7369
|
+
function active(e) {
|
|
7370
|
+
return e.id > -1 && gui.interaction.getMode() == 'labels';
|
|
5880
7371
|
}
|
|
5881
|
-
return coords[0];
|
|
5882
|
-
}
|
|
5883
7372
|
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
7373
|
+
hit.on('dragstart', function(e) {
|
|
7374
|
+
if (!active(e)) return;
|
|
7375
|
+
var textNode = getTextTarget3(e);
|
|
7376
|
+
var table = hit.getTargetDataTable();
|
|
7377
|
+
if (!textNode || !table) return false;
|
|
7378
|
+
activeId = e.id;
|
|
7379
|
+
activeRecord = getLabelRecordById(activeId);
|
|
7380
|
+
downEvt = e;
|
|
7381
|
+
gui.dispatchEvent('label_dragstart', {FID: activeId});
|
|
7382
|
+
});
|
|
5889
7383
|
|
|
7384
|
+
hit.on('drag', function(e) {
|
|
7385
|
+
if (!active(e)) return;
|
|
7386
|
+
if (e.id != activeId) {
|
|
7387
|
+
error$1("Mismatched hit ids:", e.id, activeId);
|
|
7388
|
+
}
|
|
7389
|
+
var scale = ext.getSymbolScale() || 1;
|
|
7390
|
+
var textNode;
|
|
7391
|
+
applyDelta(activeRecord, 'dx', e.dx / scale);
|
|
7392
|
+
applyDelta(activeRecord, 'dy', e.dy / scale);
|
|
7393
|
+
textNode = getTextTarget3(e);
|
|
7394
|
+
if (!isMultilineLabel(textNode)) {
|
|
7395
|
+
// update anchor position of single-line labels based on label position
|
|
7396
|
+
// relative to anchor point, for better placement when eventual display font is
|
|
7397
|
+
// different from mapshaper's font.
|
|
7398
|
+
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
|
|
7399
|
+
}
|
|
7400
|
+
// updateSymbol(targetTextNode, activeRecord);
|
|
7401
|
+
updateSymbol2(textNode, activeRecord, activeId);
|
|
7402
|
+
});
|
|
5890
7403
|
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
7404
|
+
hit.on('dragend', function(e) {
|
|
7405
|
+
if (!active(e)) return;
|
|
7406
|
+
gui.dispatchEvent('label_dragend', {FID: e.id});
|
|
7407
|
+
activeId = -1;
|
|
7408
|
+
activeRecord = null;
|
|
7409
|
+
downEvt = null;
|
|
7410
|
+
});
|
|
5898
7411
|
|
|
5899
|
-
|
|
7412
|
+
function getDisplayCoordsById(id, layer, ext) {
|
|
7413
|
+
var coords = getPointCoordsById(id, layer);
|
|
7414
|
+
return ext.translateCoords(coords[0], coords[1]);
|
|
7415
|
+
}
|
|
5900
7416
|
|
|
5901
|
-
|
|
7417
|
+
function getPointCoordsById(id, layer) {
|
|
7418
|
+
var coords = layer && layer.geometry_type == 'point' && layer.shapes[id];
|
|
7419
|
+
if (!coords || coords.length != 1) {
|
|
7420
|
+
return null;
|
|
7421
|
+
}
|
|
7422
|
+
return coords[0];
|
|
7423
|
+
}
|
|
7424
|
+
|
|
7425
|
+
function getTextTarget3(e) {
|
|
7426
|
+
if (e.id > -1 === false || !e.container) return null;
|
|
7427
|
+
return getSymbolNodeById(e.id, e.container);
|
|
7428
|
+
}
|
|
5902
7429
|
|
|
5903
|
-
function
|
|
5904
|
-
|
|
7430
|
+
function getSymbolNodeById(id, parent) {
|
|
7431
|
+
// TODO: optimize selector
|
|
7432
|
+
var sel = '[data-id="' + id + '"]';
|
|
7433
|
+
return parent.querySelector(sel);
|
|
5905
7434
|
}
|
|
5906
7435
|
|
|
5907
|
-
function
|
|
5908
|
-
|
|
7436
|
+
function getTextTarget2(e) {
|
|
7437
|
+
var el = e && e.targetSymbol || null;
|
|
7438
|
+
if (el && el.tagName == 'tspan') {
|
|
7439
|
+
el = el.parentNode;
|
|
7440
|
+
}
|
|
7441
|
+
return el && el.tagName == 'text' ? el : null;
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
function getTextTarget(e) {
|
|
7445
|
+
var el = e.target;
|
|
7446
|
+
if (el.tagName == 'tspan') {
|
|
7447
|
+
el = el.parentNode;
|
|
7448
|
+
}
|
|
7449
|
+
return el.tagName == 'text' ? el : null;
|
|
5909
7450
|
}
|
|
5910
7451
|
|
|
5911
|
-
function
|
|
5912
|
-
|
|
7452
|
+
function getLabelRecordById(id) {
|
|
7453
|
+
var table = hit.getTargetDataTable();
|
|
7454
|
+
if (id >= 0 === false || !table) return null;
|
|
7455
|
+
// add dx and dy properties, if not available
|
|
7456
|
+
if (!table.fieldExists('dx')) {
|
|
7457
|
+
table.addField('dx', 0);
|
|
7458
|
+
}
|
|
7459
|
+
if (!table.fieldExists('dy')) {
|
|
7460
|
+
table.addField('dy', 0);
|
|
7461
|
+
}
|
|
7462
|
+
if (!table.fieldExists('text-anchor')) {
|
|
7463
|
+
table.addField('text-anchor', '');
|
|
7464
|
+
}
|
|
7465
|
+
return table.getRecordAt(id);
|
|
5913
7466
|
}
|
|
5914
7467
|
|
|
5915
7468
|
// update symbol by setting attributes
|
|
@@ -5936,249 +7489,260 @@
|
|
|
5936
7489
|
gui.dispatchEvent('popup-needs-refresh');
|
|
5937
7490
|
return node2;
|
|
5938
7491
|
}
|
|
7492
|
+
}
|
|
5939
7493
|
|
|
5940
|
-
|
|
5941
|
-
var downEvt;
|
|
5942
|
-
var eventPriority = 1;
|
|
7494
|
+
function initPointDragging(gui, ext, hit) {
|
|
5943
7495
|
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
// });
|
|
7496
|
+
function active(e) {
|
|
7497
|
+
return e.id > -1 && gui.interaction.getMode() == 'location';
|
|
7498
|
+
}
|
|
5948
7499
|
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
gui.undo.clear(); // TODO: put this elsewhere?
|
|
5954
|
-
});
|
|
7500
|
+
hit.on('dragstart', function(e) {
|
|
7501
|
+
if (!active(e)) return;
|
|
7502
|
+
gui.dispatchEvent('symbol_dragstart', {FID: e.id});
|
|
7503
|
+
});
|
|
5955
7504
|
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
triggerGlobalEvent('label_dragstart', e);
|
|
5968
|
-
startDragging();
|
|
5969
|
-
} else if (locationEditingEnabled()) {
|
|
5970
|
-
triggerGlobalEvent('symbol_dragstart', e);
|
|
5971
|
-
startDragging();
|
|
5972
|
-
} else if (vertexEditingEnabled()) {
|
|
5973
|
-
onVertexDragStart(e);
|
|
5974
|
-
triggerGlobalEvent('vertex_dragstart', e);
|
|
5975
|
-
startDragging();
|
|
5976
|
-
}
|
|
5977
|
-
});
|
|
7505
|
+
hit.on('drag', function(e) {
|
|
7506
|
+
if (!active(e)) return;
|
|
7507
|
+
var lyr = hit.getHitTarget().layer;
|
|
7508
|
+
var p = getPointCoordsById(e.id, lyr);
|
|
7509
|
+
if (!p) return;
|
|
7510
|
+
var diff = translateDeltaDisplayCoords(e.dx, e.dy, ext);
|
|
7511
|
+
p[0] += diff[0];
|
|
7512
|
+
p[1] += diff[1];
|
|
7513
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
7514
|
+
gui.dispatchEvent('symbol_drag', {FID: e.id});
|
|
7515
|
+
});
|
|
5978
7516
|
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
onLocationDrag(e);
|
|
5984
|
-
} else if (vertexEditingEnabled()) {
|
|
5985
|
-
onVertexDrag(e);
|
|
5986
|
-
}
|
|
5987
|
-
});
|
|
7517
|
+
hit.on('dragend', function(e) {
|
|
7518
|
+
if (!active(e)) return;
|
|
7519
|
+
gui.dispatchEvent('symbol_dragend', {FID: e.id});
|
|
7520
|
+
});
|
|
5988
7521
|
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
triggerGlobalEvent('label_dragend', e);
|
|
5995
|
-
stopDragging();
|
|
5996
|
-
} else if (vertexEditingEnabled()) {
|
|
5997
|
-
// kludge to get dataset to recalculate internal bounding boxes
|
|
5998
|
-
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
5999
|
-
triggerGlobalEvent('vertex_dragend', e);
|
|
6000
|
-
stopDragging();
|
|
6001
|
-
}
|
|
6002
|
-
});
|
|
7522
|
+
function translateDeltaDisplayCoords(dx, dy, ext) {
|
|
7523
|
+
var a = ext.translatePixelCoords(0, 0);
|
|
7524
|
+
var b = ext.translatePixelCoords(dx, dy);
|
|
7525
|
+
return [b[0] - a[0], b[1] - a[1]];
|
|
7526
|
+
}
|
|
6003
7527
|
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
7528
|
+
function getPointCoordsById(id, layer) {
|
|
7529
|
+
var coords = layer && layer.geometry_type == 'point' && layer.shapes[id];
|
|
7530
|
+
if (!coords || coords.length != 1) {
|
|
7531
|
+
return null;
|
|
7532
|
+
}
|
|
7533
|
+
return coords[0];
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
6010
7536
|
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
if (vertexEditingEnabled() && !dragging) {
|
|
6014
|
-
onVertexHover(e);
|
|
6015
|
-
}
|
|
6016
|
-
}, null, 100);
|
|
7537
|
+
var HOVER_THRESHOLD = 8;
|
|
7538
|
+
var MIDPOINT_THRESHOLD = 12;
|
|
6017
7539
|
|
|
6018
|
-
function onVertexHover(e) {
|
|
6019
|
-
// hovering in vertex edit mode: find vertex insertion point
|
|
6020
|
-
var target = hit.getHitTarget();
|
|
6021
|
-
var shp = target.layer.shapes[e.id];
|
|
6022
|
-
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6023
|
-
var o = internal.findInsertionPoint(p, shp, target.arcs, ext.getPixelSize());
|
|
6024
|
-
}
|
|
6025
7540
|
|
|
7541
|
+
function initVertexDragging(gui, ext, hit) {
|
|
7542
|
+
var activeShapeId = -1;
|
|
7543
|
+
var draggedVertexIds = null;
|
|
7544
|
+
var selectedVertexIds = null;
|
|
7545
|
+
var activeMidpoint; // {point, segment}
|
|
6026
7546
|
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
vertexIds: activeVertexIds
|
|
6031
|
-
};
|
|
6032
|
-
}
|
|
7547
|
+
function active(e) {
|
|
7548
|
+
return e.id > -1 && gui.interaction.getMode() == 'vertices';
|
|
7549
|
+
}
|
|
6033
7550
|
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
p[1] += diff[1];
|
|
6041
|
-
triggerRedraw();
|
|
6042
|
-
triggerGlobalEvent('symbol_drag', e);
|
|
6043
|
-
}
|
|
7551
|
+
function fire(type) {
|
|
7552
|
+
gui.dispatchEvent(type, {
|
|
7553
|
+
FID: activeShapeId,
|
|
7554
|
+
vertex_ids: draggedVertexIds
|
|
7555
|
+
});
|
|
7556
|
+
}
|
|
6044
7557
|
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
activeVertexIds = internal.findNearestVertices(p, shp, target.arcs);
|
|
6050
|
-
activeId = e.id;
|
|
6051
|
-
}
|
|
7558
|
+
function setHoverVertex(id) {
|
|
7559
|
+
var target = hit.getHitTarget();
|
|
7560
|
+
hit.setHoverVertex(target.arcs.getVertex2(id));
|
|
7561
|
+
}
|
|
6052
7562
|
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
if (gui.keyboard.shiftIsPressed()) {
|
|
6058
|
-
internal.snapPointToArcEndpoint(p, activeVertexIds, target.arcs);
|
|
6059
|
-
}
|
|
6060
|
-
snapVerticesToPoint(activeVertexIds, p, target.arcs);
|
|
6061
|
-
triggerRedraw();
|
|
6062
|
-
}
|
|
7563
|
+
function clearHoverVertex() {
|
|
7564
|
+
hit.clearVertexOverlay();
|
|
7565
|
+
// gui.state.vertex_overlay = null;
|
|
7566
|
+
}
|
|
6063
7567
|
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
7568
|
+
function findDraggableVertices(e) {
|
|
7569
|
+
var target = hit.getHitTarget();
|
|
7570
|
+
var shp = target.layer.shapes[e.id];
|
|
7571
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
7572
|
+
var nearestIds = internal.findNearestVertices(p, shp, target.arcs);
|
|
7573
|
+
var p2 = target.arcs.getVertex2(nearestIds[0]);
|
|
7574
|
+
var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
|
|
7575
|
+
var pixelDist = dist / ext.getPixelSize();
|
|
7576
|
+
if (pixelDist > HOVER_THRESHOLD) {
|
|
7577
|
+
draggedVertexIds = null;
|
|
7578
|
+
return null;
|
|
6072
7579
|
}
|
|
7580
|
+
return nearestIds;
|
|
7581
|
+
}
|
|
6073
7582
|
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
7583
|
+
function insertMidpoint(v) {
|
|
7584
|
+
var target = hit.getHitTarget();
|
|
7585
|
+
internal.insertVertex(target.arcs, v.i, v.point);
|
|
7586
|
+
}
|
|
6077
7587
|
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
gui.dispatchEvent(type, o);
|
|
7588
|
+
function toggleVertexSelection(ids) {
|
|
7589
|
+
if (!ids || ids.length === 0) return;
|
|
7590
|
+
if (!selectedVertexIds) {
|
|
7591
|
+
selectedVertexIds = ids;
|
|
7592
|
+
} else {
|
|
7593
|
+
var intersection = utils$1.intersection(selectedVertexIds, ids);
|
|
7594
|
+
var union = selectedVertexIds.concat(ids);
|
|
7595
|
+
selectedVertexIds = utils$1.difference(union, intersection);
|
|
6087
7596
|
}
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
7597
|
+
// get coordinates
|
|
7598
|
+
var target = hit.getHitTarget();
|
|
7599
|
+
var points = selectedVertexIds.map(function(id) { return target.arcs.getVertex2(id); });
|
|
7600
|
+
hit.setSelectedVertices(points);
|
|
7601
|
+
}
|
|
7602
|
+
|
|
7603
|
+
hit.on('dragstart', function(e) {
|
|
7604
|
+
if (!active(e)) return;
|
|
7605
|
+
if (activeMidpoint) {
|
|
7606
|
+
insertMidpoint(activeMidpoint);
|
|
7607
|
+
draggedVertexIds = [activeMidpoint.i];
|
|
7608
|
+
// TODO: combine vertex insertion undo/redo actions with
|
|
7609
|
+
// vertex_dragend undo/redo actions
|
|
7610
|
+
gui.dispatchEvent('vertex_insert', {
|
|
7611
|
+
FID: activeShapeId,
|
|
7612
|
+
vertex_id: activeMidpoint.i,
|
|
7613
|
+
coordinates: activeMidpoint.point
|
|
7614
|
+
});
|
|
7615
|
+
activeMidpoint = null;
|
|
7616
|
+
} else {
|
|
7617
|
+
draggedVertexIds = findDraggableVertices(e);
|
|
6103
7618
|
}
|
|
7619
|
+
if (!draggedVertexIds) return;
|
|
7620
|
+
setHoverVertex(draggedVertexIds[0]);
|
|
7621
|
+
activeShapeId = e.id;
|
|
7622
|
+
fire('vertex_dragstart');
|
|
7623
|
+
});
|
|
6104
7624
|
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
downEvt = e;
|
|
6112
|
-
return true;
|
|
7625
|
+
hit.on('drag', function(e) {
|
|
7626
|
+
if (!active(e) || !draggedVertexIds) return;
|
|
7627
|
+
var target = hit.getHitTarget();
|
|
7628
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
7629
|
+
if (gui.keyboard.shiftIsPressed()) {
|
|
7630
|
+
internal.snapPointToArcEndpoint(p, draggedVertexIds, target.arcs);
|
|
6113
7631
|
}
|
|
7632
|
+
internal.snapVerticesToPoint(draggedVertexIds, p, target.arcs);
|
|
7633
|
+
setHoverVertex(draggedVertexIds[0]);
|
|
7634
|
+
// redrawing the whole map updates the data layer as well as the overlay layer
|
|
7635
|
+
// gui.dispatchEvent('map-needs-refresh');
|
|
7636
|
+
});
|
|
6114
7637
|
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
error("Mismatched hit ids:", e.id, activeId);
|
|
6121
|
-
}
|
|
6122
|
-
applyDelta(activeRecord, 'dx', e.dx / scale);
|
|
6123
|
-
applyDelta(activeRecord, 'dy', e.dy / scale);
|
|
6124
|
-
textNode = getTextTarget3(e);
|
|
6125
|
-
if (!isMultilineLabel(textNode)) {
|
|
6126
|
-
// update anchor position of single-line labels based on label position
|
|
6127
|
-
// relative to anchor point, for better placement when eventual display font is
|
|
6128
|
-
// different from mapshaper's font.
|
|
6129
|
-
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
|
|
6130
|
-
}
|
|
6131
|
-
// updateSymbol(targetTextNode, activeRecord);
|
|
6132
|
-
updateSymbol2(textNode, activeRecord, activeId);
|
|
6133
|
-
}
|
|
7638
|
+
hit.on('dragend', function(e) {
|
|
7639
|
+
if (!active(e) || !draggedVertexIds) return;
|
|
7640
|
+
// kludge to get dataset to recalculate internal bounding boxes
|
|
7641
|
+
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
7642
|
+
clearHoverVertex();
|
|
6134
7643
|
|
|
6135
|
-
function getSymbolNodeById(id, parent) {
|
|
6136
|
-
// TODO: optimize selector
|
|
6137
|
-
var sel = '[data-id="' + id + '"]';
|
|
6138
|
-
return parent.querySelector(sel);
|
|
6139
|
-
}
|
|
6140
7644
|
|
|
6141
|
-
function getTextTarget3(e) {
|
|
6142
|
-
if (e.id > -1 === false || !e.container) return null;
|
|
6143
|
-
return getSymbolNodeById(e.id, e.container);
|
|
6144
|
-
}
|
|
6145
7645
|
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
}
|
|
7646
|
+
fire('vertex_dragend');
|
|
7647
|
+
draggedVertexIds = null;
|
|
7648
|
+
activeShapeId = -1;
|
|
7649
|
+
// redraw data layer
|
|
7650
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
7651
|
+
});
|
|
6153
7652
|
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
7653
|
+
// select clicked vertices
|
|
7654
|
+
hit.on('click', function(e) {
|
|
7655
|
+
if (!active(e)) return;
|
|
7656
|
+
var vertices = findDraggableVertices(e); // same selection criteria as for dragging
|
|
7657
|
+
|
|
7658
|
+
// CASE: no draggable vertices
|
|
7659
|
+
// if selected vertices, deselect, else no-op
|
|
7660
|
+
// CASE: draggable vertices
|
|
7661
|
+
// if vertex is arc endpoint, ignore
|
|
7662
|
+
// if vertex is selected, deselect
|
|
7663
|
+
// if vertex is not selected, select
|
|
7664
|
+
|
|
7665
|
+
// if (vertices) {
|
|
7666
|
+
// toggleVertexSelection(vertices);
|
|
7667
|
+
// } else if (selectedVertexIds) {
|
|
7668
|
+
// toggleVertexSelection(selectedVertexIds);
|
|
7669
|
+
// }
|
|
7670
|
+
|
|
7671
|
+
});
|
|
7672
|
+
|
|
7673
|
+
// highlight hit vertex in path edit mode
|
|
7674
|
+
hit.on('hover', function(e) {
|
|
7675
|
+
activeMidpoint = null;
|
|
7676
|
+
if (!active(e) || draggedVertexIds) return; // no hover effect while dragging
|
|
7677
|
+
var vertexIds = findDraggableVertices(e);
|
|
7678
|
+
if (vertexIds) {
|
|
7679
|
+
setHoverVertex(vertexIds[0]);
|
|
7680
|
+
return;
|
|
6160
7681
|
}
|
|
6161
|
-
|
|
7682
|
+
var target = hit.getHitTarget();
|
|
7683
|
+
// vertex insertion doesn't work yet with simplification applied
|
|
7684
|
+
if (!target.arcs.isFlat()) return;
|
|
7685
|
+
var shp = target.layer.shapes[e.id];
|
|
7686
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
7687
|
+
var midpoint = findNearestMidpoint(p, shp, target.arcs);
|
|
7688
|
+
if (midpoint && midpoint.distance / ext.getPixelSize() < MIDPOINT_THRESHOLD) {
|
|
7689
|
+
hit.setHoverVertex(midpoint.point);
|
|
7690
|
+
activeMidpoint = midpoint;
|
|
7691
|
+
} else {
|
|
7692
|
+
clearHoverVertex();
|
|
7693
|
+
}
|
|
7694
|
+
}, null, 100);
|
|
7695
|
+
}
|
|
6162
7696
|
|
|
6163
|
-
function startDragging() {
|
|
6164
|
-
dragging = true;
|
|
6165
|
-
}
|
|
6166
7697
|
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
7698
|
+
// Given a location @p (e.g. corresponding to the mouse pointer location),
|
|
7699
|
+
// find the midpoint of two vertices on @shp suitable for inserting a new vertex,
|
|
7700
|
+
// but only if:
|
|
7701
|
+
// 1. point @p is closer to the midpoint than either adjacent vertex
|
|
7702
|
+
// 2. the segment containing @p is longer than a minimum distance in pixels.
|
|
7703
|
+
//
|
|
7704
|
+
function findNearestMidpoint(p, shp, arcs) {
|
|
7705
|
+
// var v1 = internal.findNearestVertex(p[0], p[1], shp, arcs);
|
|
7706
|
+
// var v0 = internal.findAdjacentVertex(v1, shp, arcs, -1);
|
|
7707
|
+
// var v2 = internal.findAdjacentVertex(v1, shp, arcs, 1);
|
|
7708
|
+
var minDist = Infinity, v;
|
|
7709
|
+
internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
|
|
7710
|
+
var x1 = xx[i],
|
|
7711
|
+
y1 = yy[i],
|
|
7712
|
+
x2 = xx[j],
|
|
7713
|
+
y2 = yy[j],
|
|
7714
|
+
cx = (x1 + x2) / 2,
|
|
7715
|
+
cy = (y1 + y2) / 2,
|
|
7716
|
+
dist = geom.distance2D(cx, cy, p[0], p[1]);
|
|
7717
|
+
if (dist < minDist) {
|
|
7718
|
+
minDist = dist;
|
|
7719
|
+
v = {
|
|
7720
|
+
i: (i < j ? i : j) + 1, // insertion point
|
|
7721
|
+
segment: [i, j],
|
|
7722
|
+
point: [cx, cy],
|
|
7723
|
+
distance: dist
|
|
7724
|
+
};
|
|
7725
|
+
}
|
|
7726
|
+
});
|
|
7727
|
+
return v || null;
|
|
7728
|
+
}
|
|
6173
7729
|
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
7730
|
+
function initInteractiveEditing(gui, ext, hit) {
|
|
7731
|
+
initLabelDragging(gui, ext, hit);
|
|
7732
|
+
initPointDragging(gui, ext, hit);
|
|
7733
|
+
initVertexDragging(gui, ext, hit);
|
|
7734
|
+
|
|
7735
|
+
gui.on('interaction_mode_change', function(e) {
|
|
7736
|
+
gui.undo.clear(); // TODO: put this elsewhere?
|
|
7737
|
+
});
|
|
6181
7738
|
|
|
7739
|
+
// function isClickEvent(up, down) {
|
|
7740
|
+
// var elapsed = Math.abs(down.timeStamp - up.timeStamp);
|
|
7741
|
+
// var dx = up.screenX - down.screenX;
|
|
7742
|
+
// var dy = up.screenY - down.screenY;
|
|
7743
|
+
// var dist = Math.sqrt(dx * dx + dy * dy);
|
|
7744
|
+
// return dist <= 4 && elapsed < 300;
|
|
7745
|
+
// }
|
|
6182
7746
|
}
|
|
6183
7747
|
|
|
6184
7748
|
var darkStroke = "#334",
|
|
@@ -6203,7 +7767,7 @@
|
|
|
6203
7767
|
},
|
|
6204
7768
|
referenceStyle = { // outline style for reference layers
|
|
6205
7769
|
type: 'outline',
|
|
6206
|
-
strokeColors: [null, '#
|
|
7770
|
+
strokeColors: [null, '#78c110'], // upped saturation from #86c927
|
|
6207
7771
|
strokeWidth: 0.85,
|
|
6208
7772
|
dotColor: "#73ba20",
|
|
6209
7773
|
dotSize: 1
|
|
@@ -6284,7 +7848,7 @@
|
|
|
6284
7848
|
}
|
|
6285
7849
|
|
|
6286
7850
|
function getDefaultStyle(lyr, baseStyle) {
|
|
6287
|
-
var style = utils.extend({}, baseStyle);
|
|
7851
|
+
var style = utils$1.extend({}, baseStyle);
|
|
6288
7852
|
// reduce the dot size of large point layers
|
|
6289
7853
|
if (lyr.geometry_type == 'point' && style.dotSize > 0) {
|
|
6290
7854
|
style.dotSize *= getDotScale$1(lyr);
|
|
@@ -6349,8 +7913,15 @@
|
|
|
6349
7913
|
var geomType = lyr.geometry_type;
|
|
6350
7914
|
var topId = o.id; // pinned id (if pinned) or hover id
|
|
6351
7915
|
var topIdx = -1;
|
|
6352
|
-
var styler = function(
|
|
6353
|
-
utils.extend(
|
|
7916
|
+
var styler = function(style, i) {
|
|
7917
|
+
utils$1.extend(style, i === topIdx ? topStyle: baseStyle);
|
|
7918
|
+
// kludge to show vertices when editing path shapes
|
|
7919
|
+
if (o.mode == 'vertices') {
|
|
7920
|
+
style.vertices = true;
|
|
7921
|
+
style.vertex_overlay = o.hit_coordinates || null;
|
|
7922
|
+
style.selected_points = o.selected_points || null;
|
|
7923
|
+
style.fillColor = null;
|
|
7924
|
+
}
|
|
6354
7925
|
};
|
|
6355
7926
|
var baseStyle = getDefaultStyle(lyr, selectionStyles[geomType]);
|
|
6356
7927
|
var topStyle;
|
|
@@ -6463,7 +8034,7 @@
|
|
|
6463
8034
|
if (lyr.geometry_type == 'point') {
|
|
6464
8035
|
return fields.indexOf('r') > -1; // require 'r' field for point symbols
|
|
6465
8036
|
}
|
|
6466
|
-
return utils.difference(fields, ['opacity', 'class']).length > 0;
|
|
8037
|
+
return utils$1.difference(fields, ['opacity', 'class']).length > 0;
|
|
6467
8038
|
}
|
|
6468
8039
|
|
|
6469
8040
|
|
|
@@ -6620,7 +8191,7 @@
|
|
|
6620
8191
|
}
|
|
6621
8192
|
|
|
6622
8193
|
function maxAbs() {
|
|
6623
|
-
return Math.max.apply(null, utils.toArray(arguments).map(Math.abs));
|
|
8194
|
+
return Math.max.apply(null, utils$1.toArray(arguments).map(Math.abs));
|
|
6624
8195
|
}
|
|
6625
8196
|
|
|
6626
8197
|
function limitScale(scale) {
|
|
@@ -6674,7 +8245,7 @@
|
|
|
6674
8245
|
}
|
|
6675
8246
|
}
|
|
6676
8247
|
|
|
6677
|
-
utils.inherit(MapExtent, EventDispatcher);
|
|
8248
|
+
utils$1.inherit(MapExtent, EventDispatcher);
|
|
6678
8249
|
|
|
6679
8250
|
// TODO: consider moving this upstream
|
|
6680
8251
|
function getArcsForRendering(obj, ext) {
|
|
@@ -6821,21 +8392,40 @@
|
|
|
6821
8392
|
_self.drawVertices = function(shapes, arcs, style, filter) {
|
|
6822
8393
|
var iter = new internal.ShapeIter(arcs);
|
|
6823
8394
|
var t = getScaledTransform(_ext);
|
|
6824
|
-
var radius = (style.strokeWidth * 0.9
|
|
8395
|
+
var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
|
|
6825
8396
|
var color = style.strokeColor || 'black';
|
|
6826
|
-
var
|
|
8397
|
+
var radius2 = radius * 1.7;
|
|
8398
|
+
var i, j, p;
|
|
6827
8399
|
_ctx.beginPath();
|
|
6828
8400
|
_ctx.fillStyle = color;
|
|
6829
|
-
for (
|
|
6830
|
-
shp = shapes[i];
|
|
8401
|
+
for (i=0; i<shapes.length; i++) {
|
|
8402
|
+
var shp = shapes[i];
|
|
6831
8403
|
if (!shp || filter && !filter(shp)) continue;
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
8404
|
+
for (j=0; j<shp.length; j++) {
|
|
8405
|
+
iter.init(shp[j]);
|
|
8406
|
+
while (iter.hasNext()) {
|
|
8407
|
+
drawCircle(iter.x * t.mx + t.bx, iter.y * t.my + t.by, radius, _ctx);
|
|
8408
|
+
}
|
|
6835
8409
|
}
|
|
6836
8410
|
}
|
|
8411
|
+
|
|
8412
|
+
if (style.vertex_overlay) {
|
|
8413
|
+
p = style.vertex_overlay;
|
|
8414
|
+
drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius2, _ctx);
|
|
8415
|
+
}
|
|
6837
8416
|
_ctx.fill();
|
|
6838
8417
|
_ctx.closePath();
|
|
8418
|
+
|
|
8419
|
+
if (style.selected_points) {
|
|
8420
|
+
_ctx.beginPath();
|
|
8421
|
+
_ctx.fillStyle = 'magenta';
|
|
8422
|
+
for (i=0; i<style.selected_points.length; i++) {
|
|
8423
|
+
p = style.selected_points[i];
|
|
8424
|
+
drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius2, _ctx);
|
|
8425
|
+
}
|
|
8426
|
+
_ctx.fill();
|
|
8427
|
+
_ctx.closePath();
|
|
8428
|
+
}
|
|
6839
8429
|
};
|
|
6840
8430
|
|
|
6841
8431
|
// Optimized to draw paths in same-style batches (faster Canvas drawing)
|
|
@@ -6858,7 +8448,7 @@
|
|
|
6858
8448
|
key = getStyleKey(style);
|
|
6859
8449
|
if (key in styleIndex === false) {
|
|
6860
8450
|
styleIndex[key] = {
|
|
6861
|
-
style: utils.defaults({}, style),
|
|
8451
|
+
style: utils$1.defaults({}, style),
|
|
6862
8452
|
shapes: []
|
|
6863
8453
|
};
|
|
6864
8454
|
}
|
|
@@ -7198,7 +8788,8 @@
|
|
|
7198
8788
|
if (style.strokeWidth > 0) {
|
|
7199
8789
|
strokeWidth = style.strokeWidth;
|
|
7200
8790
|
if (pixRatio > 1) {
|
|
7201
|
-
// bump up thin lines on retina, but not to more than 1px
|
|
8791
|
+
// bump up thin lines on retina, but not to more than 1px
|
|
8792
|
+
// (tests on Chrome showed much faster rendering of 1px lines)
|
|
7202
8793
|
strokeWidth = strokeWidth < 1 ? 1 : strokeWidth * pixRatio;
|
|
7203
8794
|
}
|
|
7204
8795
|
ctx.lineCap = 'round';
|
|
@@ -7332,7 +8923,7 @@
|
|
|
7332
8923
|
var frame = ext.getFrame(); // frame should be set if we're rendering a furniture layer
|
|
7333
8924
|
var obj = internal.getEmptyLayerForSVG(lyr, {});
|
|
7334
8925
|
if (!frame) {
|
|
7335
|
-
stop('Missing map frame data');
|
|
8926
|
+
stop$1('Missing map frame data');
|
|
7336
8927
|
}
|
|
7337
8928
|
obj.properties.transform = getSvgFurnitureTransform(ext);
|
|
7338
8929
|
obj.properties.class = 'mapshaper-svg-furniture';
|
|
@@ -7360,7 +8951,7 @@
|
|
|
7360
8951
|
var html = '';
|
|
7361
8952
|
// generate a unique id so layer can be identified when symbols are repositioned
|
|
7362
8953
|
// use it as a class name to avoid id collisions
|
|
7363
|
-
var id = utils.getUniqueName();
|
|
8954
|
+
var id = utils$1.getUniqueName();
|
|
7364
8955
|
var classNames = [id, 'mapshaper-svg-layer', 'mapshaper-' + type + '-layer'];
|
|
7365
8956
|
g.setAttribute('class', classNames.join(' '));
|
|
7366
8957
|
target.svg_id = id;
|
|
@@ -7811,7 +9402,7 @@
|
|
|
7811
9402
|
}
|
|
7812
9403
|
|
|
7813
9404
|
if (obj.tabular) {
|
|
7814
|
-
utils.extend(obj, getDisplayLayerForTable(layer.data));
|
|
9405
|
+
utils$1.extend(obj, getDisplayLayerForTable(layer.data));
|
|
7815
9406
|
}
|
|
7816
9407
|
|
|
7817
9408
|
// dynamic reprojection (arcs were already reprojected above)
|
|
@@ -7869,7 +9460,7 @@
|
|
|
7869
9460
|
return ids;
|
|
7870
9461
|
}
|
|
7871
9462
|
|
|
7872
|
-
utils.inherit(MshpMap, EventDispatcher);
|
|
9463
|
+
utils$1.inherit(MshpMap, EventDispatcher);
|
|
7873
9464
|
|
|
7874
9465
|
function MshpMap(gui) {
|
|
7875
9466
|
var opts = gui.options,
|
|
@@ -7886,7 +9477,7 @@
|
|
|
7886
9477
|
_visibleLayers = [], // cached visible map layers
|
|
7887
9478
|
_fullBounds = null,
|
|
7888
9479
|
_intersectionLyr, _activeLyr, _overlayLyr,
|
|
7889
|
-
_inspector, _stack,
|
|
9480
|
+
_inspector, _stack,
|
|
7890
9481
|
_dynamicCRS;
|
|
7891
9482
|
|
|
7892
9483
|
if (gui.options.showMouseCoordinates) {
|
|
@@ -7963,7 +9554,7 @@
|
|
|
7963
9554
|
this.setDisplayCRS = function(crs) {
|
|
7964
9555
|
// TODO: update bounds of frame layer, if there is a frame layer
|
|
7965
9556
|
var oldCRS = this.getDisplayCRS();
|
|
7966
|
-
var newCRS = utils.isString(crs) ? internal.getCRS(crs) : crs;
|
|
9557
|
+
var newCRS = utils$1.isString(crs) ? internal.getCRS(crs) : crs;
|
|
7967
9558
|
// TODO: handle case that old and new CRS are the same
|
|
7968
9559
|
_dynamicCRS = newCRS;
|
|
7969
9560
|
if (!_activeLyr) return; // stop here if no layers have been selected
|
|
@@ -8069,7 +9660,9 @@
|
|
|
8069
9660
|
});
|
|
8070
9661
|
}
|
|
8071
9662
|
|
|
8072
|
-
|
|
9663
|
+
if (gui.interaction) {
|
|
9664
|
+
initInteractiveEditing(gui, _ext, _hit);
|
|
9665
|
+
}
|
|
8073
9666
|
|
|
8074
9667
|
_ext.on('change', function(e) {
|
|
8075
9668
|
if (e.reset) return; // don't need to redraw map here if extent has been reset
|
|
@@ -8089,11 +9682,7 @@
|
|
|
8089
9682
|
function updateOverlayLayer(e) {
|
|
8090
9683
|
var style = getOverlayStyle(_activeLyr.layer, e);
|
|
8091
9684
|
if (style) {
|
|
8092
|
-
|
|
8093
|
-
if (gui.state.interaction_mode == 'vertices') {
|
|
8094
|
-
style.vertices = true;
|
|
8095
|
-
}
|
|
8096
|
-
_overlayLyr = utils.defaults({
|
|
9685
|
+
_overlayLyr = utils$1.defaults({
|
|
8097
9686
|
layer: filterLayerByIds(_activeLyr.layer, style.ids),
|
|
8098
9687
|
style: style
|
|
8099
9688
|
}, _activeLyr);
|
|
@@ -8258,7 +9847,7 @@
|
|
|
8258
9847
|
// kludge to hide ghosted layers when reference layers are present
|
|
8259
9848
|
// TODO: consider never showing ghosted layers (which appear after
|
|
8260
9849
|
// commands like dissolve and filter).
|
|
8261
|
-
mapLayer.style = utils.defaults({
|
|
9850
|
+
mapLayer.style = utils$1.defaults({
|
|
8262
9851
|
strokeColors: [null, mapLayer.style.strokeColors[1]]
|
|
8263
9852
|
}, mapLayer.style);
|
|
8264
9853
|
}
|
|
@@ -8314,7 +9903,7 @@
|
|
|
8314
9903
|
|
|
8315
9904
|
function GuiInstance(container, opts) {
|
|
8316
9905
|
var gui = new ModeSwitcher();
|
|
8317
|
-
opts = utils.extend({
|
|
9906
|
+
opts = utils$1.extend({
|
|
8318
9907
|
// defaults
|
|
8319
9908
|
homeControl: true,
|
|
8320
9909
|
zoomControl: true,
|
|
@@ -8396,14 +9985,14 @@
|
|
|
8396
9985
|
startEditing();
|
|
8397
9986
|
});
|
|
8398
9987
|
|
|
8399
|
-
function
|
|
9988
|
+
function getManifest() {
|
|
9989
|
+
return window.mapshaper.manifest || {}; // kludge -- bin/mapshaper-gui sets this
|
|
9990
|
+
}
|
|
9991
|
+
|
|
9992
|
+
function getImportOpts(manifest) {
|
|
8400
9993
|
var vars = GUI.getUrlVars();
|
|
8401
9994
|
var opts = {};
|
|
8402
|
-
|
|
8403
|
-
if (Array.isArray(manifest)) {
|
|
8404
|
-
// old-style manifest: an array of filenames
|
|
8405
|
-
opts.files = manifest;
|
|
8406
|
-
} else if (manifest.files) {
|
|
9995
|
+
if (manifest.files) {
|
|
8407
9996
|
opts.files = manifest.files.concat();
|
|
8408
9997
|
} else {
|
|
8409
9998
|
opts.files = [];
|
|
@@ -8421,11 +10010,20 @@
|
|
|
8421
10010
|
return opts;
|
|
8422
10011
|
}
|
|
8423
10012
|
|
|
10013
|
+
function getInitialConsoleCommands() {
|
|
10014
|
+
return getManifest().commands || '';
|
|
10015
|
+
}
|
|
10016
|
+
|
|
8424
10017
|
var startEditing = function() {
|
|
8425
10018
|
var dataLoaded = false,
|
|
8426
|
-
|
|
10019
|
+
manifest = getManifest(),
|
|
10020
|
+
importOpts = getImportOpts(manifest),
|
|
8427
10021
|
gui = new GuiInstance('body');
|
|
8428
10022
|
|
|
10023
|
+
if (manifest.blurb) {
|
|
10024
|
+
El('#splash-screen-blurb').text(manifest.blurb);
|
|
10025
|
+
}
|
|
10026
|
+
|
|
8429
10027
|
new AlertControl(gui);
|
|
8430
10028
|
new RepairControl(gui);
|
|
8431
10029
|
new SimplifyControl(gui);
|
|
@@ -8462,6 +10060,8 @@
|
|
|
8462
10060
|
gui.map.setLayerPinning(o, true);
|
|
8463
10061
|
});
|
|
8464
10062
|
}
|
|
10063
|
+
gui.console.runInitialCommands(getInitialConsoleCommands());
|
|
10064
|
+
|
|
8465
10065
|
});
|
|
8466
10066
|
};
|
|
8467
10067
|
|