mapshaper 0.6.41 → 0.6.42

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/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.41";
3
+ var VERSION = "0.6.42";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -1267,6 +1267,26 @@
1267
1267
  _stop = stop;
1268
1268
  }
1269
1269
 
1270
+ // get detailed error information from error stack (if available)
1271
+ // Example stack string (Node.js):
1272
+ /*
1273
+ /Users/someuser/somescript.js:226
1274
+ opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc
1275
+ ^
1276
+
1277
+ SyntaxError: missing ) after argument list
1278
+ at internalCompileFunction (node:internal/vm:73:18)
1279
+ at wrapSafe (node:internal/modules/cjs/loader:1149:20)
1280
+ at Module._compile (node:internal/modules/cjs/loader:1190:27)
1281
+ ...
1282
+ */
1283
+ function getErrorDetail(e) {
1284
+ var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : [];
1285
+ if (parts.length > 1 || true) {
1286
+ return '\nError details:\n' + parts[0];
1287
+ }
1288
+ return '';
1289
+ }
1270
1290
 
1271
1291
  // print a message to stdout
1272
1292
  function print() {
@@ -1389,6 +1409,7 @@
1389
1409
  interrupt: interrupt,
1390
1410
  message: message,
1391
1411
  setLoggingFunctions: setLoggingFunctions,
1412
+ getErrorDetail: getErrorDetail,
1392
1413
  print: print,
1393
1414
  verbose: verbose,
1394
1415
  debug: debug,
@@ -6359,9 +6380,10 @@
6359
6380
  function mergeDatasets(arr) {
6360
6381
  var arcSources = [],
6361
6382
  arcCount = 0,
6362
- mergedLayers = [],
6363
- mergedInfo = {},
6364
- mergedArcs;
6383
+ merged = {
6384
+ info: {},
6385
+ layers: []
6386
+ };
6365
6387
 
6366
6388
  // Error if incompatible CRS
6367
6389
  requireDatasetsHaveCompatibleCRS(arr);
@@ -6372,38 +6394,35 @@
6372
6394
  arcSources.push(dataset.arcs);
6373
6395
  }
6374
6396
 
6375
- mergeDatasetInfo(mergedInfo, dataset);
6397
+ mergeDatasetInfo$1(merged, dataset);
6376
6398
  dataset.layers.forEach(function(lyr) {
6377
6399
  if (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') {
6378
6400
  forEachArcId(lyr.shapes, function(id) {
6379
6401
  return id < 0 ? id - arcCount : id + arcCount;
6380
6402
  });
6381
6403
  }
6382
- mergedLayers.push(lyr);
6404
+ merged.layers.push(lyr);
6383
6405
  });
6384
6406
  arcCount += n;
6385
6407
  });
6386
6408
 
6387
6409
  if (arcSources.length > 0) {
6388
- mergedArcs = mergeArcs(arcSources);
6389
- if (mergedArcs.size() != arcCount) {
6410
+ merged.arcs = mergeArcs(arcSources);
6411
+ if (merged.arcs.size() != arcCount) {
6390
6412
  error("[mergeDatasets()] Arc indexing error");
6391
6413
  }
6392
6414
  }
6393
6415
 
6394
- return {
6395
- info: mergedInfo,
6396
- arcs: mergedArcs,
6397
- layers: mergedLayers
6398
- };
6416
+ return merged;
6399
6417
  }
6400
6418
 
6401
- function mergeDatasetInfo(merged, dataset) {
6402
- var info = dataset.info || {};
6403
- merged.input_files = utils.uniq((merged.input_files || []).concat(info.input_files || []));
6404
- merged.input_formats = utils.uniq((merged.input_formats || []).concat(info.input_formats || []));
6419
+ function mergeDatasetInfo$1(merged, dataset) {
6420
+ var src = dataset.info || {};
6421
+ var dest = merged.info || (merged.info = {});
6422
+ dest.input_files = utils.uniq((dest.input_files || []).concat(src.input_files || []));
6423
+ dest.input_formats = utils.uniq((dest.input_formats || []).concat(src.input_formats || []));
6405
6424
  // merge other info properties (e.g. input_geojson_crs, input_delimiter, prj, crs)
6406
- utils.defaults(merged, info);
6425
+ utils.defaults(dest, src);
6407
6426
  }
6408
6427
 
6409
6428
  function mergeArcs(arr) {
@@ -6450,6 +6469,7 @@
6450
6469
  mergeDatasetsForExport: mergeDatasetsForExport,
6451
6470
  mergeCommandTargets: mergeCommandTargets,
6452
6471
  mergeDatasets: mergeDatasets,
6472
+ mergeDatasetInfo: mergeDatasetInfo$1,
6453
6473
  mergeArcs: mergeArcs
6454
6474
  });
6455
6475
 
@@ -6900,6 +6920,18 @@
6900
6920
  });
6901
6921
  }
6902
6922
 
