mapshaper 0.6.29 → 0.6.31

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.29";
3
+ var VERSION = "0.6.31";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -4846,13 +4846,14 @@
4846
4846
 
4847
4847
  // @info: info property of source dataset (instead of crs object, so wkt string
4848
4848
  // can be preserved if present)
4849
- function setDatasetCrsInfo(dataset, info) {
4849
+ function setDatasetCrsInfo(dataset, crsInfo) {
4850
+ crsInfo = crsInfo || {}; // also accepts null/unknown crs info
4850
4851
  dataset.info = dataset.info || {};
4851
4852
  // Assumes that proj4 object is never mutated.
4852
4853
  // TODO: assign a copy of crs (if present)
4853
- dataset.info.crs = info.crs;
4854
- dataset.info.prj = info.prj;
4855
- dataset.info.crs_string = info.crs_string;
4854
+ dataset.info.crs = crsInfo.crs;
4855
+ dataset.info.prj = crsInfo.prj;
4856
+ dataset.info.crs_string = crsInfo.crs_string;
4856
4857
  return dataset;
4857
4858
  }
4858
4859
 
@@ -23814,6 +23815,10 @@ ${svg}
23814
23815
  type: 'strings',
23815
23816
  describe: 'fields to retain (comma-sep.), e.g. \'fips,name\''
23816
23817
  })
23818
+ .option('invert', {
23819
+ type: 'flag',
23820
+ describe: 'retain only fields that would have been deleted'
23821
+ })
23817
23822
  .option('target', targetOpt);
23818
23823
 
23819
23824
  parser.command('filter-geom')
@@ -36481,7 +36486,7 @@ ${svg}
36481
36486
  return removed;
36482
36487
  }
36483
36488
 
36484
- cmd.filterFields = function(lyr, names) {
36489
+ cmd.filterFields = function(lyr, names, opts) {
36485
36490
  var table = lyr.data;
36486
36491
  names = names || [];
36487
36492
  requireDataFields(table, names);
@@ -36490,6 +36495,9 @@ ${svg}
36490
36495
  // utils.difference(table.getFields(), names).forEach(table.deleteField, table);
36491
36496
  // the below method sets field order of CSV output, and is generally faster
36492
36497
  var map = mapFieldNames(names);
36498
+ if (opts.invert) {
36499
+ map = invertFieldMap(map, table.getFields());
36500
+ }
36493
36501
  lyr.data.update(getRecordMapper(map));
36494
36502
  };
36495
36503
 
@@ -36500,6 +36508,15 @@ ${svg}
36500
36508
  lyr.data.update(getRecordMapper(map));
36501
36509
  };
36502
36510
 
