mapshaper 0.5.92 → 0.5.93

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.
@@ -1,16 +1,114 @@
1
1
  (function () {
2
2
 
3
+ var utils = /*#__PURE__*/Object.freeze({
4
+ __proto__: null,
5
+ get default () { return utils; },
6
+ get getUniqueName () { return getUniqueName; },
7
+ get isFunction () { return isFunction; },
8
+ get isObject () { return isObject; },
9
+ get clamp () { return clamp; },
10
+ get isArray () { return isArray; },
11
+ get isNumber () { return isNumber; },
12
+ get isValidNumber () { return isValidNumber; },
13
+ get isFiniteNumber () { return isFiniteNumber; },
14
+ get isNonNegNumber () { return isNonNegNumber; },
15
+ get isInteger () { return isInteger; },
16
+ get isEven () { return isEven; },
17
+ get isOdd () { return isOdd; },
18
+ get isString () { return isString; },
19
+ get isDate () { return isDate; },
20
+ get isBoolean () { return isBoolean; },
21
+ get formatDateISO () { return formatDateISO; },
22
+ get toArray () { return toArray; },
23
+ get isArrayLike () { return isArrayLike; },
24
+ get addslashes () { return addslashes; },
25
+ get regexEscape () { return regexEscape; },
26
+ get htmlEscape () { return htmlEscape; },
27
+ get defaults () { return defaults; },
28
+ get extend () { return extend; },
29
+ get inherit () { return inherit; },
30
+ get reduceAsync () { return reduceAsync; },
31
+ get merge () { return merge; },
32
+ get difference () { return difference; },
33
+ get intersection () { return intersection; },
34
+ get indexOf () { return indexOf; },
35
+ get contains () { return contains; },
36
+ get some () { return some; },
37
+ get every () { return every; },
38
+ get find () { return find; },
39
+ get range () { return range; },
40
+ get repeat () { return repeat; },
41
+ get sum () { return sum; },
42
+ get getArrayBounds () { return getArrayBounds; },
43
+ get uniq () { return uniq; },
44
+ get pluck () { return pluck; },
45
+ get countValues () { return countValues; },
46
+ get indexOn () { return indexOn; },
47
+ get groupBy () { return groupBy; },
48
+ get arrayToIndex () { return arrayToIndex; },
49
+ get forEach () { return forEach; },
50
+ get forEachProperty () { return forEachProperty; },
51
+ get initializeArray () { return initializeArray; },
52
+ get replaceArray () { return replaceArray; },
53
+ get repeatString () { return repeatString; },
54
+ get splitLines () { return splitLines; },
55
+ get pluralSuffix () { return pluralSuffix; },
56
+ get endsWith () { return endsWith; },
57
+ get lpad () { return lpad; },
58
+ get rpad () { return rpad; },
59
+ get trim () { return trim; },
60
+ get ltrim () { return ltrim; },
61
+ get rtrim () { return rtrim; },
62
+ get addThousandsSep () { return addThousandsSep; },
63
+ get numToStr () { return numToStr; },
64
+ get formatNumber () { return formatNumber; },
65
+ get formatIntlNumber () { return formatIntlNumber; },
66
+ get formatNumberForDisplay () { return formatNumberForDisplay; },
67
+ get shuffle () { return shuffle; },
68
+ get sortOn () { return sortOn; },
69
+ get genericSort () { return genericSort; },
70
+ get getSortedIds () { return getSortedIds; },
71
+ get sortArrayIndex () { return sortArrayIndex; },
72
+ get reorderArray () { return reorderArray; },
73
+ get getKeyComparator () { return getKeyComparator; },
74
+ get getGenericComparator () { return getGenericComparator; },
75
+ get quicksort () { return quicksort; },
76
+ get quicksortPartition () { return quicksortPartition; },
77
+ get findRankByValue () { return findRankByValue; },
78
+ get findValueByPct () { return findValueByPct; },
79
+ get findValueByRank () { return findValueByRank; },
80
+ get findMedian () { return findMedian; },
81
+ get mean () { return mean; },
82
+ get format () { return format; },
83
+ get formatter () { return formatter; },
84
+ get wildcardToRegExp () { return wildcardToRegExp; },
85
+ get createBuffer () { return createBuffer; },
86
+ get expandoBuffer () { return expandoBuffer; },
87
+ get copyElements () { return copyElements; },
88
+ get extendBuffer () { return extendBuffer; },
89
+ get mergeNames () { return mergeNames; },
90
+ get findStringPrefix () { return findStringPrefix; },
91
+ get parsePercent () { return parsePercent; },
92
+ get formatVersionedName () { return formatVersionedName; },
93
+ get uniqifyNames () { return uniqifyNames; },
94
+ get parseString () { return parseString; },
95
+ get parseNumber () { return parseNumber; },
96
+ get parseIntlNumber () { return parseIntlNumber; },
97
+ get cleanNumericString () { return cleanNumericString; },
98
+ get trimQuotes () { return trimQuotes; }
99
+ });
100
+
3
101
  var api = window.mapshaper; // assuming mapshaper is in global scope
4
102
  var mapshaper = api,
5
- utils = api.utils,
103
+ utils$1 = api.utils,
6
104
  cli = api.cli,
7
105
  geom = api.geom,
8
106
  internal = api.internal,
9
107
  Bounds = internal.Bounds,
10
- UserError = internal.UserError,
11
- message = internal.message, // stop, error and message are overridden in gui-proxy.js
12
- stop = internal.stop,
13
- error = internal.error;
108
+ UserError$1 = internal.UserError,
109
+ message$1 = internal.message, // stop, error and message are overridden in gui-proxy.js
110
+ stop$1 = internal.stop,
111
+ error$1 = internal.error;
14
112
 
15
113
  api.enableLogging();
16
114
 
@@ -46,7 +144,7 @@
46
144
 
47
145
  html = '<table>';
48
146
  if (catalog.title) {
49
- html += utils.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
147
+ html += utils$1.format('<tr><th colspan="%d"><h4>%s</h4></th></tr>', cols, catalog.title);
50
148
  }
51
149
  while (row < rows) {
52
150
  html += renderRow(items.slice(row * cols, row * cols + cols));
@@ -111,7 +209,7 @@
111
209
 
112
210
  function renderCell(item, i) {
113
211
  var template = '<td data-id="%d"><h4 class="title">%s</h4><div class="subtitle">%s</div></td>';
114
- return utils.format(template, i, item.title, item.subtitle || '');
212
+ return utils$1.format(template, i, item.title, item.subtitle || '');
115
213
  }
116
214
 
117
215
  }
@@ -228,7 +326,7 @@
228
326
  }
229
327
  parsed = internal.parseCommands(str);
230
328
  if (!parsed.length || parsed[0].name != cmd) {
231
- stop("Unable to parse command line options");
329
+ stop$1("Unable to parse command line options");
232
330
  }
233
331
  return parsed[0].options;
234
332
  };
@@ -321,7 +419,7 @@
321
419
  evt = new EventData(this.type);
322
420
  evt.target = this.target;