6923
+ // dest: destination dataset
6924
+ // src: source dataset
6925
+ function mergeDatasetInfo(dest, src) {
6926
+ var srcInfo = src.info || {};
6927
+ var destInfo = dest.info || (dest.info = {});
6928
+ destInfo.input_files = utils.uniq((destInfo.input_files || []).concat(srcInfo.input_files || []));
6929
+ destInfo.input_formats = utils.uniq((destInfo.input_formats || []).concat(srcInfo.input_formats || []));
6930
+ // merge other info properties (e.g. input_geojson_crs, input_delimiter, prj, crs)
6931
+ utils.defaults(destInfo, srcInfo);
6932
+ }
6933
+
6934
+
6903
6935
  function splitApartLayers(dataset, layers) {
6904
6936
  var datasets = [];
6905
6937
  dataset.layers = dataset.layers.filter(function(lyr) {
@@ -7064,6 +7096,7 @@
7064
7096
  var DatasetUtils = /*#__PURE__*/Object.freeze({
7065
7097
  __proto__: null,
7066
7098
  splitDataset: splitDataset,
7099
+ mergeDatasetInfo: mergeDatasetInfo,
7067
7100
  splitApartLayers: splitApartLayers,
7068
7101
  copyDataset: copyDataset,
7069
7102
  copyDatasetForExport: copyDatasetForExport,
@@ -11205,20 +11238,43 @@
11205
11238
  return dest;
11206
11239
  };
11207
11240
 
11241
+ // Receives a directory path, in which the final subdirectory may include the
11242
+ // "*" wildcard, e.g. '.' 'data' '*' 'data/*' '2023-*'
11243
+ // Returns an array of expanded directory names
11244
+ // TODO: add support for wildcards in other subdirectories
11245
+ cli.expandDirectoryName = function(name) {
11246
+ var info = parseLocalPath(name);
11247
+ // final directory name is parsed as info.filename
11248
+ if (!info.filename.includes('*')) {
11249
+ return [name];
11250
+ }
11251
+ var rxp = utils.wildcardToRegExp(info.filename);
11252
+ var dirs = [];
11253
+ require$1('fs').readdirSync(info.directory || '.').forEach(function(item) {
11254
+ var path = info.directory ? require$1('path').join(info.directory, item) : item;
11255
+ if (rxp.test(item) && cli.isDirectory(path)) {
11256
+ dirs.push(path);
11257
+ }
11258
+ });
11259
+ return dirs;
11260
+ };
11261
+
11208
11262
  // Expand any "*" wild cards in file name
11209
11263
  // (For the Windows command line; unix shells do this automatically)
11210
11264
  cli.expandFileName = function(name) {
11211
11265
  var info = parseLocalPath(name),
11212
11266
  rxp = utils.wildcardToRegExp(info.filename),
11213
- dir = info.directory || '.',
11267
+ dirs = cli.expandDirectoryName(info.directory || '.'),
11214
11268
  files = [];
11215
11269
 
11216
11270
  try {
11217
- require$1('fs').readdirSync(dir).forEach(function(item) {
11218
- var path = require$1('path').join(dir, item);
11219
- if (rxp.test(item) && cli.isFile(path)) {
11220
- files.push(path);
11221
- }
11271
+ dirs.forEach(function(dir) {
11272
+ require$1('fs').readdirSync(dir).forEach(function(item) {
11273
+ var path = require$1('path').join(dir, item);
11274
+ if (rxp.test(item) && cli.isFile(path)) {
11275
+ files.push(path);
11276
+ }
11277
+ });
11222
11278
  });
11223
11279
  } catch(e) {}
11224
11280
 
@@ -28239,20 +28295,23 @@ ${svg}
28239
28295
  };
28240
28296
 
28241
28297
  this.setDefaultTarget = function(layers, dataset) {
28242
- if (datasets.indexOf(dataset) == -1) {
28243
- datasets.push(dataset);
28244
- }
28245
- defaultTargets = [{
28298
+ this.setDefaultTargets([{
28246
28299
  // Copy layers array, in case layers is a reference to dataset.layers.
28247
28300
  // This prevents layers that are added to the dataset inside a command from
28248
28301
  // being added to the next command's target, e.g. debugging layers added
28249
28302
  // by '-join unmatched unjoined'.
28250
28303
  layers: layers.concat(),
28251
28304
  dataset: dataset
28252
- }];
28305
+ }]);
28253
28306
  };
28254
28307
 
28308
+ // arr: array of target objects {layers:[], dataset:{}}
28255
28309
  this.setDefaultTargets = function(arr) {
28310
+ arr.forEach(function(target) {
28311
+ if (datasets.indexOf(target.dataset) == -1) {
28312
+ datasets.push(target.dataset);
28313
+ }
28314
+ });
28256
28315
  defaultTargets = arr;
28257
28316
  };
28258
28317
 
@@ -28345,6 +28404,30 @@ ${svg}
28345
28404
  stashVar('input_files', job.input_files);
28346
28405
  }
28347
28406
 
28407
+ // Apply a command to an array of target layers
28408
+ function applyCommandToEachLayer(func, targetLayers) {
28409
+ var args = utils.toArray(arguments).slice(2);
28410
+ return targetLayers.reduce(function(memo, lyr) {
28411
+ var result = func.apply(null, [lyr].concat(args));
28412
+ if (utils.isArray(result)) { // some commands return an array of layers
28413
+ memo = memo.concat(result);
28414
+ } else if (result) { // assuming result is a layer
28415
+ memo.push(result);
28416
+ }
28417
+ return memo;
28418
+ }, []);
28419
+ }
28420
+
28421
+ function applyCommandToEachTarget(func, targets) {
28422
+ var args = utils.toArray(arguments).slice(2);
28423
+ targets.forEach(function(target) {
28424
+ var result = func.apply(null, [target].concat(args));
28425
+ if (result) {
28426
+ error('Unexpected output from command');
28427
+ }
28428
+ });
28429
+ }
28430
+
28348
28431
  cmd.addShape = addShape;
28349
28432
 
28350
28433
  function addShape(targetLayers, targetDataset, opts) {
@@ -36290,6 +36373,7 @@ ${svg}
36290
36373
  var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
36291
36374
  var targets = catalog.findCommandTargets(opts.target || '*');
36292
36375
  var target = targets[0];
36376
+ var output;
36293
36377
  if (!target) {
36294
36378
  stop('Missing a target');
36295
36379
  }
@@ -36300,12 +36384,34 @@ ${svg}
36300
36384
  stop("Targetting layers from multiple datasets is not supported");
36301
36385
  }
36302
36386
  if (targetType == 'layer') {
36303
- cmdDefn.command(target.layers[0], target.dataset, opts.options);
36387
+ output = cmdDefn.command(target.layers[0], target.dataset, opts.options);
36304
36388
  } else if (targetType == 'layers') {
36305
- cmdDefn.command(target.layers, target.dataset, opts.options);
36389
+ output = cmdDefn.command(target.layers, target.dataset, opts.options);
36390
+ }
36391
+ if (output) {
36392
+ integrateOutput(output, target, catalog, opts);
36306
36393
  }
36307
36394
  };
36308
36395
 
36396
+ // TODO: remove restrictions on output data
36397
+ function integrateOutput(output, input, catalog, opts) {
36398
+ if (!output.dataset || !output.layers || output.layers.length > 0 === false) {
36399
+ stop('Invalid command output');
36400
+ }
36401
+ if (output.dataset == input.dataset) {
36402
+ stop('External commands are not currently allowed to modify input datasets');
36403
+ }
36404
+ if (output.dataset.layers.length != output.layers.length) {
36405
+ stop('Currently not supported: targetting a subset of output layers');
36406
+ }
36407
+ if (!opts.no_replace) {
36408
+ input.layers.forEach(function(lyr) {
36409
+ catalog.deleteLayer(lyr, input.dataset);
36410
+ });
36411
+ }
36412
+ catalog.addDataset(output.dataset);
36413
+ }
36414
+
36309
36415
  function parseExternalCommand(name, cmdDefn, tokens) {
36310
36416
  var parser = new CommandParser();
36311
36417
  var cmd = parser.command(name);
@@ -40720,7 +40826,8 @@ ${svg}
40720
40826
  function makeCircleCoords(center, opts) {
40721
40827
  var margin = opts.cell_margin > 0 ? opts.cell_margin : 1e-6;
40722
40828
  var radius = opts.interval / 2 * (1 - margin);
40723
- return getPointBufferCoordinates(center, radius, 20, getPlanarSegmentEndpoint);
40829
+ var vertices = opts.vertices || 20;
40830
+ return getPointBufferCoordinates(center, radius, vertices, getPlanarSegmentEndpoint);
40724
40831
  }
40725
40832
 
40726
40833
  // Returns a function that receives a cell index and returns indices of points
@@ -40731,12 +40838,15 @@ ${svg}
40731
40838
  var bboxIndex = new Flatbush(points.length);
40732
40839
  var empty = [];
40733
40840
  points.forEach(function(p) {
40841
+ var bbox = getPointBounds(p, radius);
40734
40842
  addPointToGridIndex(p, gridIndex, grid);
40735
- bboxIndex.add.apply(bboxIndex, getPointBounds(p, radius));
40843
+ bboxIndex.add.apply(bboxIndex, bbox);
40736
40844
  });
40737
40845
  bboxIndex.finish();
40738
40846
  return function(i) {
40739
- if (!gridIndex.hasId(i)) return empty;
40847
+ if (!gridIndex.hasId(i)) {
40848
+ return empty;
40849
+ }
40740
40850
  var bbox = grid.idxToBBox(i);
40741
40851
  var indices = bboxIndex.search.apply(bboxIndex, bbox);
40742
40852
  return indices;
@@ -40870,6 +40980,7 @@ ${svg}
40870
40980
  calcWeights: calcWeights,
40871
40981
  twoCircleIntersection: twoCircleIntersection,
40872
40982
  makeCellPolygon: makeCellPolygon,
40983
+ makeCircleCoords: makeCircleCoords,
40873
40984
  getPointIndex: getPointIndex,
40874
40985
  getAlignedGridBounds: getAlignedGridBounds,
40875
40986
  getCenteredGridBounds: getCenteredGridBounds,
@@ -41198,8 +41309,7 @@ ${svg}
41198
41309
  }
41199
41310
  }
41200
41311
  } catch(e) {
41201
- // stop(e);
41202
- stop('Unable to load external module:', e.message);
41312
+ stop('Unable to load external module:', e.message, getErrorDetail(e));
41203
41313
  }
41204
41314
  if (moduleName || opts.alias) {
41205
41315
  defs[opts.alias || moduleName] = mod;
@@ -42230,9 +42340,10 @@ ${svg}
42230
42340
  }
42231
42341
  };
42232
42342
 
42233
- cmd.snap = function(dataset, opts) {
42343
+ cmd.snap = function(target, opts) {
42234
42344
  var interval = 0;
42235
42345
  var snapCount = 0;
42346
+ var dataset = target.dataset;
42236
42347
  var arcs = dataset.arcs;
42237
42348
  var arcBounds = arcs && arcs.getBounds();
42238
42349
  if (!arcBounds || !arcBounds.hasBounds()) {
@@ -43367,7 +43478,7 @@ ${svg}
43367
43478
  function commandAcceptsMultipleTargetDatasets(name) {
43368
43479
  return name == 'rotate' || name == 'info' || name == 'proj' || name == 'require' ||
43369
43480
  name == 'drop' || name == 'target' || name == 'if' || name == 'elif' ||
43370
- name == 'else' || name == 'endif' || name == 'run' || name == 'i';
43481
+ name == 'else' || name == 'endif' || name == 'run' || name == 'i' || name == 'snap';
43371
43482
  }
43372
43483
 
43373
43484
  function commandAcceptsEmptyTarget(name) {
@@ -43449,6 +43560,10 @@ ${svg}
43449
43560
  source = findCommandSource(convertSourceName(opts.source, targets), job.catalog, opts);
43450
43561
  }
43451
43562
 
43563
+ // identify command target/input (for postprocessing)
43564
+ // TODO: support commands with multiple target datasets
43565
+ // target = name == 'i' ? null : targets[0];
43566
+
43452
43567
  if (name == 'add-shape') {
43453
43568
  if (!targetDataset) {
43454
43569
  targetDataset = {info: {}, layers: []};
@@ -43556,6 +43671,9 @@ ${svg}
43556
43671
  } else if (name == 'graticule') {
43557
43672
  job.catalog.addDataset(cmd.graticule(targetDataset, opts));
43558
43673
 
43674
+ } else if (name == 'grid') {
43675
+ outputDataset = cmd.polygonGrid(targetLayers, targetDataset, opts);
43676
+
43559
43677
  } else if (name == 'help') {
43560
43678
  // placing help command here to handle errors from invalid command names
43561
43679
  cmd.printHelp(command.options);
@@ -43627,9 +43745,6 @@ ${svg}
43627
43745
  } else if (name == 'point-to-grid') {
43628
43746
  outputLayers = cmd.pointToGrid(targetLayers, targetDataset, opts);
43629
43747
 
43630
- } else if (name == 'grid') {
43631
- outputDataset = cmd.polygonGrid(targetLayers, targetDataset, opts);
43632
-
43633
43748
  } else if (name == 'points') {
43634
43749
  outputLayers = applyCommandToEachLayer(cmd.createPointLayer, targetLayers, targetDataset, opts);
43635
43750
 
@@ -43693,7 +43808,8 @@ ${svg}
43693
43808
  outputLayers = cmd.sliceLayers(targetLayers, source, targetDataset, opts);
43694
43809
 
43695
43810
  } else if (name == 'snap') {
43696
- cmd.snap(targetDataset, opts);
43811
+ // cmd.snap(targetDataset, opts);
43812
+ applyCommandToEachTarget(targets, opts);
43697
43813
 
43698
43814
  } else if (name == 'sort') {
43699
43815
  applyCommandToEachLayer(cmd.sortFeatures, targetLayers, arcs, opts);
@@ -43784,9 +43900,12 @@ ${svg}
43784
43900
 
43785
43901
  // delete arcs if no longer needed (e.g. after -points command)
43786
43902
  // (after output layers have been integrated)
43903
+ // TODO: be more selective (e.g. -i command doesn't need cleanup)
43904
+ // or: detect if arcs have been changed
43787
43905
  if (targetDataset) {
43788
43906
  cleanupArcs(targetDataset);
43789
43907
  }
43908
+
43790
43909
  } catch(e) {
43791
43910
  return done(e);
43792
43911
  }
@@ -43808,20 +43927,6 @@ ${svg}
43808
43927
  });
43809
43928
  }
43810
43929
 
43811
- // Apply a command to an array of target layers
43812
- function applyCommandToEachLayer(func, targetLayers) {
43813
- var args = utils.toArray(arguments).slice(2);
43814
- return targetLayers.reduce(function(memo, lyr) {
43815
- var result = func.apply(null, [lyr].concat(args));
43816
- if (utils.isArray(result)) { // some commands return an array of layers
43817
- memo = memo.concat(result);
43818
- } else if (result) { // assuming result is a layer
43819
- memo.push(result);
43820
- }
43821
- return memo;
43822
- }, []);
43823
- }
43824
-
43825
43930
  // Parse command line args into commands and run them
43826
43931
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
43827
43932
  // function(argv[, input], callback)
@@ -44465,6 +44570,7 @@ ${svg}
44465
44570
  editArcs,
44466
44571
  GeoJSONReader,
44467
44572
  Heap,
44573
+ IdLookupIndex,
44468
44574
  NodeCollection,
44469
44575
  parseDMS,
44470
44576
  formatDMS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.41",
3
+ "version": "0.6.42",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/index.html CHANGED
@@ -172,7 +172,7 @@ precision=0.001. Click to see all options.</div></div></div></a>
172
172
 
173
173
  <!-- <div class="cancel-btn btn dialog-btn">Cancel</div> -->
174
174
  <div class="save-btn btn dialog-btn">Export</div>
175
- <span id="save-preference"><input type="checkbox"/>choose directory</span>
175
+ <span id="save-preference" class="inline-checkbox" style="display: none;"><input type="checkbox"/>choose directory</span>
176
176
 
177
177
  </div>
178
178
  </div>
@@ -1125,21 +1125,26 @@
1125
1125
  var self = {}, html = '';
1126
1126
  var _cancel, _close;
1127
1127
  var warningRxp = /^Warning: /;
1128
- var el = El('div').appendTo('body').addClass('error-wrapper');
1129
- var infoBox = El('div').appendTo(el).addClass('error-box info-box selectable');
1128
+ var el = El('div').appendTo('body').addClass('alert-wrapper');
1129
+ var infoBox = El('div').appendTo(el).addClass('alert-box info-box selectable');
1130
+ El('div').appendTo(infoBox).addClass('close2-btn').on('click', function() {
1131
+ if (_cancel) _cancel();
1132
+ self.close();
1133
+ });
1134
+ var container = El('div').appendTo(infoBox);
1130
1135
  if (!title && warningRxp.test(msg)) {
1131
1136
  title = 'Warning';
1132
1137
  msg = msg.replace(warningRxp, '');
1133
1138
  }
1134
1139
  if (title) {
1135
- html += `<div class="error-title">${title}</div>`;
1140
+ El('div').addClass('alert-title').text(title).appendTo(container);
1136
1141
  }
1137
- html += `<p class="error-message">${msg}</p>`;
1138
- El('div').appendTo(infoBox).addClass('close2-btn').on('click', function() {
1139
- if (_cancel) _cancel();
1140
- self.close();
1141
- });
1142
- El('div').appendTo(infoBox).addClass('error-content').html(html);
1142
+ var content = El('div').appendTo(infoBox);
1143
+ if (msg) {
1144
+ content.html(`<p class="error-message">${msg}</p>`);
1145
+ }
1146
+
1147
+ self.container = function() { return content; };
1143
1148
 
1144
1149
  self.onCancel = function(cb) {
1145
1150
  _cancel = cb;
@@ -4023,10 +4028,10 @@
4023
4028
 
4024
4029
  function render() {
4025
4030
  renderLayerList();
4026
- renderFileList();
4031
+ renderSourceFileList();
4027
4032
  }
4028
4033
 
4029
- function renderFileList() {
4034
+ function renderSourceFileList() {
4030
4035
  var list = el.findChild('.file-list');
4031
4036
  var files = [];
4032
4037
  list.empty();
@@ -5064,6 +5069,26 @@
5064
5069
  _stop = stop;
5065
5070
  }
5066
5071
 
5072
+ // get detailed error information from error stack (if available)
5073
+ // Example stack string (Node.js):
5074
+ /*
5075
+ /Users/someuser/somescript.js:226
5076
+ opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc
5077
+ ^
5078
+
5079
+ SyntaxError: missing ) after argument list
5080
+ at internalCompileFunction (node:internal/vm:73:18)
5081
+ at wrapSafe (node:internal/modules/cjs/loader:1149:20)
5082
+ at Module._compile (node:internal/modules/cjs/loader:1190:27)
5083
+ ...
5084
+ */
5085
+ function getErrorDetail(e) {
5086
+ var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : [];
5087
+ if (parts.length > 1 || true) {
5088
+ return '\nError details:\n' + parts[0];
5089
+ }
5090
+ return '';
5091
+ }
5067
5092
 
5068
5093
  // print a message to stdout
5069
5094
  function print() {
@@ -7993,8 +8018,7 @@
7993
8018
  // stash a function for refreshing the current popup when data changes
7994
8019
  // while the popup is being displayed (e.g. while dragging a label)
7995
8020
  refresh = function() {
7996
- var rec = table && (editable ? table.getRecordAt(id) : table.getReadOnlyRecordAt(id)) || {};
7997
- render(content, rec, table, editable);
8021
+ render(content, id, table, editable);
7998
8022
  };
7999
8023
  refresh();
8000
8024
  if (ids && ids.length > 1) {
@@ -8033,7 +8057,8 @@
8033
8057
  tab.show();
8034
8058
  }
8035
8059
 
8036
- function render(el, rec, table, editable) {
8060
+ function render(el, recId, table, editable) {
8061
+ var rec = table && (editable ? table.getRecordAt(recId) : table.getReadOnlyRecordAt(recId)) || {};
8037
8062
  var tableEl = El('table').addClass('selectable'),
8038
8063
  rows = 0;
8039
8064
  // self.hide(); // clean up if panel is already open
@@ -8048,11 +8073,6 @@
8048
8073
  }
8049
8074
  });
8050
8075
 
8051
- // add new field form
8052
- if (editable) {
8053
- renderNewRow(tableEl, rec, table);
8054
- }
8055
-
8056
8076
  tableEl.appendTo(el);
8057
8077
  if (rows > 0) {
8058
8078
  // tableEl.appendTo(el);
@@ -8077,15 +8097,58 @@
8077
8097
  }
8078
8098
 
8079
8099
  if (editable) {
8100
+ // render "add field" button
8080
8101
  var line = El('div').appendTo(el);
8081
8102
  El('span').addClass('save-menu-btn').appendTo(line).on('click', async function(e) {
8103
+ // show "add field" dialog
8104
+ renderAddFieldPopup(recId, table);
8105
+ }).text('+ add field');
8106
+ }
8107
+ }
8108
+
8109
+ function renderAddFieldPopup(recId, table) {
8110
+ var popup = showPopupAlert('', 'Add field');
8111
+ var el = popup.container();
8112
+ el.addClass('option-menu');
8113
+ var html = `<input type="text" class="field-name text-input" placeholder="field name"><br>
8114
+ <input type="text" class="field-value text-input" placeholder="value"><br>
8115
+ <div class="btn dialog-btn">Apply</div> <span class="inline-checkbox"><input type="checkbox" class="all" />assign value to all records</span>`;
8116
+ el.html(html);
8117
+
8118
+ var name = el.findChild('.field-name');
8119
+ name.node().focus();
8120
+ var val = el.findChild('.field-value');
8121
+ var box = el.findChild('.all');
8122
+ var btn = el.findChild('.btn').on('click', function() {
8123
+ var all = box.node().checked;
8124
+ var nameStr = name.node().value.trim();
8125
+ if (!nameStr) return;
8126
+ if (table.fieldExists(nameStr)) {
8127
+ name.node().value = '';
8128
+ return;
8129
+ }
8130
+ var valStr = val.node().value.trim();
8131
+ var value = parseUnknownType(valStr);
8132
+ // table.addField(nameStr, function(d) {
8133
+ // // parse each time to avoid multiple references to objects
8134
+ // return (all || d == rec) ? parseUnknownType(valStr) : null;
8135
+ // });
8082
8136
 
8083
- }).text('add field');
8084
- }
8085
- }
8086
-
8087
- function renderNewRow(el, rec, table) {
8137
+ var cmdStr = `-each "d['${nameStr}'] = `;
8138
+ if (!all) {
8139
+ cmdStr += `this.id != ${recId} ? null : `;
8140
+ }
8141
+ valStr = JSON.stringify(JSON.stringify(value));
8142
+ cmdStr = valStr.replace('"', cmdStr);
8088
8143
 
8144
+ gui.console.runMapshaperCommands(cmdStr, function(err) {
8145
+ if (!err) {
8146
+ popup.close();
8147
+ } else {
8148
+ console.error(err);
8149
+ }
8150
+ });
8151
+ });
8089
8152
  }
8090
8153
 
8091
8154
  function renderRow(table, rec, key, type, editable) {
@@ -8121,12 +8184,10 @@
8121
8184
  input.on('change', function(e) {
8122
8185
  var val2 = parser(input.value()),
8123
8186
  strval2 = formatInspectorValue(val2, type);
8124
- if (strval == strval2) {
8125
- // contents unchanged
8126
- } else if (val2 === null && type != 'object') { // allow null objects
8187
+ if (val2 === null && type != 'object') { // allow null objects
8127
8188
  // invalid value; revert to previous value
8128
8189
  input.value(strval);
8129
- } else {
8190
+ } else if (strval != strval2) {
8130
8191
  // field content has changed
8131
8192
  strval = strval2;
8132
8193
  gui.dispatchEvent('data_preupdate', {FID: currId}); // for undo/redo
@@ -8191,6 +8252,14 @@
8191
8252
  }
8192
8253
  };
8193
8254
 
8255
+ function parseUnknownType(str) {
8256
+ var val = inputParsers.number(str);
8257
+ if (val !== null) return val;
8258
+ val = inputParsers.object(str);
8259
+ if (val !== null) return val;
8260
+ return str;
8261
+ }
8262
+
8194
8263
  function getInputParser(type) {
8195
8264
  return inputParsers[type || 'multiple'];
8196
8265
  }
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.41";
3
+ var VERSION = "0.6.42";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -1267,6 +1267,26 @@
1267
1267
  _stop = stop;
1268
1268
  }
1269
1269
 
1270
+ // get detailed error information from error stack (if available)
1271
+ // Example stack string (Node.js):
1272
+ /*
1273
+ /Users/someuser/somescript.js:226
1274
+ opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc
1275
+ ^
1276
+
1277
+ SyntaxError: missing ) after argument list
1278
+ at internalCompileFunction (node:internal/vm:73:18)
1279
+ at wrapSafe (node:internal/modules/cjs/loader:1149:20)
1280
+ at Module._compile (node:internal/modules/cjs/loader:1190:27)
1281
+ ...
1282
+ */
1283
+ function getErrorDetail(e) {
1284
+ var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : [];
1285
+ if (parts.length > 1 || true) {
1286
+ return '\nError details:\n' + parts[0];
1287
+ }
1288
+ return '';
1289
+ }
1270
1290
 
1271
1291
  // print a message to stdout
1272
1292
  function print() {
@@ -1389,6 +1409,7 @@
1389
1409
  interrupt: interrupt,
1390
1410
  message: message,
1391
1411
  setLoggingFunctions: setLoggingFunctions,
1412
+ getErrorDetail: getErrorDetail,
1392
1413
  print: print,
1393
1414
  verbose: verbose,
1394
1415
  debug: debug,
@@ -6359,9 +6380,10 @@
6359
6380
  function mergeDatasets(arr) {
6360
6381
  var arcSources = [],
6361
6382
  arcCount = 0,
6362
- mergedLayers = [],
6363
- mergedInfo = {},
6364
- mergedArcs;
6383
+ merged = {
6384
+ info: {},
6385
+ layers: []
6386
+ };
6365
6387
 
6366
6388
  // Error if incompatible CRS
6367
6389
  requireDatasetsHaveCompatibleCRS(arr);
@@ -6372,38 +6394,35 @@
6372
6394
  arcSources.push(dataset.arcs);
6373
6395
  }
6374
6396
 
6375
- mergeDatasetInfo(mergedInfo, dataset);
6397
+ mergeDatasetInfo$1(merged, dataset);
6376
6398
  dataset.layers.forEach(function(lyr) {
6377
6399
  if (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline') {
6378
6400
  forEachArcId(lyr.shapes, function(id) {
6379
6401
  return id < 0 ? id - arcCount : id + arcCount;
6380
6402
  });
6381
6403
  }
6382
- mergedLayers.push(lyr);
6404
+ merged.layers.push(lyr);
6383
6405
  });
6384
6406
  arcCount += n;
6385
6407
  });
6386
6408
 
6387
6409
  if (arcSources.length > 0) {
6388
- mergedArcs = mergeArcs(arcSources);
6389
- if (mergedArcs.size() != arcCount) {
6410
+ merged.arcs = mergeArcs(arcSources);
6411
+ if (merged.arcs.size() != arcCount) {
6390
6412
  error("[mergeDatasets()] Arc indexing error");
6391
6413
  }
6392
6414
  }
6393
6415
 
6394
- return {
6395
- info: mergedInfo,
6396
- arcs: mergedArcs,
6397
- layers: mergedLayers
6398
- };
6416
+ return merged;
6399
6417
  }
6400
6418
 
6401
- function mergeDatasetInfo(merged, dataset) {
6402
- var info = dataset.info || {};
6403
- merged.input_files = utils.uniq((merged.input_files || []).concat(info.input_files || []));
6404
- merged.input_formats = utils.uniq((merged.input_formats || []).concat(info.input_formats || []));
6419
+ function mergeDatasetInfo$1(merged, dataset) {
6420
+ var src = dataset.info || {};
6421
+ var dest = merged.info || (merged.info = {});
6422
+ dest.input_files = utils.uniq((dest.input_files || []).concat(src.input_files || []));
6423
+ dest.input_formats = utils.uniq((dest.input_formats || []).concat(src.input_formats || []));
6405
6424
  // merge other info properties (e.g. input_geojson_crs, input_delimiter, prj, crs)
6406
- utils.defaults(merged, info);
6425
+ utils.defaults(dest, src);
6407
6426
  }
6408
6427
 
6409
6428
  function mergeArcs(arr) {
@@ -6450,6 +6469,7 @@
6450
6469
  mergeDatasetsForExport: mergeDatasetsForExport,
6451
6470
  mergeCommandTargets: mergeCommandTargets,
6452
6471
  mergeDatasets: mergeDatasets,
6472
+ mergeDatasetInfo: mergeDatasetInfo$1,
6453
6473
  mergeArcs: mergeArcs
6454
6474
  });
6455
6475
 
@@ -6900,6 +6920,18 @@
6900
6920
  });