36511
+ function invertFieldMap(map, fields) {
36512
+ return fields.reduce(function(memo, name) {
36513
+ if (!(name in map)) {
36514
+ memo[name] = name;
36515
+ }
36516
+ return memo;
36517
+ }, {});
36518
+ }
36519
+
36503
36520
  function mapFieldNames(names) {
36504
36521
  return (names || []).reduce(function(memo, str) {
36505
36522
  var parts = str.split('='),
@@ -37123,7 +37140,7 @@ ${svg}
37123
37140
  crsInfo = getDatasetCrsInfo(source.dataset);
37124
37141
  } else if (opts.bbox) {
37125
37142
  bounds = new Bounds(opts.bbox);
37126
- crsInfo = getCrsInfo('wgs84');
37143
+ crsInfo = probablyDecimalDegreeBounds(bounds) ? getCrsInfo('wgs84') : {};
37127
37144
  }
37128
37145
  bounds = bounds && applyRectangleOptions(bounds, crsInfo.crs, opts);
37129
37146
  if (!bounds || !bounds.hasBounds()) {
@@ -43237,7 +43254,7 @@ ${svg}
43237
43254
  outputLayers = applyCommandToEachLayer(cmd.filterFeatures, targetLayers, arcs, opts);
43238
43255
 
43239
43256
  } else if (name == 'filter-fields') {
43240
- applyCommandToEachLayer(cmd.filterFields, targetLayers, opts.fields);
43257
+ applyCommandToEachLayer(cmd.filterFields, targetLayers, opts.fields, opts);
43241
43258
 
43242
43259
  } else if (name == 'filter-geom') {
43243
43260
  applyCommandToEachLayer(cmd.filterGeom, targetLayers, arcs, opts);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.29",
3
+ "version": "0.6.31",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -56,7 +56,7 @@
56
56
  "iconv-lite": "^0.6.3",
57
57
  "idb-keyval": "^6.2.0",
58
58
  "kdbush": "^3.0.0",
59
- "mproj": "0.0.36",
59
+ "mproj": "0.0.37",
60
60
  "msgpackr": "^1.8.5",
61
61
  "opn": "^5.3.0",
62
62
  "rw": "~1.3.3",
package/www/index.html CHANGED
@@ -100,7 +100,8 @@
100
100
  <img class="pin-btn pinned" src="images/eye2.png">
101
101
  </div>
102
102
  <div class="layer-list"></div>
103
- <h4>Sources</h4>
103
+ <!-- <h4>Sources</h4> -->
104
+ <h4>Source files</h4>
104
105
  <div class="file-list"></div>
105
106
  <div>
106
107
  <div id="add-file-btn" class="dialog-btn btn">Add a file</div>
@@ -192,8 +193,8 @@ the largest ring of multi-ring features.
192
193
  </div></div></div></div>
193
194
  <div class="planar-opt-wrapper"><label for="planar-opt"><input type="checkbox" class="checkbox planar-opt"/>use planar geometry</label>
194
195
  <div class="tip-button">?<div class="tip-anchor">
195
- <div class="tip">Interpret x, y values as Cartesian coordinates
196
- on a plane, rather than longitude, latitude
196
+ <div class="tip">Treat x, y values as Cartesian coordinates
197
+ on a plane, rather than as longitude, latitude
197
198
  coordinates on a sphere.
198
199
  </div></div></div></div>
199
200
  </div>
@@ -256,7 +257,7 @@ a smoother appearance.</div></div></div></div>
256
257
 
257
258
  <div id="import-options" class="main-area popup-dialog">
258
259
  <div class="info-box">
259
- <!-- <h4>Queued files</h4> -->
260
+ <h3 class="list-header">Files</h3>
260
261
 
261
262
  <div class="dropped-file-list"></div>
262
263
 
@@ -272,20 +273,20 @@ a smoother appearance.</div></div></div></div>
272
273
  self-intersections, to help identify
273
274
  topological errors in a dataset.</div></div></div></div>
274
275
 
275
- <div><label for="snap-points-opt"><input type="checkbox" class="checkbox" id="snap-points-opt" />snap vertices</label>
276
+ <!-- <div><label for="snap-points-opt"><input type="checkbox" class="checkbox" id="snap-points-opt" />snap vertices</label>
276
277
  <div class="tip-button">?<div class="tip-anchor">
277
278
  <div class="tip">Fix topology errors by snapping
278
279
  together points with nearly identical
279
280
  coordinates. This option does not
280
- apply to TopoJSON files.</div></div></div></div>
281
+ apply to TopoJSON files.</div></div></div></div> -->
281
282
  <div style="height:5px"></div>
282
283
 
283
284
  </div>
284
285
 
285
286
  <div><input type="text" class="advanced-options" placeholder="import options" /><div class="tip-button">?<div class="tip-anchor">
286
287
  <div class="tip">Enter options from the command line
287
- interface. Examples: "no-topology"
288
- "encoding=big5"</div></div></div></div>
288
+ interface. Examples: <span id="import-option-examples">no-topology
289
+ encoding=big5</span></div></div></div></div>
289
290
 
290
291
  </div>
291
292
 
@@ -1959,7 +1959,21 @@
1959
1959
  function showQueuedFiles() {
1960
1960
  var list = gui.container.findChild('.dropped-file-list').empty();
1961
1961
  queuedFiles.forEach(function(f) {
1962
- El('<p>').text(f.name).appendTo(list);
1962
+ var html = '<span>' + f.name + '</span><img class="close-btn" draggable="false" src="images/close.png">';
1963
+ var entry = El('<div>').html(html);
1964
+ entry.appendTo(list);
1965
+ // init delete button
1966
+ GUI.onClick(entry.findChild('img.close-btn'), function(e) {
1967
+ e.stopPropagation();
1968
+ queuedFiles = queuedFiles.filter(function(item) {
1969
+ return item != f;
1970
+ });
1971
+ if (queuedFiles.length > 0) {
1972
+ showQueuedFiles();
1973
+ } else {
1974
+ gui.clearMode();
1975
+ }
1976
+ });
1963
1977
  });
1964
1978
  }
1965
1979
 
@@ -2026,23 +2040,23 @@
2026
2040
  }
2027
2041
  if (group[internal.PACKAGE_EXT]) {
2028
2042
  await importSessionData(group[internal.PACKAGE_EXT].content, gui);
2029
- } else {
2030
- importDataset(group, importOpts);
2043
+ } else if (importDataset(group, importOpts)) {
2044
+ importCount++;
2045
+ gui.session.fileImported(group.filename, optStr);
2031
2046
  }
2032
- importCount++;
2033
- gui.session.fileImported(group.filename, optStr);
2034
2047
  }
2035
2048
  }
2036
2049
 