323
421
  } else if (evt.target != this.target || evt.type != this.type) {
324
- error("[Handler] event target/type have changed.");
422
+ error$1("[Handler] event target/type have changed.");
325
423
  }
326
424
  this.callback.call(this.listener, evt);
327
425
  };
@@ -330,7 +428,7 @@
330
428
  this.type = type;
331
429
  this.target = target;
332
430
  if (data) {
333
- utils.defaults(this, data);
431
+ utils$1.defaults(this, data);
334
432
  this.data = data;
335
433
  }
336
434
  }
@@ -560,12 +658,12 @@
560
658
  try {
561
659
  els = root.querySelectorAll(selector);
562
660
  } catch (e) {
563
- error("Invalid selector:", selector);
661
+ error$1("Invalid selector:", selector);
564
662
  }
565
663
  } else {
566
- error("This browser doesn't support CSS query selectors");
664
+ error$1("This browser doesn't support CSS query selectors");
567
665
  }
568
- return utils.toArray(els);
666
+ return utils$1.toArray(els);
569
667
  };
570
668
 
571
669
  // Converts dash-separated names (e.g. background-color) to camelCase (e.g. backgroundColor)
@@ -602,7 +700,7 @@
602
700
  };
603
701
 
604
702
  function El(ref) {
605
- if (!ref) error("Element() needs a reference");
703
+ if (!ref) error$1("Element() needs a reference");
606
704
  if (ref instanceof El) {
607
705
  return ref;
608
706
  }
@@ -611,7 +709,7 @@
611
709
  }
612
710
 
613
711
  var node;