6901
6921
  }
6902
6922
 
6923
+ // dest: destination dataset
6924
+ // src: source dataset
6925
+ function mergeDatasetInfo(dest, src) {
6926
+ var srcInfo = src.info || {};
6927
+ var destInfo = dest.info || (dest.info = {});
6928
+ destInfo.input_files = utils.uniq((destInfo.input_files || []).concat(srcInfo.input_files || []));
6929
+ destInfo.input_formats = utils.uniq((destInfo.input_formats || []).concat(srcInfo.input_formats || []));
6930
+ // merge other info properties (e.g. input_geojson_crs, input_delimiter, prj, crs)
6931
+ utils.defaults(destInfo, srcInfo);
6932
+ }
6933
+
6934
+
6903
6935
  function splitApartLayers(dataset, layers) {
6904
6936
  var datasets = [];
6905
6937
  dataset.layers = dataset.layers.filter(function(lyr) {
@@ -7064,6 +7096,7 @@
7064
7096
  var DatasetUtils = /*#__PURE__*/Object.freeze({
7065
7097
  __proto__: null,
7066
7098
  splitDataset: splitDataset,
7099
+ mergeDatasetInfo: mergeDatasetInfo,
7067
7100
  splitApartLayers: splitApartLayers,
7068
7101
  copyDataset: copyDataset,
7069
7102
  copyDatasetForExport: copyDatasetForExport,
@@ -11205,20 +11238,43 @@
11205
11238
  return dest;
11206
11239
  };
11207
11240
 
11241
+ // Receives a directory path, in which the final subdirectory may include the
11242
+ // "*" wildcard, e.g. '.' 'data' '*' 'data/*' '2023-*'
11243
+ // Returns an array of expanded directory names
11244
+ // TODO: add support for wildcards in other subdirectories
11245
+ cli.expandDirectoryName = function(name) {
11246
+ var info = parseLocalPath(name);
11247
+ // final directory name is parsed as info.filename
11248
+ if (!info.filename.includes('*')) {
11249
+ return [name];
11250
+ }
11251
+ var rxp = utils.wildcardToRegExp(info.filename);
11252
+ var dirs = [];
11253
+ require$1('fs').readdirSync(info.directory || '.').forEach(function(item) {
11254
+ var path = info.directory ? require$1('path').join(info.directory, item) : item;
11255
+ if (rxp.test(item) && cli.isDirectory(path)) {
11256
+ dirs.push(path);
11257
+ }
11258
+ });
11259
+ return dirs;
11260
+ };
11261
+
11208
11262
  // Expand any "*" wild cards in file name
11209
11263
  // (For the Windows command line; unix shells do this automatically)
11210
11264
  cli.expandFileName = function(name) {
11211
11265
  var info = parseLocalPath(name),
11212
11266
  rxp = utils.wildcardToRegExp(info.filename),
11213
- dir = info.directory || '.',
11267
+ dirs = cli.expandDirectoryName(info.directory || '.'),
11214
11268
  files = [];
11215
11269
 
11216
11270
  try {
11217
- require$1('fs').readdirSync(dir).forEach(function(item) {
11218
- var path = require$1('path').join(dir, item);
11219
- if (rxp.test(item) && cli.isFile(path)) {
11220
- files.push(path);
11221
- }
11271
+ dirs.forEach(function(dir) {
11272
+ require$1('fs').readdirSync(dir).forEach(function(item) {
11273
+ var path = require$1('path').join(dir, item);
11274
+ if (rxp.test(item) && cli.isFile(path)) {
11275
+ files.push(path);
11276
+ }
11277
+ });
11222
11278
  });
11223
11279
  } catch(e) {}
11224
11280
 
@@ -28239,20 +28295,23 @@ ${svg}
28239
28295
  };
28240
28296
 
28241
28297
  this.setDefaultTarget = function(layers, dataset) {
28242
- if (datasets.indexOf(dataset) == -1) {
28243
- datasets.push(dataset);
28244
- }
28245
- defaultTargets = [{
28298
+ this.setDefaultTargets([{
28246
28299
  // Copy layers array, in case layers is a reference to dataset.layers.
28247
28300
  // This prevents layers that are added to the dataset inside a command from
28248
28301
  // being added to the next command's target, e.g. debugging layers added
28249
28302
  // by '-join unmatched unjoined'.
28250
28303
  layers: layers.concat(),
28251
28304
  dataset: dataset
28252
- }];
28305
+ }]);
28253
28306
  };
28254
28307
 
28308
+ // arr: array of target objects {layers:[], dataset:{}}
28255
28309
  this.setDefaultTargets = function(arr) {
28310
+ arr.forEach(function(target) {
28311
+ if (datasets.indexOf(target.dataset) == -1) {
28312
+ datasets.push(target.dataset);
28313
+ }
28314
+ });
28256
28315
  defaultTargets = arr;
28257
28316
  };
28258
28317
 
@@ -28345,6 +28404,30 @@ ${svg}
28345
28404
  stashVar('input_files', job.input_files);
28346
28405
  }
28347
28406
 
28407
+ // Apply a command to an array of target layers
28408
+ function applyCommandToEachLayer(func, targetLayers) {
28409
+ var args = utils.toArray(arguments).slice(2);
28410
+ return targetLayers.reduce(function(memo, lyr) {
28411
+ var result = func.apply(null, [lyr].concat(args));
28412
+ if (utils.isArray(result)) { // some commands return an array of layers
28413
+ memo = memo.concat(result);
28414
+ } else if (result) { // assuming result is a layer
28415
+ memo.push(result);
28416
+ }
28417
+ return memo;
28418
+ }, []);
28419
+ }
28420
+
28421
+ function applyCommandToEachTarget(func, targets) {
28422
+ var args = utils.toArray(arguments).slice(2);
28423
+ targets.forEach(function(target) {
28424
+ var result = func.apply(null, [target].concat(args));
28425
+ if (result) {
28426
+ error('Unexpected output from command');
28427
+ }
28428
+ });
28429
+ }
28430
+
28348
28431
  cmd.addShape = addShape;
28349
28432
 
28350
28433
  function addShape(targetLayers, targetDataset, opts) {
@@ -36290,6 +36373,7 @@ ${svg}
36290
36373
  var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
36291
36374
  var targets = catalog.findCommandTargets(opts.target || '*');
36292
36375
  var target = targets[0];
36376
+ var output;
36293
36377
  if (!target) {
36294
36378
  stop('Missing a target');
36295
36379
  }
@@ -36300,12 +36384,34 @@ ${svg}
36300
36384
  stop("Targetting layers from multiple datasets is not supported");
36301
36385
  }
36302
36386
  if (targetType == 'layer') {
36303
- cmdDefn.command(target.layers[0], target.dataset, opts.options);
36387
+ output = cmdDefn.command(target.layers[0], target.dataset, opts.options);
36304
36388
  } else if (targetType == 'layers') {
36305
- cmdDefn.command(target.layers, target.dataset, opts.options);
36389
+ output = cmdDefn.command(target.layers, target.dataset, opts.options);
36390
+ }
36391
+ if (output) {
36392
+ integrateOutput(output, target, catalog, opts);
36306
36393
  }
36307
36394
  };
36308
36395
 
36396
+ // TODO: remove restrictions on output data
36397
+ function integrateOutput(output, input, catalog, opts) {
36398
+ if (!output.dataset || !output.layers || output.layers.length > 0 === false) {
36399
+ stop('Invalid command output');
36400
+ }
36401
+ if (output.dataset == input.dataset) {
36402
+ stop('External commands are not currently allowed to modify input datasets');
36403
+ }
36404
+ if (output.dataset.layers.length != output.layers.length) {
36405
+ stop('Currently not supported: targetting a subset of output layers');
36406
+ }
36407
+ if (!opts.no_replace) {
36408
+ input.layers.forEach(function(lyr) {
36409
+ catalog.deleteLayer(lyr, input.dataset);
36410
+ });
36411
+ }
36412
+ catalog.addDataset(output.dataset);
36413
+ }
36414
+
36309
36415
  function parseExternalCommand(name, cmdDefn, tokens) {
36310
36416
  var parser = new CommandParser();
36311
36417
  var cmd = parser.command(name);
@@ -40720,7 +40826,8 @@ ${svg}
40720
40826
  function makeCircleCoords(center, opts) {
40721
40827
  var margin = opts.cell_margin > 0 ? opts.cell_margin : 1e-6;
40722
40828
  var radius = opts.interval / 2 * (1 - margin);
40723
- return getPointBufferCoordinates(center, radius, 20, getPlanarSegmentEndpoint);
40829
+ var vertices = opts.vertices || 20;
40830
+ return getPointBufferCoordinates(center, radius, vertices, getPlanarSegmentEndpoint);
40724
40831
  }
40725
40832
 
40726
40833
  // Returns a function that receives a cell index and returns indices of points
@@ -40731,12 +40838,15 @@ ${svg}
40731
40838
  var bboxIndex = new Flatbush(points.length);
40732
40839
  var empty = [];
40733
40840
  points.forEach(function(p) {
40841
+ var bbox = getPointBounds(p, radius);
40734
40842
  addPointToGridIndex(p, gridIndex, grid);
40735
- bboxIndex.add.apply(bboxIndex, getPointBounds(p, radius));
40843
+ bboxIndex.add.apply(bboxIndex, bbox);
40736
40844
  });
40737
40845
  bboxIndex.finish();
40738
40846
  return function(i) {
40739
- if (!gridIndex.hasId(i)) return empty;
40847
+ if (!gridIndex.hasId(i)) {
40848
+ return empty;
40849
+ }
40740
40850
  var bbox = grid.idxToBBox(i);
40741
40851
  var indices = bboxIndex.search.apply(bboxIndex, bbox);
40742
40852
  return indices;
@@ -40870,6 +40980,7 @@ ${svg}
40870
40980
  calcWeights: calcWeights,
40871
40981
  twoCircleIntersection: twoCircleIntersection,
40872
40982
  makeCellPolygon: makeCellPolygon,
40983
+ makeCircleCoords: makeCircleCoords,
40873
40984
  getPointIndex: getPointIndex,
40874
40985
  getAlignedGridBounds: getAlignedGridBounds,
40875
40986
  getCenteredGridBounds: getCenteredGridBounds,
@@ -41198,8 +41309,7 @@ ${svg}
41198
41309
  }
41199
41310
  }
41200
41311
  } catch(e) {
41201
- // stop(e);
41202
- stop('Unable to load external module:', e.message);
41312
+ stop('Unable to load external module:', e.message, getErrorDetail(e));
41203
41313
  }
41204
41314
  if (moduleName || opts.alias) {
41205
41315
  defs[opts.alias || moduleName] = mod;
@@ -42230,9 +42340,10 @@ ${svg}
42230
42340
  }
42231
42341
  };
42232
42342
 
42233
- cmd.snap = function(dataset, opts) {
42343
+ cmd.snap = function(target, opts) {
42234
42344
  var interval = 0;
42235
42345
  var snapCount = 0;
42346
+ var dataset = target.dataset;
42236
42347
  var arcs = dataset.arcs;
42237
42348
  var arcBounds = arcs && arcs.getBounds();
42238
42349
  if (!arcBounds || !arcBounds.hasBounds()) {
@@ -43367,7 +43478,7 @@ ${svg}
43367
43478
  function commandAcceptsMultipleTargetDatasets(name) {
43368
43479
  return name == 'rotate' || name == 'info' || name == 'proj' || name == 'require' ||
43369
43480
  name == 'drop' || name == 'target' || name == 'if' || name == 'elif' ||
43370
- name == 'else' || name == 'endif' || name == 'run' || name == 'i';
43481
+ name == 'else' || name == 'endif' || name == 'run' || name == 'i' || name == 'snap';
43371
43482
  }
43372
43483
 
43373
43484
  function commandAcceptsEmptyTarget(name) {
@@ -43449,6 +43560,10 @@ ${svg}
43449
43560
  source = findCommandSource(convertSourceName(opts.source, targets), job.catalog, opts);
43450
43561
  }
43451
43562
 
43563
+ // identify command target/input (for postprocessing)
43564
+ // TODO: support commands with multiple target datasets
43565
+ // target = name == 'i' ? null : targets[0];
43566
+
43452
43567
  if (name == 'add-shape') {
43453
43568
  if (!targetDataset) {
43454
43569
  targetDataset = {info: {}, layers: []};
@@ -43556,6 +43671,9 @@ ${svg}
43556
43671
  } else if (name == 'graticule') {
43557
43672
  job.catalog.addDataset(cmd.graticule(targetDataset, opts));
43558
43673
 
43674
+ } else if (name == 'grid') {
43675
+ outputDataset = cmd.polygonGrid(targetLayers, targetDataset, opts);
43676
+
43559
43677
  } else if (name == 'help') {
43560
43678
  // placing help command here to handle errors from invalid command names
43561
43679
  cmd.printHelp(command.options);
@@ -43627,9 +43745,6 @@ ${svg}
43627
43745
  } else if (name == 'point-to-grid') {
43628
43746
  outputLayers = cmd.pointToGrid(targetLayers, targetDataset, opts);
43629
43747
 
43630
- } else if (name == 'grid') {
43631
- outputDataset = cmd.polygonGrid(targetLayers, targetDataset, opts);
43632
-
43633
43748
  } else if (name == 'points') {
43634
43749
  outputLayers = applyCommandToEachLayer(cmd.createPointLayer, targetLayers, targetDataset, opts);
43635
43750
 
@@ -43693,7 +43808,8 @@ ${svg}
43693
43808
  outputLayers = cmd.sliceLayers(targetLayers, source, targetDataset, opts);
43694
43809
 
43695
43810
  } else if (name == 'snap') {
43696
- cmd.snap(targetDataset, opts);
43811
+ // cmd.snap(targetDataset, opts);
43812
+ applyCommandToEachTarget(targets, opts);
43697
43813
 
43698
43814
  } else if (name == 'sort') {
43699
43815
  applyCommandToEachLayer(cmd.sortFeatures, targetLayers, arcs, opts);
@@ -43784,9 +43900,12 @@ ${svg}
43784
43900
 
43785
43901
  // delete arcs if no longer needed (e.g. after -points command)
43786
43902
  // (after output layers have been integrated)
43903
+ // TODO: be more selective (e.g. -i command doesn't need cleanup)
43904
+ // or: detect if arcs have been changed
43787
43905
  if (targetDataset) {
43788
43906
  cleanupArcs(targetDataset);
43789
43907
  }
43908
+
43790
43909
  } catch(e) {
43791
43910
  return done(e);
43792
43911
  }
@@ -43808,20 +43927,6 @@ ${svg}
43808
43927
  });
43809
43928
  }
43810
43929
 
43811
- // Apply a command to an array of target layers
43812
- function applyCommandToEachLayer(func, targetLayers) {
43813
- var args = utils.toArray(arguments).slice(2);
43814
- return targetLayers.reduce(function(memo, lyr) {
43815
- var result = func.apply(null, [lyr].concat(args));
43816
- if (utils.isArray(result)) { // some commands return an array of layers
43817
- memo = memo.concat(result);
43818
- } else if (result) { // assuming result is a layer
43819
- memo.push(result);
43820
- }
43821
- return memo;
43822
- }, []);
43823
- }
43824
-
43825
43930
  // Parse command line args into commands and run them
43826
43931
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
43827
43932
  // function(argv[, input], callback)
@@ -44465,6 +44570,7 @@ ${svg}
44465
44570
  editArcs,
44466
44571
  GeoJSONReader,
44467
44572
  Heap,
44573
+ IdLookupIndex,
44468
44574
  NodeCollection,
44469
44575
  parseDMS,
44470
44576
  formatDMS,
package/www/page.css CHANGED
@@ -256,7 +256,7 @@ body {
256
256
 
257
257
  /* --- Error message ---------- */
258
258
 
259
- .error-wrapper {
259
+ .alert-wrapper {
260
260
  z-index: 120;
261
261
  text-align: center;
262
262
  position: absolute;
@@ -266,29 +266,33 @@ body {
266
266
  left: 0;
267
267
  }
268
268
 
269
- .error-wrapper p.error-message {
269
+ .alert-wrapper p.error-message {
270
270
  margin: 1px 0 0 0;
271
271
  }
272
272
 
273
- .error-wrapper .dialog-btn {
274
- margin-top: 8px;
275
- }
276
-
277
- .error-title {
273
+ .alert-title {
278
274
  line-height: 1.1;
279
275
  font-weight: bold;
280
276
  margin-bottom: 5px;
281
277
  }
282
278
 
283
- div.error-box {
279
+ div.alert-title, div.error-message {
280
+ font-size: 16px;
281
+ }
282
+
283
+ .alert-wrapper .alert-btn {
284
+ margin-top: 8px;
285
+ }
286
+
287
+ div.alert-box {
284
288
  margin-top: 42px; /* 55px; */
285
289
  overflow: auto;
286
290
  max-height: 70%;
287
291
  max-width: 400px;
288
- font-size: 16px;
289
292
  }
290
293
 
291
294
 
295
+
292
296
  /* --- Splash screen -------------- */
293
297
 
294
298
  .splash-screen #splash-screen {
@@ -513,7 +517,7 @@ body.dragover #import-options-drop-area .drop-area {
513
517
  text-align: left;
514
518
  margin-top: 12px;
515
519
  margin-right: 20px;
516
- padding: 12px 16px 12px 18px;
520
+ padding: 11px 16px 12px 18px;
517
521
  vertical-align: top;
518
522
  display: inline-block;
519
523
  /* border: 1px solid #aaa; */
@@ -553,6 +557,7 @@ body.dragover #import-options-drop-area .drop-area {
553
557
  top: 1px;
554
558
  width: 12px;
555
559
  height: 12px;
560
+ cursor: pointer;
556
561
  }
557
562
 
558
563
  .info-box .tip-button {
@@ -800,7 +805,7 @@ img.close-btn {
800
805
  float: right;
801
806
  height: 18px;
802
807
  width: 18px;
803
- margin-top: 1px;
808
+ /* margin-top: 1px; */
804
809
  margin-right: -3px;
805
810
  cursor: pointer;
806
811
  border-radius: 4px;
@@ -1227,13 +1232,16 @@ div.basemap-style-btn.active img {
1227
1232
  top: 23px;
1228
1233
  }
1229
1234
 
1230
- #save-preference {
1231
- display: none;
1235
+ .inline-checkbox {
1232
1236
  position: relative;
1233
1237
  top: 1px;
1234
1238
  left: 5px;
1235
1239
  }
1236
1240
 
1241
+ #save-preference {
1242
+ /* display: none; */
1243
+ }
1244
+
1237
1245
  .nav-sub-menu {
1238
1246
  position: absolute;
1239
1247
  z-index: -1;
@@ -1316,25 +1324,32 @@ div.basemap-style-btn.active img {
1316
1324
  background: white;
1317
1325
  }
1318
1326
 
1319
- .save-menu-btn {
1327
+ /*.save-menu-btn {
1320
1328
  display: inline-block;
1321
1329
  border-radius: 4px;
1322
1330
  border: 1px solid #aaa;
1323
1331
  font-size: 12px;
1324
1332
  margin-left: 2px;
1325
1333
  padding: 1px 2px 3px 2px;
1326
- }
1334
+ }*/
1327
1335
 
1328
- .save-menu-link,
1329
1336
  .save-menu-btn {
1330
- cursor: pointer;
1337
+ display: inline-block;
1338
+ font-size: 12px;
1339
+ margin-top: 2px;
1331
1340
  }
1332
1341
 
1333
1342
  .save-menu-btn:hover {
1334
- background: #e6f7ff;
1335
1343
  color: black;
1336
1344
  }
1337
1345
 
1346
+ .save-menu-link,
1347
+ .save-menu-btn {
1348
+ cursor: pointer;
1349
+ }
1350
+
1351
+
1352
+
1338
1353
  .save-menu-link:hover {
1339
1354
  /* background: #e6f7ff; */
1340
1355
  font-weight: bold;