2037
2050
  function importDataset(group, importOpts) {
2038
2051
  var dataset = internal.importContent(group, importOpts);
2039
- if (datasetIsEmpty(dataset)) return;
2052
+ if (datasetIsEmpty(dataset)) return false;
2040
2053
  if (group.layername) {
2041
2054
  dataset.layers.forEach(lyr => lyr.name = group.layername);
2042
2055
  }
2043
2056
  // save import options for use by repair control, etc.
2044
2057
  dataset.info.import_options = importOpts;
2045
2058
  model.addDataset(dataset);
2059
+ return true;
2046
2060
  }
2047
2061
 
2048
2062
  function addEmptyLayer() {
@@ -2083,7 +2097,7 @@
2083
2097
  var freeform = El('#import-options .advanced-options').node().value;
2084
2098
  importOpts = GUI.parseFreeformOptions(freeform, 'i');
2085
2099
  importOpts.no_repair = !El("#repair-intersections-opt").node().checked;
2086
- importOpts.snap = !!El("#snap-points-opt").node().checked;
2100
+ // importOpts.snap = !!El("#snap-points-opt").node().checked;
2087
2101
  }
2088
2102
  return importOpts;
2089
2103
  }
@@ -2183,8 +2197,8 @@
2183
2197
  name: filename,
2184
2198
  content: index[filename]
2185
2199
  });
2186
- return memo;
2187
2200
  }
2201
+ return memo;
2188
2202
  }, []);
2189
2203
  }
2190
2204
 
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.29";
3
+ var VERSION = "0.6.31";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -4846,13 +4846,14 @@
4846
4846
 
4847
4847
  // @info: info property of source dataset (instead of crs object, so wkt string
4848
4848
  // can be preserved if present)
4849
- function setDatasetCrsInfo(dataset, info) {
4849
+ function setDatasetCrsInfo(dataset, crsInfo) {
4850
+ crsInfo = crsInfo || {}; // also accepts null/unknown crs info
4850
4851
  dataset.info = dataset.info || {};
4851
4852
  // Assumes that proj4 object is never mutated.
4852
4853
  // TODO: assign a copy of crs (if present)
4853
- dataset.info.crs = info.crs;
4854
- dataset.info.prj = info.prj;
4855
- dataset.info.crs_string = info.crs_string;
4854
+ dataset.info.crs = crsInfo.crs;
4855
+ dataset.info.prj = crsInfo.prj;
4856
+ dataset.info.crs_string = crsInfo.crs_string;
4856
4857
  return dataset;
4857
4858
  }
4858
4859
 
@@ -23814,6 +23815,10 @@ ${svg}
23814
23815
  type: 'strings',
23815
23816
  describe: 'fields to retain (comma-sep.), e.g. \'fips,name\''
23816
23817
  })
23818
+ .option('invert', {
23819
+ type: 'flag',
23820
+ describe: 'retain only fields that would have been deleted'
23821
+ })
23817
23822
  .option('target', targetOpt);
23818
23823
 
23819
23824
  parser.command('filter-geom')
@@ -36481,7 +36486,7 @@ ${svg}
36481
36486
  return removed;
36482
36487
  }
36483
36488
 
36484
- cmd.filterFields = function(lyr, names) {
36489
+ cmd.filterFields = function(lyr, names, opts) {
36485
36490
  var table = lyr.data;
36486
36491
  names = names || [];
36487
36492
  requireDataFields(table, names);
@@ -36490,6 +36495,9 @@ ${svg}
36490
36495
  // utils.difference(table.getFields(), names).forEach(table.deleteField, table);
36491
36496
  // the below method sets field order of CSV output, and is generally faster
36492
36497
  var map = mapFieldNames(names);
36498
+ if (opts.invert) {
36499
+ map = invertFieldMap(map, table.getFields());
36500
+ }
36493
36501
  lyr.data.update(getRecordMapper(map));
36494
36502
  };
36495
36503
 
@@ -36500,6 +36508,15 @@ ${svg}
36500
36508
  lyr.data.update(getRecordMapper(map));
36501
36509
  };
36502
36510
 