614
- if (utils.isString(ref)) {
712
+ if (utils$1.isString(ref)) {
615
713
  if (ref[0] == '<') {
616
714
  var parent = El('div').html(ref).node();
617
715
  node = parent.childNodes.length == 1 ? parent.childNodes[0] : parent;
@@ -623,13 +721,13 @@
623
721
  } else if (ref.tagName) {
624
722
  node = ref;
625
723
  }
626
- if (!node) error("Unmatched element selector:", ref);
724
+ if (!node) error$1("Unmatched element selector:", ref);
627
725
  this.el = node;
628
726
  }
629
727
 
630
- utils.inherit(El, EventDispatcher);
728
+ utils$1.inherit(El, EventDispatcher);
631
729
 
632
- utils.extend(El.prototype, {
730
+ utils$1.extend(El.prototype, {
633
731
 
634
732
  clone: function() {
635
733
  var el = this.el.cloneNode(true);
@@ -638,7 +736,7 @@
638
736
  // can ...
639
737
  el = El('div').addClass(el.className).html(el.innerHTML).node();
640
738
  }
641
- el.id = utils.getUniqueName();
739
+ el.id = utils$1.getUniqueName();
642
740
  this.el = el;
643
741
  return this;
644
742
  },
@@ -668,11 +766,11 @@
668
766
  if (val != null) {
669
767
  El.setStyle(this.el, css, val);
670
768
  }
671
- else if (utils.isString(css)) {
769
+ else if (utils$1.isString(css)) {
672
770
  addCSS(this.el, css);
673
771
  }
674
- else if (utils.isObject(css)) {
675
- utils.forEachProperty(css, function(val, key) {
772
+ else if (utils$1.isObject(css)) {
773
+ utils$1.forEachProperty(css, function(val, key) {
676
774
  El.setStyle(this.el, key, val);
677
775
  }, this);
678
776
  }
@@ -680,7 +778,7 @@
680
778
  },
681
779
 
682
780
  attr: function(obj, value) {
683
- if (utils.isString(obj)) {
781
+ if (utils$1.isString(obj)) {
684
782
  if (arguments.length == 1) {
685
783
  return this.el.getAttribute(obj);
686
784
  }
@@ -764,7 +862,7 @@
764
862
  },
765
863
 
766
864
  text: function(str) {
767
- this.html(utils.htmlEscape(str));
865
+ this.html(utils$1.htmlEscape(str));
768
866
  return this;
769
867
  },
770
868
 
@@ -854,7 +952,7 @@
854
952
  El.prototype.__on = El.prototype.on;
855
953
  El.prototype.on = function(type, func, ctx) {
856
954
  if (ctx) {
857
- error("[El#on()] Third argument no longer supported.");
955
+ error$1("[El#on()] Third argument no longer supported.");
858
956
  }
859
957
  if (this.constructor == El) {
860
958
  this.el.addEventListener(type, func);
@@ -910,7 +1008,7 @@
910
1008
  }
911
1009
 
912
1010
  this.value = function(str) {
913
- if (utils.isString(str)) {
1011
+ if (utils$1.isString(str)) {
914
1012
  el.node().textContent = str;
915
1013
  } else {
916
1014
  return el.node().textContent;
@@ -918,7 +1016,7 @@
918
1016
  };
919
1017
  }
920
1018
 
921
- utils.inherit(ClickText2, EventDispatcher);
1019
+ utils$1.inherit(ClickText2, EventDispatcher);
922
1020
 
923
1021
  // @ref reference to a text input element
924
1022
  function ClickText(ref) {
@@ -989,9 +1087,9 @@
989
1087
  // return _parser ? _parser(valStr) : parseFloat(valStr);
990
1088
  return _value;
991
1089
  }
992
- var val = utils.clamp(arg, _min, _max);
1090
+ var val = utils$1.clamp(arg, _min, _max);
993
1091
  if (!_validator(val)) {
994
- error("ClickText#value() invalid value:", arg);
1092
+ error$1("ClickText#value() invalid value:", arg);
995
1093
  } else {
996
1094
  _value = val;
997
1095
  }
@@ -1000,14 +1098,14 @@
1000
1098
  };
1001
1099
  }
1002
1100
 
1003
- utils.inherit(ClickText, EventDispatcher);
1101
+ utils$1.inherit(ClickText, EventDispatcher);
1004
1102
 
1005
1103
 
1006
1104
  function Checkbox(ref) {
1007
1105
  var _el = El(ref);
1008
1106
  }
1009
1107
 
1010
- utils.inherit(Checkbox, EventDispatcher);
1108
+ utils$1.inherit(Checkbox, EventDispatcher);
1011
1109
 
1012
1110
  function SimpleButton(ref) {
1013
1111
  var _el = El(ref),
@@ -1036,7 +1134,7 @@
1036
1134
  }
1037
1135
  }
1038
1136
 
1039
- utils.inherit(SimpleButton, EventDispatcher);
1137
+ utils$1.inherit(SimpleButton, EventDispatcher);
1040
1138
 
1041
1139
  // @cb function(<FileList>)
1042
1140
  function DropControl(gui, el, cb) {
@@ -1316,7 +1414,7 @@
1316
1414
  }
1317
1415
 
1318
1416
  function filesMayContainPaths(files) {
1319
- return utils.some(files, function(f) {
1417
+ return utils$1.some(files, function(f) {
1320
1418
  var type = internal.guessInputFileType(f.name);
1321
1419
  return type == 'shp' || type == 'json' || internal.isZipFile(f.name);
1322
1420
  });
@@ -1372,7 +1470,7 @@
1372
1470
  }
1373
1471
 
1374
1472
  function handleImportError(e, fileName) {
1375
- var msg = utils.isString(e) ? e : e.message;
1473
+ var msg = utils$1.isString(e) ? e : e.message;
1376
1474
  if (fileName) {
1377
1475
  msg = "Error importing <i>" + fileName + "</i><br>" + msg;
1378
1476
  }
@@ -1402,7 +1500,7 @@
1402
1500
 
1403
1501
  function downloadFiles(paths) {
1404
1502
  var items = prepFilesForDownload(paths);
1405
- utils.reduceAsync(items, [], downloadNextFile, function(err, files) {
1503
+ utils$1.reduceAsync(items, [], downloadNextFile, function(err, files) {
1406
1504
  if (err) {
1407
1505
  gui.alert(err);
1408
1506
  } else if (!files.length) {
@@ -1568,7 +1666,7 @@
1568
1666
  var defaults = {
1569
1667
  space: 7
1570
1668
  };
1571
- opts = utils.extend(defaults, opts);
1669
+ opts = utils$1.extend(defaults, opts);
1572
1670
 
1573
1671
  var _pct = 0;
1574
1672
  var _track,
@@ -1621,7 +1719,7 @@
1621
1719
  };
1622
1720
 
1623
1721
  function setHandlePos(x, fire) {
1624
- x = utils.clamp(x, 0, size());
1722
+ x = utils$1.clamp(x, 0, size());
1625
1723
  var pct = x / size();
1626
1724
  if (pct != _pct) {
1627
1725
  _pct = pct;
@@ -1636,7 +1734,7 @@
1636
1734
  }
1637
1735
  }
1638
1736
 
1639
- utils.inherit(Slider, EventDispatcher);
1737
+ utils$1.inherit(Slider, EventDispatcher);
1640
1738
 
1641
1739
  /*
1642
1740
  How changes in the simplify control should affect other components
@@ -1704,7 +1802,7 @@
1704
1802
  slider.on('change', function(e) {
1705
1803
  var pct = fromSliderPct(e.pct);
1706
1804
  text.value(pct);
1707
- pct = utils.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
1805
+ pct = utils$1.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
1708
1806
  onChange(pct);
1709
1807
  });
1710
1808
  slider.on('start', function(e) {
@@ -1725,7 +1823,7 @@
1725
1823
  else if (pct < 0.01) decimals = 3;
1726
1824
  else if (pct < 1) decimals = 2;
1727
1825
  else if (pct < 100) decimals = 1;
1728
- return utils.formatNumberForDisplay(pct, decimals) + "%";
1826
+ return utils$1.formatNumberForDisplay(pct, decimals) + "%";
1729
1827
  });
1730
1828
 
1731
1829
  text.parser(function(s) {
@@ -1977,7 +2075,7 @@
1977
2075
 
1978
2076
  // Replace error function in mapshaper lib
1979
2077
  var error = function() {
1980
- stop.apply(null, utils.toArray(arguments));
2078
+ stop.apply(null, utils$1.toArray(arguments));
1981
2079
  };
1982
2080
 
1983
2081
  var message = function() {
@@ -1991,11 +2089,11 @@
1991
2089
  // replace CLI version of writeFiles()
1992
2090
  internal.replaceWriteFiles(function(files, opts, done) {
1993
2091
  var filename;
1994
- if (!utils.isArray(files) || files.length === 0) {
2092
+ if (!utils$1.isArray(files) || files.length === 0) {
1995
2093
  done("Nothing to export");
1996
2094
  } else if (GUI.canSaveToServer() && !opts.save_to_download_folder) {
1997
- var paths = internal.getOutputPaths(utils.pluck(files, 'filename'), opts);
1998
- var data = utils.pluck(files, 'content');
2095
+ var paths = internal.getOutputPaths(utils$1.pluck(files, 'filename'), opts);
2096
+ var data = utils$1.pluck(files, 'content');
1999
2097
  saveFilesToServer(paths, data, function(err) {
2000
2098
  var msg;
2001
2099
  if (err) {
@@ -2014,7 +2112,7 @@
2014
2112
  } else if (files.length == 1) {
2015
2113
  saveBlobToDownloadFolder(files[0].filename, new Blob([files[0].content]), done);
2016
2114
  } else {
2017
- filename = internal.getCommonFileBase(utils.pluck(files, 'filename')) || "output";
2115
+ filename = internal.getCommonFileBase(utils$1.pluck(files, 'filename')) || "output";
2018
2116
  saveZipFile(filename + ".zip", files, done);
2019
2117
  }
2020
2118
  });
@@ -2036,10 +2134,10 @@
2036
2134
  // try to match import filename of this dataset
2037
2135
  if (d.info.input_files[0] == src) return d;
2038
2136
  // try to match name of a layer in this dataset
2039
- lyr = utils.find(d.layers, function(lyr) {return lyr.name == src;});
2137
+ lyr = utils$1.find(d.layers, function(lyr) {return lyr.name == src;});
2040
2138
  return lyr ? internal.isolateLayer(lyr, d) : null;
2041
2139
  }, null);
2042
- if (!retn) stop("Missing data layer [" + src + "]");
2140
+ if (!retn) stop$1("Missing data layer [" + src + "]");
2043
2141
  return retn;
2044
2142
  }
2045
2143
 
@@ -2048,7 +2146,7 @@
2048
2146
  // Return a copy with layers duplicated, so changes won't affect original layers
2049
2147
  // This makes an (unsafe) assumption that the dataset arcs won't be changed...
2050
2148
  // need to rethink this.
2051
- return utils.defaults({
2149
+ return utils$1.defaults({
2052
2150
  layers: dataset.layers.map(internal.copyLayer)
2053
2151
  }, dataset);
2054
2152
  });
@@ -2120,7 +2218,7 @@
2120
2218
  }
2121
2219
 
2122
2220
  function projectPointsForDisplay(lyr, src, dest) {
2123
- var copy = utils.extend({}, lyr);
2221
+ var copy = utils$1.extend({}, lyr);
2124
2222
  var proj = internal.getProjTransform2(src, dest);
2125
2223
  copy.shapes = internal.cloneShapes(lyr.shapes);
2126
2224
  internal.projectPointLayer(copy, proj);
@@ -2525,7 +2623,7 @@
2525
2623
  } else if (cmd == 'history') {
2526
2624
  toLog(gui.session.toCommandLineString());
2527
2625
  } else if (cmd == 'layers') {
2528
- message("Available layers:",
2626
+ message$1("Available layers:",
2529
2627
  internal.getFormattedLayerList(model));
2530
2628
  } else if (cmd == 'close' || cmd == 'exit' || cmd == 'quit') {
2531
2629
  turnOff();
@@ -2614,7 +2712,7 @@
2614
2712
  }
2615
2713
 
2616
2714
  function onError(err) {
2617
- if (utils.isString(err)) {
2715
+ if (utils$1.isString(err)) {
2618
2716
  consoleStop(err);
2619
2717
  } else if (err.name == 'UserError') {
2620
2718
  // stop() has already been called, don't need to log
@@ -2629,7 +2727,7 @@
2629
2727
  function consoleStop() {
2630
2728
  var msg = GUI.formatMessageArgs(arguments);
2631
2729
  consoleWarning(msg);
2632
- throw new UserError(msg);
2730
+ throw new UserError$1(msg);
2633
2731
  }
2634
2732
 
2635
2733
  function consoleWarning() {
@@ -2793,7 +2891,7 @@
2793
2891
  // console.log("first intersection:", internal.getIntersectionDebugData(XX[0], arcs));
2794
2892
  pointLyr = {geometry_type: 'point', shapes: [internal.getIntersectionPoints(XX)]};
2795
2893
  map.setIntersectionLayer(pointLyr, {layers:[pointLyr]});
2796
- readout.html(utils.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils.pluralSuffix(n)));
2894
+ readout.html(utils$1.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils$1.pluralSuffix(n)));
2797
2895
  readout.findChild('.close-btn').on('click', dismiss);
2798
2896
  } else {
2799
2897
  map.setIntersectionLayer(null);
@@ -2802,7 +2900,7 @@
2802
2900
  }
2803
2901
  }
2804
2902
 
2805
- utils.inherit(RepairControl, EventDispatcher);
2903
+ utils$1.inherit(RepairControl, EventDispatcher);
2806
2904
 
2807
2905
  function filterLayerByIds(lyr, ids) {
2808
2906
  var shapes;
@@ -2810,7 +2908,7 @@
2810
2908
  shapes = ids.map(function(id) {
2811
2909
  return lyr.shapes[id];
2812
2910
  });
2813
- return utils.defaults({shapes: shapes, data: null}, lyr);
2911
+ return utils$1.defaults({shapes: shapes, data: null}, lyr);
2814
2912
  }
2815
2913
  return lyr;
2816
2914
  }
@@ -2863,7 +2961,7 @@
2863
2961
  });
2864
2962
 
2865
2963
  internal.writeFiles = function() {
2866
- error(unsupportedMsg);
2964
+ error$1(unsupportedMsg);
2867
2965
  };
2868
2966
  } else {
2869
2967
  new SimpleButton(menu.findChild('.save-btn').addClass('default-btn')).on('click', onExportClick);
@@ -2899,7 +2997,7 @@
2899
2997
  setTimeout(function() {
2900
2998
  exportMenuSelection(layers, function(err) {
2901
2999
  if (err) {
2902
- if (utils.isString(err)) {
3000
+ if (utils$1.isString(err)) {
2903
3001
  gui.alert(err);
2904
3002
  } else {
2905
3003
  // stack seems to change if Error is logged directly
@@ -2946,7 +3044,7 @@
2946
3044
  // without changing its name elsewhere
2947
3045
  layer: Object.assign({}, o.layer)
2948
3046
  };
2949
- var html = utils.format(template, i + 1, target.layer.name || '[unnamed layer]');
3047
+ var html = utils$1.format(template, i + 1, target.layer.name || '[unnamed layer]');
2950
3048
  // return {layer: o.layer, html: html};
2951
3049
  var el = El('div').html(html).addClass('layer-item');
2952
3050
  var box = el.findChild('input').node();
@@ -3056,9 +3154,9 @@
3056
3154
 
3057
3155
  function initFormatMenu() {
3058
3156
  var defaults = ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'svg'];
3059
- var formats = utils.uniq(defaults.concat(getInputFormats()));
3157
+ var formats = utils$1.uniq(defaults.concat(getInputFormats()));
3060
3158
  var items = formats.map(function(fmt) {
3061
- return utils.format('<div><label><input type="radio" name="format" value="%s"' +
3159
+ return utils$1.format('<div><label><input type="radio" name="format" value="%s"' +
3062
3160
  ' class="radio">%s</label></div>', fmt, internal.getFormatName(fmt));
3063
3161
  });
3064
3162
  menu.findChild('.export-formats').html(items.join('\n'));
@@ -3221,7 +3319,7 @@
3221
3319
  // can be used as unique identifiers for caching rendered HTML, and as
3222
3320
  // an id for layer menu event handlers
3223
3321
  if (!lyr.menu_id || uniqIds[lyr.menu_id]) {
3224
- lyr.menu_id = utils.getUniqueName();
3322
+ lyr.menu_id = utils$1.getUniqueName();
3225
3323
  }
3226
3324
  uniqIds[lyr.menu_id] = true;
3227
3325
  if (isPinnable(lyr)) pinnableCount++;
@@ -3394,7 +3492,7 @@
3394
3492
  type = lyr.geometry_type + ' feature';
3395
3493
  }
3396
3494
  if (type) {
3397
- str = utils.format('%,d %s%s', n, type, utils.pluralSuffix(n));
3495
+ str = utils$1.format('%,d %s%s', n, type, utils$1.pluralSuffix(n));
3398
3496
  } else {
3399
3497
  str = "[empty]";
3400
3498
  }
@@ -3405,7 +3503,7 @@
3405
3503
  var file = internal.getLayerSourceFile(lyr, dataset);
3406
3504
  var missing = [];
3407
3505
  var msg;
3408
- if (utils.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
3506
+ if (utils$1.endsWith(file, '.shp') && lyr == dataset.layers[0]) {
3409
3507
  if (!lyr.data) {
3410
3508
  missing.push('.dbf');
3411
3509
  }
@@ -3431,7 +3529,7 @@
3431
3529
 
3432
3530
 
3433
3531
  function rowHTML(c1, c2, cname) {
3434
- return utils.format('<div class="row%s"><div class="col1">%s</div>' +
3532
+ return utils$1.format('<div class="row%s"><div class="col1">%s</div>' +
3435
3533
  '<div class="col2">%s</div></div>', cname ? ' ' + cname : '', c1, c2);
3436
3534
  }
3437
3535
  }
@@ -3640,6 +3738,18 @@
3640
3738
  this.addHistoryState(stashedUndo, redo);
3641
3739
  }, this);
3642
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
+
3643
3753
  this.clear = function() {
3644
3754
  reset();
3645
3755
  };
@@ -3799,7 +3909,7 @@
3799
3909
  };
3800
3910
  }
3801
3911
 
3802
- utils.inherit(ModeSwitcher, EventDispatcher);
3912
+ utils$1.inherit(ModeSwitcher, EventDispatcher);
3803
3913
 
3804
3914
  function KeyboardEvents(gui) {
3805
3915
  var self = this;
@@ -3827,7 +3937,7 @@
3827
3937
  };
3828
3938
  }
3829
3939
 
3830
- utils.inherit(KeyboardEvents, EventDispatcher);
3940
+ utils$1.inherit(KeyboardEvents, EventDispatcher);
3831
3941
 
3832
3942
  function InteractionMode(gui) {
3833
3943
 
@@ -3853,7 +3963,7 @@
3853
3963
  data: 'edit attributes',
3854
3964
  labels: 'position labels',
3855
3965
  location: 'drag points',
3856
- vertices: 'drag vertices',
3966
+ vertices: 'edit vertices',
3857
3967
  selection: 'select features',
3858
3968
  off: 'turn off'
3859
3969
  };
@@ -4049,7 +4159,7 @@
4049
4159
  function Model(gui) {
4050
4160
  var self = new internal.Catalog();
4051
4161
  var deleteLayer = self.deleteLayer;
4052
- utils.extend(self, EventDispatcher.prototype);
4162
+ utils$1.extend(self, EventDispatcher.prototype);
4053
4163
 
4054
4164
  // override Catalog method (so -drop command will work in web console)
4055
4165
  self.deleteLayer = function(lyr, dataset) {
@@ -4083,7 +4193,7 @@
4083
4193
  if (flags.select) {
4084
4194
  self.dispatchEvent('select', active);
4085
4195
  }
4086
- self.dispatchEvent('update', utils.extend({flags: flags}, active));
4196
+ self.dispatchEvent('update', utils$1.extend({flags: flags}, active));
4087
4197
  };
4088
4198
 
4089
4199
  self.selectLayer = function(lyr, dataset) {
@@ -4106,6 +4216,1251 @@
4106
4216
  return self;
4107
4217
  }
4108
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
+ '&': '&amp;',
4550
+ '<': '&lt;',
4551
+ '>': '&gt;',
4552
+ '"': '&quot;',
4553
+ "'": '&#39;',
4554
+ '/': '&#x2F;'
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 = [];
5396
+
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
5409
+ }
5410
+ candidate = versionedName;
5411
+ }
5412
+ names2.push(candidate);
5413
+ });
5414
+ return names2;
5415
+ }
5416
+
5417
+
5418
+ // Assume: @raw is string, undefined or null
5419
+ function parseString(raw) {
5420
+ return raw ? raw : "";
5421
+ }
5422
+
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
+ }
5430
+
5431
+ function parseIntlNumber(raw) {
5432
+ return parseToNum(raw, convertIntlNumString);
5433
+ }
5434
+
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
+
4109
5464
  function absArcId(arcId) {
4110
5465
  return arcId >= 0 ? arcId : ~arcId;
4111
5466
  }
@@ -4129,6 +5484,61 @@
4129
5484
  return [xmin, ymin, xmax, ymax];
4130
5485
  }
4131
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
+
4132
5542
  function getShapeHitTest(displayLayer, ext, interactionMode) {
4133
5543
  var geoType = displayLayer.layer.geometry_type;
4134
5544
  var test;
@@ -4143,7 +5553,7 @@
4143
5553
  } else if (geoType == 'polygon') {
4144
5554
  test = polygonTest;
4145
5555
  } else {
4146
- error("Unexpected geometry type:", geoType);
5556
+ error$1("Unexpected geometry type:", geoType);
4147
5557
  }
4148
5558
  return test;
4149
5559
 
@@ -4179,7 +5589,7 @@
4179
5589
  hits = pickNearestCandidates(cands, 0, maxDist);
4180
5590
  }
4181
5591
  return {
4182
- ids: utils.pluck(hits, 'id')
5592
+ ids: utils$1.pluck(hits, 'id')
4183
5593
  };
4184
5594
  }
4185
5595
 
@@ -4201,15 +5611,15 @@
4201
5611
  }
4202
5612
 
4203
5613
  function vertexTest(x, y) {
4204
- var maxDist = getZoomAdjustedHitBuffer(15, 2),
5614
+ var maxDist = getZoomAdjustedHitBuffer(20, 2),
4205
5615
  bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
4206
5616
  cands = findHitCandidates(x, y, maxDist);
4207
5617
  sortByDistance(x, y, cands, displayLayer.arcs);
4208
5618
  cands = pickNearestCandidates(cands, bufDist, maxDist);
4209
5619
  var arcs = cands.map(function(cand) { return absArcId(cand.info.arcId); });
4210
5620
  return {
4211
- arcs: utils.uniq(arcs),
4212
- ids: utils.pluck(cands, 'id')
5621
+ arcs: utils$1.uniq(arcs),
5622
+ ids: utils$1.pluck(cands, 'id')
4213
5623
  };
4214
5624
  }
4215
5625
 
@@ -4220,7 +5630,7 @@
4220
5630
  sortByDistance(x, y, cands, displayLayer.arcs);
4221
5631
  cands = pickNearestCandidates(cands, bufDist, maxDist);
4222
5632
  return {
4223
- ids: utils.pluck(cands, 'id')
5633
+ ids: utils$1.pluck(cands, 'id')
4224
5634
  };
4225
5635
  }
4226
5636
 
@@ -4231,7 +5641,7 @@
4231
5641
  cand.info = geom.getPointToShapeInfo(x, y, cands[i].shape, arcs);
4232
5642
  cand.dist = cand.info.distance;
4233
5643
  }
4234
- utils.sortOn(cands, 'dist');
5644
+ utils$1.sortOn(cands, 'dist');
4235
5645
  }
4236
5646
 
4237
5647
  function pointTest(x, y) {
@@ -4258,7 +5668,7 @@
4258
5668
  });
4259
5669
  // console.log(hitThreshold, bullseye);
4260
5670
  return {
4261
- ids: utils.uniq(hits) // multipoint features can register multiple hits
5671
+ ids: utils$1.uniq(hits) // multipoint features can register multiple hits
4262
5672
  };
4263
5673
  }
4264
5674
 
@@ -4466,9 +5876,9 @@
4466
5876
  var data = shapeTest(p[0], p[1]) || {ids:[]};
4467
5877
  var svgData = svgTest(e); // null or a data object
4468
5878
  if (svgData) { // mouse is over an SVG symbol
4469
- utils.extend(data, svgData);
5879
+ utils$1.extend(data, svgData);
4470
5880
  // placing symbol id in front of any other hits
4471
- data.ids = utils.uniq([svgData.targetId].concat(data.ids));
5881
+ data.ids = utils$1.uniq([svgData.targetId].concat(data.ids));
4472
5882
  }
4473
5883
  data.id = data.ids.length > 0 ? data.ids[0] : -1;
4474
5884
  return data;
@@ -4572,8 +5982,8 @@
4572
5982
 
4573
5983
  self.addSelectionIds = function(ids) {
4574
5984
  turnOn('selection');
4575
- selectionIds = utils.uniq(selectionIds.concat(ids));
4576
- ids = utils.uniq(storedData.ids.concat(ids));
5985
+ selectionIds = utils$1.uniq(selectionIds.concat(ids));
5986
+ ids = utils$1.uniq(storedData.ids.concat(ids));
4577
5987
  updateSelectionState({ids: ids});
4578
5988
  };
4579
5989
 
@@ -4746,7 +6156,7 @@
4746
6156
 
4747
6157
  function toggleId(id, ids) {
4748
6158
  if (ids.indexOf(id) > -1) {
4749
- return utils.difference(ids, [id]);
6159
+ return utils$1.difference(ids, [id]);
4750
6160
  }
4751
6161
  return [id].concat(ids);
4752
6162
  }
@@ -4798,9 +6208,9 @@
4798
6208
  // d: event data (may be a pointer event object, an ordinary object or null)
4799
6209
  function triggerHitEvent(type, d) {
4800
6210
  // Merge stored hit data into the event data
4801
- var eventData = utils.extend({mode: interactionMode}, d || {}, storedData);
6211
+ var eventData = utils$1.extend({mode: interactionMode}, d || {}, storedData);
4802
6212
  if (transientIds.length) {
4803
- eventData.ids = utils.uniq(transientIds.concat(eventData.ids || []));
6213
+ eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
4804
6214
  }
4805
6215
  self.dispatchEvent(type, eventData);
4806
6216
  }
@@ -4934,7 +6344,7 @@
4934
6344
  }
4935
6345
  }
4936
6346
 
4937
- utils.inherit(Timer, EventDispatcher);
6347
+ utils$1.inherit(Timer, EventDispatcher);
4938
6348
 
4939
6349
  function Tween(ease) {
4940
6350
  var self = this,
@@ -4956,7 +6366,7 @@
4956
6366
  }
4957
6367
  }
4958
6368
 
4959
- utils.inherit(Tween, EventDispatcher);
6369
+ utils$1.inherit(Tween, EventDispatcher);
4960
6370
 
4961
6371
  Tween.sineInOut = function(n) {
4962
6372
  return 0.5 - Math.cos(n * Math.PI) / 2;
@@ -5024,7 +6434,7 @@
5024
6434
  update();
5025
6435
  }
5026
6436
 
5027
- utils.inherit(ElementPosition, EventDispatcher);
6437
+ utils$1.inherit(ElementPosition, EventDispatcher);
5028
6438
 
5029
6439
  function MouseWheelDirection() {
5030
6440
  var prevTime = 0;
@@ -5122,13 +6532,13 @@
5122
6532
  // Decelerate towards the end of the sustain interval (for smoother zooming)
5123
6533
  multiplier *= Tween.quadraticOut(1 - fadeFactor);
5124
6534
  }
5125
- obj = utils.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
6535
+ obj = utils$1.extend({direction: wheelDirection, multiplier: multiplier}, mouse.mouseData());
5126
6536
  self.dispatchEvent('mousewheel', obj);
5127
6537
  }
5128
6538
  }
5129
6539
  }
5130
6540
 
5131
- utils.inherit(MouseWheel, EventDispatcher);
6541
+ utils$1.inherit(MouseWheel, EventDispatcher);
5132
6542
 
5133
6543
 
5134
6544
  function MouseArea(element, pos) {
@@ -5182,7 +6592,7 @@
5182
6592
  };
5183
6593
 
5184
6594
  this.mouseData = function() {
5185
- return utils.extend({}, _prevEvt);
6595
+ return utils$1.extend({}, _prevEvt);
5186
6596
  };
5187
6597
 
5188
6598
  function onAreaDown(e) {
@@ -5241,7 +6651,7 @@
5241
6651
  dragX: evt.pageX - _downEvt.pageX,
5242
6652
  dragY: evt.pageY - _downEvt.pageY
5243
6653
  };
5244
- _self.dispatchEvent('drag', utils.extend(obj, evt));
6654
+ _self.dispatchEvent('drag', utils$1.extend(obj, evt));
5245
6655
  } else {
5246
6656
  _self.dispatchEvent('hover', evt);
5247
6657
  }
@@ -5273,7 +6683,7 @@
5273
6683
  }
5274
6684
  }
5275
6685
 
5276
- utils.inherit(MouseArea, EventDispatcher);
6686
+ utils$1.inherit(MouseArea, EventDispatcher);
5277
6687
 
5278
6688
  function initVariableClick(node, cb) {
5279
6689
  var downEvent = null;
@@ -5420,7 +6830,7 @@
5420
6830
  maxScale = 4,
5421
6831
  minTime = 100,
5422
6832
  maxTime = 800,
5423
- time = utils.clamp(clickTime || 200, minTime, maxTime),
6833
+ time = utils$1.clamp(clickTime || 200, minTime, maxTime),
5424
6834
  k = (time - minTime) / (maxTime - minTime),
5425
6835
  scale = minScale + k * (maxScale - minScale);
5426
6836
  return 1 + scale * zoomScaleMultiplier;
@@ -5647,7 +7057,7 @@
5647
7057
  rows = 0;
5648
7058
  // self.hide(); // clean up if panel is already open
5649
7059
  el.empty(); // clean up if panel is already open
5650
- utils.forEachProperty(rec, function(v, k) {
7060
+ utils$1.forEachProperty(rec, function(v, k) {
5651
7061
  var type;
5652
7062
  // missing GeoJSON fields are set to undefined on import; skip these
5653
7063
  if (v !== undefined) {
@@ -5675,7 +7085,7 @@
5675
7085
  // Some individual features can have undefined values for some or all of
5676
7086
  // their data properties (properties are set to undefined when an input JSON file
5677
7087
  // has inconsistent fields, or after force-merging layers with inconsistent fields).
5678
- el.html(utils.format('<div class="note">This %s is missing attribute data.</div>',
7088
+ el.html(utils$1.format('<div class="note">This %s is missing attribute data.</div>',
5679
7089
  table && table.getFields().length > 0 ? 'feature': 'layer'));
5680
7090
  }
5681
7091
  }
@@ -5686,7 +7096,7 @@
5686
7096
  var str = formatInspectorValue(val, type);
5687
7097
  var cell = El('tr')
5688
7098
  .appendTo(table)
5689
- .html(utils.format(rowHtml, key, utils.htmlEscape(str)))
7099
+ .html(utils$1.format(rowHtml, key, utils$1.htmlEscape(str)))
5690
7100
  .findChild('.value');
5691
7101
  setFieldClass(cell, val, type);
5692
7102
  if (editable) {
@@ -5695,7 +7105,7 @@
5695
7105
  }
5696
7106
 
5697
7107
  function setFieldClass(el, val, type) {
5698
- var isNum = type ? type == 'number' : utils.isNumber(val);
7108
+ var isNum = type ? type == 'number' : utils$1.isNumber(val);
5699
7109
  var isNully = val === undefined || val === null || val !== val;
5700
7110
  var isEmpty = val === '';
5701
7111
  el.classed('num-field', isNum);
@@ -5735,7 +7145,7 @@
5735
7145
  function formatInspectorValue(val, type) {
5736
7146
  var str;
5737
7147
  if (type == 'date') {
5738
- str = utils.formatDateISO(val);
7148
+ str = utils$1.formatDateISO(val);
5739
7149
  } else if (type == 'object') {
5740
7150
  str = val ? JSON.stringify(val) : "";
5741
7151
  } else {
@@ -5934,7 +7344,7 @@
5934
7344
  // handle either numeric strings or numbers in fields
5935
7345
  function applyDelta(rec, key, delta) {
5936
7346
  var currVal = rec[key];
5937
- var isString = utils.isString(currVal);
7347
+ var isString = utils$1.isString(currVal);
5938
7348
  var newVal = (+currVal + delta) || 0;
5939
7349
  rec[key] = isString ? String(newVal) : newVal;
5940
7350
  }
@@ -5962,7 +7372,7 @@
5962
7372
  hit.on('drag', function(e) {
5963
7373
  if (!active(e)) return;
5964
7374
  if (e.id != activeId) {
5965
- error("Mismatched hit ids:", e.id, activeId);
7375
+ error$1("Mismatched hit ids:", e.id, activeId);
5966
7376
  }
5967
7377
  var scale = ext.getSymbolScale() || 1;
5968
7378
  var textNode;
@@ -6112,10 +7522,15 @@
6112
7522
  }
6113
7523
  }
6114
7524
 
7525
+ var HOVER_THRESHOLD = 8;
7526
+ var MIDPOINT_THRESHOLD = 12;
7527
+
7528
+
6115
7529
  function initVertexDragging(gui, ext, hit) {
6116
7530
  var activeShapeId = -1;
6117
7531
  var draggedVertexIds = null;
6118
7532
  var selectedVertexIds = null;
7533
+ var activeMidpoint; // {point, segment}
6119
7534
 
6120
7535
  function active(e) {
6121
7536
  return e.id > -1 && gui.interaction.getMode() == 'vertices';
@@ -6146,16 +7561,34 @@
6146
7561
  var p2 = target.arcs.getVertex2(nearestIds[0]);
6147
7562
  var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
6148
7563
  var pixelDist = dist / ext.getPixelSize();
6149
- if (pixelDist > 5) {
7564
+ if (pixelDist > HOVER_THRESHOLD) {
6150
7565
  draggedVertexIds = null;
6151
7566
  return null;
6152
7567
  }
6153
7568
  return nearestIds;
6154
7569
  }
6155
7570
 
7571
+ function insertMidpoint(v) {
7572
+ var target = hit.getHitTarget();
7573
+ internal.insertVertex(target.arcs, v.i, v.point);
7574
+ }
7575
+
6156
7576
  hit.on('dragstart', function(e) {
6157
7577
  if (!active(e)) return;
6158
- draggedVertexIds = findDraggableVertices(e);
7578
+ if (activeMidpoint) {
7579
+ insertMidpoint(activeMidpoint);
7580
+ draggedVertexIds = [activeMidpoint.i];
7581
+ // TODO: combine vertex insertion undo/redo actions with
7582
+ // vertex_dragend undo/redo actions
7583
+ gui.dispatchEvent('vertex_insert', {
7584
+ FID: activeShapeId,
7585
+ vertex_id: activeMidpoint.i,
7586
+ coordinates: activeMidpoint.point
7587
+ });
7588
+ activeMidpoint = null;
7589
+ } else {
7590
+ draggedVertexIds = findDraggableVertices(e);
7591
+ }
6159
7592
  if (!draggedVertexIds) return;
6160
7593
  setHoverVertex(draggedVertexIds[0]);
6161
7594
  activeShapeId = e.id;
@@ -6196,6 +7629,7 @@
6196
7629
 
6197
7630
  // highlight hit vertex in path edit mode
6198
7631
  hit.on('hover', function(e) {
7632
+ activeMidpoint = null;
6199
7633
  if (!active(e) || draggedVertexIds) return; // no hover effect while dragging
6200
7634
  var vertexIds = findDraggableVertices(e);
6201
7635
  if (vertexIds) {
@@ -6203,13 +7637,51 @@
6203
7637
  return;
6204
7638
  }
6205
7639
  var target = hit.getHitTarget();
7640
+ // vertex insertion doesn't work yet with simplification applied
7641
+ if (!target.arcs.isFlat()) return;
6206
7642
  var shp = target.layer.shapes[e.id];
6207
7643
  var p = ext.translatePixelCoords(e.x, e.y);
6208
- var o = internal.findInsertionPoint(p, shp, target.arcs, ext.getPixelSize());
6209
- console.log('*', o, p);
6210
- clearHoverVertex();
7644
+ var midpoint = findNearestMidpoint(p, shp, target.arcs);
7645
+ if (midpoint && midpoint.distance / ext.getPixelSize() < MIDPOINT_THRESHOLD) {
7646
+ hit.setHoverVertex(midpoint.point);
7647
+ activeMidpoint = midpoint;
7648
+ } else {
7649
+ clearHoverVertex();
7650
+ }
6211
7651
  }, null, 100);
7652
+ }
7653
+
6212
7654
 
7655
+ // Given a location @p (e.g. corresponding to the mouse pointer location),
7656
+ // find the midpoint of two vertices on @shp suitable for inserting a new vertex,
7657
+ // but only if:
7658
+ // 1. point @p is closer to the midpoint than either adjacent vertex
7659
+ // 2. the segment containing @p is longer than a minimum distance in pixels.
7660
+ //
7661
+ function findNearestMidpoint(p, shp, arcs) {
7662
+ // var v1 = internal.findNearestVertex(p[0], p[1], shp, arcs);
7663
+ // var v0 = internal.findAdjacentVertex(v1, shp, arcs, -1);
7664
+ // var v2 = internal.findAdjacentVertex(v1, shp, arcs, 1);
7665
+ var minDist = Infinity, v;
7666
+ internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
7667
+ var x1 = xx[i],
7668
+ y1 = yy[i],
7669
+ x2 = xx[j],
7670
+ y2 = yy[j],
7671
+ cx = (x1 + x2) / 2,
7672
+ cy = (y1 + y2) / 2,
7673
+ dist = geom.distance2D(cx, cy, p[0], p[1]);
7674
+ if (dist < minDist) {
7675
+ minDist = dist;
7676
+ v = {
7677
+ i: (i < j ? i : j) + 1, // insertion point
7678
+ segment: [i, j],
7679
+ point: [cx, cy],
7680
+ distance: dist
7681
+ };
7682
+ }
7683
+ });
7684
+ return v || null;
6213
7685
  }
6214
7686
 
6215
7687
  function initInteractiveEditing(gui, ext, hit) {
@@ -6252,7 +7724,7 @@
6252
7724
  },
6253
7725
  referenceStyle = { // outline style for reference layers
6254
7726
  type: 'outline',
6255
- strokeColors: [null, '#86c927'],
7727
+ strokeColors: [null, '#78c110'], // upped saturation from #86c927
6256
7728
  strokeWidth: 0.85,
6257
7729
  dotColor: "#73ba20",
6258
7730
  dotSize: 1
@@ -6333,7 +7805,7 @@
6333
7805
  }
6334
7806
 
6335
7807
  function getDefaultStyle(lyr, baseStyle) {
6336
- var style = utils.extend({}, baseStyle);
7808
+ var style = utils$1.extend({}, baseStyle);
6337
7809
  // reduce the dot size of large point layers
6338
7810
  if (lyr.geometry_type == 'point' && style.dotSize > 0) {
6339
7811
  style.dotSize *= getDotScale$1(lyr);
@@ -6399,7 +7871,7 @@
6399
7871
  var topId = o.id; // pinned id (if pinned) or hover id
6400
7872
  var topIdx = -1;
6401
7873
  var styler = function(style, i) {
6402
- utils.extend(style, i === topIdx ? topStyle: baseStyle);
7874
+ utils$1.extend(style, i === topIdx ? topStyle: baseStyle);
6403
7875
  // kludge to show vertices when editing path shapes
6404
7876
  if (o.mode == 'vertices') {
6405
7877
  style.vertices = true;
@@ -6518,7 +7990,7 @@
6518
7990
  if (lyr.geometry_type == 'point') {
6519
7991
  return fields.indexOf('r') > -1; // require 'r' field for point symbols
6520
7992
  }
6521
- return utils.difference(fields, ['opacity', 'class']).length > 0;
7993
+ return utils$1.difference(fields, ['opacity', 'class']).length > 0;
6522
7994
  }
6523
7995
 
6524
7996
 
@@ -6675,7 +8147,7 @@
6675
8147
  }
6676
8148
 
6677
8149
  function maxAbs() {
6678
- return Math.max.apply(null, utils.toArray(arguments).map(Math.abs));
8150
+ return Math.max.apply(null, utils$1.toArray(arguments).map(Math.abs));
6679
8151
  }
6680
8152
 
6681
8153
  function limitScale(scale) {
@@ -6729,7 +8201,7 @@
6729
8201
  }
6730
8202
  }
6731
8203
 
6732
- utils.inherit(MapExtent, EventDispatcher);
8204
+ utils$1.inherit(MapExtent, EventDispatcher);
6733
8205
 
6734
8206
  // TODO: consider moving this upstream
6735
8207
  function getArcsForRendering(obj, ext) {
@@ -6878,7 +8350,7 @@
6878
8350
  var t = getScaledTransform(_ext);
6879
8351
  var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
6880
8352
  var color = style.strokeColor || 'black';
6881
- var radius2 = radius * 2;
8353
+ var radius2 = radius * 1.7;
6882
8354
  _ctx.beginPath();
6883
8355
  _ctx.fillStyle = color;
6884
8356
  for (var i=0; i<shapes.length; i++) {
@@ -6919,7 +8391,7 @@
6919
8391
  key = getStyleKey(style);
6920
8392
  if (key in styleIndex === false) {
6921
8393
  styleIndex[key] = {
6922
- style: utils.defaults({}, style),
8394
+ style: utils$1.defaults({}, style),
6923
8395
  shapes: []
6924
8396
  };
6925
8397
  }
@@ -7259,7 +8731,8 @@
7259
8731
  if (style.strokeWidth > 0) {
7260
8732
  strokeWidth = style.strokeWidth;
7261
8733
  if (pixRatio > 1) {
7262
- // bump up thin lines on retina, but not to more than 1px (too slow)
8734
+ // bump up thin lines on retina, but not to more than 1px
8735
+ // (tests on Chrome showed much faster rendering of 1px lines)
7263
8736
  strokeWidth = strokeWidth < 1 ? 1 : strokeWidth * pixRatio;
7264
8737
  }
7265
8738
  ctx.lineCap = 'round';
@@ -7393,7 +8866,7 @@
7393
8866
  var frame = ext.getFrame(); // frame should be set if we're rendering a furniture layer
7394
8867
  var obj = internal.getEmptyLayerForSVG(lyr, {});
7395
8868
  if (!frame) {
7396
- stop('Missing map frame data');
8869
+ stop$1('Missing map frame data');
7397
8870
  }
7398
8871
  obj.properties.transform = getSvgFurnitureTransform(ext);
7399
8872
  obj.properties.class = 'mapshaper-svg-furniture';
@@ -7421,7 +8894,7 @@
7421
8894
  var html = '';
7422
8895
  // generate a unique id so layer can be identified when symbols are repositioned
7423
8896
  // use it as a class name to avoid id collisions
7424
- var id = utils.getUniqueName();
8897
+ var id = utils$1.getUniqueName();
7425
8898
  var classNames = [id, 'mapshaper-svg-layer', 'mapshaper-' + type + '-layer'];
7426
8899
  g.setAttribute('class', classNames.join(' '));
7427
8900
  target.svg_id = id;
@@ -7872,7 +9345,7 @@
7872
9345
  }
7873
9346
 
7874
9347
  if (obj.tabular) {
7875
- utils.extend(obj, getDisplayLayerForTable(layer.data));
9348
+ utils$1.extend(obj, getDisplayLayerForTable(layer.data));
7876
9349
  }
7877
9350
 
7878
9351
  // dynamic reprojection (arcs were already reprojected above)
@@ -7930,7 +9403,7 @@
7930
9403
  return ids;
7931
9404
  }
7932
9405
 
7933
- utils.inherit(MshpMap, EventDispatcher);
9406
+ utils$1.inherit(MshpMap, EventDispatcher);
7934
9407
 
7935
9408
  function MshpMap(gui) {
7936
9409
  var opts = gui.options,
@@ -8024,7 +9497,7 @@
8024
9497
  this.setDisplayCRS = function(crs) {
8025
9498
  // TODO: update bounds of frame layer, if there is a frame layer
8026
9499
  var oldCRS = this.getDisplayCRS();
8027
- var newCRS = utils.isString(crs) ? internal.getCRS(crs) : crs;
9500
+ var newCRS = utils$1.isString(crs) ? internal.getCRS(crs) : crs;
8028
9501
  // TODO: handle case that old and new CRS are the same
8029
9502
  _dynamicCRS = newCRS;
8030
9503
  if (!_activeLyr) return; // stop here if no layers have been selected
@@ -8152,7 +9625,7 @@
8152
9625
  function updateOverlayLayer(e) {
8153
9626
  var style = getOverlayStyle(_activeLyr.layer, e);
8154
9627
  if (style) {
8155
- _overlayLyr = utils.defaults({
9628
+ _overlayLyr = utils$1.defaults({
8156
9629
  layer: filterLayerByIds(_activeLyr.layer, style.ids),
8157
9630
  style: style
8158
9631
  }, _activeLyr);
@@ -8317,7 +9790,7 @@
8317
9790
  // kludge to hide ghosted layers when reference layers are present
8318
9791
  // TODO: consider never showing ghosted layers (which appear after
8319
9792
  // commands like dissolve and filter).
8320
- mapLayer.style = utils.defaults({
9793
+ mapLayer.style = utils$1.defaults({
8321
9794
  strokeColors: [null, mapLayer.style.strokeColors[1]]
8322
9795
  }, mapLayer.style);
8323
9796
  }
@@ -8373,7 +9846,7 @@
8373
9846
 
8374
9847
  function GuiInstance(container, opts) {
8375
9848
  var gui = new ModeSwitcher();
8376
- opts = utils.extend({
9849
+ opts = utils$1.extend({
8377
9850
  // defaults
8378
9851
  homeControl: true,
8379
9852
  zoomControl: true,