36511
+ function invertFieldMap(map, fields) {
36512
+ return fields.reduce(function(memo, name) {
36513
+ if (!(name in map)) {
36514
+ memo[name] = name;
36515
+ }
36516
+ return memo;
36517
+ }, {});
36518
+ }
36519
+
36503
36520
  function mapFieldNames(names) {
36504
36521
  return (names || []).reduce(function(memo, str) {
36505
36522
  var parts = str.split('='),
@@ -37123,7 +37140,7 @@ ${svg}
37123
37140
  crsInfo = getDatasetCrsInfo(source.dataset);
37124
37141
  } else if (opts.bbox) {
37125
37142
  bounds = new Bounds(opts.bbox);
37126
- crsInfo = getCrsInfo('wgs84');
37143
+ crsInfo = probablyDecimalDegreeBounds(bounds) ? getCrsInfo('wgs84') : {};
37127
37144
  }
37128
37145
  bounds = bounds && applyRectangleOptions(bounds, crsInfo.crs, opts);
37129
37146
  if (!bounds || !bounds.hasBounds()) {
@@ -43237,7 +43254,7 @@ ${svg}
43237
43254
  outputLayers = applyCommandToEachLayer(cmd.filterFeatures, targetLayers, arcs, opts);
43238
43255
 
43239
43256
  } else if (name == 'filter-fields') {
43240
- applyCommandToEachLayer(cmd.filterFields, targetLayers, opts.fields);
43257
+ applyCommandToEachLayer(cmd.filterFields, targetLayers, opts.fields, opts);
43241
43258
 
43242
43259
  } else if (name == 'filter-geom') {
43243
43260
  applyCommandToEachLayer(cmd.filterGeom, targetLayers, arcs, opts);
package/www/modules.js CHANGED
@@ -12530,7 +12530,10 @@ function wkt_unpack(str) {
12530
12530
  str = convert_wkt_quotes(str);
12531
12531
 
12532
12532
  // Convert WKT entities to JSON arrays
12533
- str = str.replace(/([A-Z0-9]+)\[/g, '["$1",');
12533
+ // str = str.replace(/([A-Z0-9]+)\[/g, '["$1",');
12534
+ // Changed to ignore some names that look like entities, like "GCS_TWD97[2020]"
12535
+ // allow only [ or , character before the next quote (i.e. block close quotes)
12536
+ str = str.replace(/([A-Z0-9]+)\[(?![^"]*[^\[,"]")/g, '["$1",');
12534
12537
 
12535
12538
  // Enclose axis keywords in quotes to create valid JSON strings
12536
12539
  str = str.replace(/, *([a-zA-Z]+) *(?=[,\]])/g, ',"$1"');
package/www/page.css CHANGED
@@ -472,6 +472,25 @@ body.dragover #import-options-drop-area .drop-area {
472
472
  overflow-y: auto;
473
473
  }
474
474
 
475
+ .dropped-file-list img.close-btn {
476
+ position: absolute;
477
+ cursor: pointer;
478
+ width: 14px;
479
+ height: 14px;
480
+ padding: 0;
481
+ top: 3px;
482
+ right: 0px;
483
+ }
484
+
485
+ .dropped-file-list > div {
486
+ position: relative;
487
+ }
488
+
489
+ .dropped-file-list span {
490
+ margin-right: 16px;
491
+ }
492
+
493
+
475
494
  #import-options .dropped-file-list p {
476
495
  line-height: 1;
477
496
  margin-bottom: 5px;
@@ -498,7 +517,7 @@ body.dragover #import-options-drop-area .drop-area {
498
517
  text-align: left;
499
518
  margin-top: 12px;
500
519
  margin-right: 20px;
501
- padding: 12px 18px 12px 18px;
520
+ padding: 12px 16px 12px 18px;
502
521
  vertical-align: top;
503
522
  display: inline-block;
504
523
  /* border: 1px solid #aaa; */
@@ -512,6 +531,10 @@ body.dragover #import-options-drop-area .drop-area {
512
531
  font-weight: normal;
513
532
  }
514
533
 
534
+ .info-box h3.list-header {
535
+ margin-bottom: 0.1em;
536
+ }
537
+
515
538
  .info-box h4 {
516
539
  font-size: 1.085em;
517
540
  font-weight: normal;
@@ -541,8 +564,8 @@ body.dragover #import-options-drop-area .drop-area {
541
564
  }
542
565
 
543
566
  .info-box .tip-button {
544
- margin-left: 12px;
545
- margin-top: 3px;
567
+ margin: 3px 2px 0 10px;
568
+
546
569
  }
547
570
 
548
571
  .info-box input[type="checkbox"] {
@@ -762,8 +785,10 @@ body.simplify .layer-control-btn {
762
785
  padding: 0px 14px 2px 14px;
763
786
  }
764
787
 
788
+
765
789
  .pin-all img,
766
- .layer-item img {
790
+ .layer-item img
791
+ {
767
792
  position: absolute;
768
793
  width: 16px;
769
794
  height: 16px;
@@ -784,7 +809,7 @@ img.close-btn {
784
809
  height: 18px;
785
810
  width: 18px;
786
811
  margin-top: 1px;
787
- margin-right: -5px;
812
+ margin-right: -3px;
788
813
  cursor: pointer;
789
814
  border-radius: 4px;
790
815
  }