mapshaper 0.7.7 → 0.7.9

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/www/index.html CHANGED
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <title>Mapshaper</title>
5
- <meta name="Description" content="A topology-aware tool for editing and converting geospatial vector data. Works with Shapefile, GeoJSON, TopoJSON, GeoPackage, FlatGeobuf and KML — in the browser or on the command line.">
5
+ <meta name="Description" content="A topology-aware tool for editing and converting geospatial vector data. Works with Shapefile, GeoJSON, TopoJSON, GeoPackage, FlatGeobuf, GeoParquet and KML — in the browser or on the command line.">
6
6
  <meta charset="UTF-8">
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1">
8
8
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -319,7 +319,7 @@ a smoother appearance.</div></div></div></div>
319
319
  <span><input type="checkbox" class="advanced-import-options">with advanced options</span>
320
320
  <div class="mini-drop-area">
321
321
  <div class="subtitle">Drop, paste or <span class="add-btn inline-btn btn"><span class="label-text">select</span></span> files to import.</div>
322
- <div class="subtitle">Shapefile, GeoJSON, TopoJSON, GeoPackage, FlatGeobuf, KML and CSV formats are supported. Files can be zipped or gzipped.</div>
322
+ <div class="subtitle">Shapefile, GeoJSON, TopoJSON, GeoPackage, FlatGeobuf, GeoParquet, KML and CSV formats are supported. Files can be zipped or gzipped.</div>
323
323
  </div>
324
324
  </div>
325
325
  <div class="queued-file-section">
@@ -2064,6 +2064,7 @@
2064
2064
  }
2065
2065
 
2066
2066
  var geopackagePromise = null;
2067
+ var geoParquetPromise = null;
2067
2068
 
2068
2069
  async function loadGeopackageLib() {
2069
2070
  if (!window.modules || !window.modules['@ngageoint/geopackage']) {
@@ -2097,6 +2098,16 @@
2097
2098
  }
2098
2099
  }
2099
2100
 
2101
+ async function loadGeoParquetLib() {
2102
+ if (!window.modules || !window.modules.hyparquet || !window.modules['hyparquet-compressors'] || !window.modules['hyparquet-writer'] || !window.modules['zstd-codec']) {
2103
+ if (!geoParquetPromise) {
2104
+ geoParquetPromise = loadScript('geoparquet.js');
2105
+ }
2106
+ await geoParquetPromise;
2107
+ geoParquetPromise = null;
2108
+ }
2109
+ }
2110
+
2100
2111
  // @cb function(<FileList>)
2101
2112
  function DropControl(gui, el, cb) {
2102
2113
  var area = El(el);
@@ -2515,7 +2526,10 @@
2515
2526
  if (group.gpkg) {
2516
2527
  await loadGeopackageLib();
2517
2528
  }
2518
- if (group.gpkg || group.fgb) {
2529
+ if (group.parquet) {
2530
+ await loadGeoParquetLib();
2531
+ }
2532
+ if (group.gpkg || group.fgb || group.parquet) {
2519
2533
  dataset = await internal.importContentAsync(group, importOpts);
2520
2534
  } else {
2521
2535
  dataset = internal.importContent(group, importOpts);
@@ -2546,7 +2560,7 @@
2546
2560
  function filesMayContainPaths(files) {
2547
2561
  return utils$1.some(files, function(f) {
2548
2562
  var type = internal.guessInputFileType(f.name);
2549
- return type == 'shp' || type == 'json' || type == 'gpkg' || internal.isZipFile(f.name);
2563
+ return type == 'shp' || type == 'json' || type == 'gpkg' || type == 'parquet' || internal.isZipFile(f.name);
2550
2564
  });
2551
2565
  }
2552
2566
 
@@ -4099,6 +4113,116 @@
4099
4113
  }
4100
4114
  };
4101
4115
 
4116
+ var FIELD_TYPE_SCAN_LIMIT = 1000;
4117
+ var RECENT_COMMAND_LIMIT = 20;
4118
+ var RECENT_MESSAGE_LIMIT = 10;
4119
+
4120
+ function getRuntimeStateContext(gui) {
4121
+ var layers = gui.model.getLayers();
4122
+ var active = gui.model.getActiveLayer();
4123
+ var history = gui.session.getHistorySnapshot();
4124
+ var messages = gui.getMessages ? gui.getMessages() : [];
4125
+
4126
+ return {
4127
+ schema: 'mapshaper-runtime-context',
4128
+ schema_version: 1,
4129
+ generated_at: new Date().toISOString(),
4130
+ privacy_note: 'Contains project metadata only: layer names, field names/types, counts, CRS, recent commands and recent messages. It does not include geometry or attribute records.',
4131
+ ui: getUiContext(gui),
4132
+ active_layer: active ? getLayerTargetId(gui, active.layer) : null,
4133
+ default_targets: getDefaultTargets(gui),
4134
+ layers: layers.map(function(o, i) {
4135
+ return getLayerContext(gui, o.layer, o.dataset, i, active && active.layer);
4136
+ }),
4137
+ session: {
4138
+ command_count: history.commands.length,
4139
+ recent_commands: history.commands.slice(-RECENT_COMMAND_LIMIT),
4140
+ unsaved_changes: gui.session.unsavedChanges()
4141
+ },
4142
+ messages: messages.slice(0, RECENT_MESSAGE_LIMIT)
4143
+ };
4144
+ }
4145
+
4146
+ function stringifyRuntimeStateContext(gui) {
4147
+ return JSON.stringify(getRuntimeStateContext(gui), null, 2);
4148
+ }
4149
+
4150
+ function getUiContext(gui) {
4151
+ return {
4152
+ interface: 'web_app',
4153
+ console_open: gui.consoleIsOpen(),
4154
+ panel_mode: gui.getMode(),
4155
+ interaction_mode: gui.interaction ? gui.interaction.getMode() : null,
4156
+ dataset_count: gui.model.getDatasets().length,
4157
+ layer_count: gui.model.getLayers().length,
4158
+ has_data: !gui.model.isEmpty()
4159
+ };
4160
+ }
4161
+
4162
+ function getDefaultTargets(gui) {
4163
+ return gui.model.getDefaultTargets().map(function(target) {
4164
+ return {
4165
+ layers: target.layers.map(function(lyr) {
4166
+ return getLayerTargetId(gui, lyr);
4167
+ })
4168
+ };
4169
+ });
4170
+ }
4171
+
4172
+ function getLayerContext(gui, lyr, dataset, i, activeLyr) {
4173
+ var fields = getFieldContexts(lyr);
4174
+ var context = {
4175
+ id: i + 1,
4176
+ target_id: getLayerTargetId(gui, lyr),
4177
+ name: lyr.name || null,
4178
+ active: lyr == activeLyr,
4179
+ geometry_type: lyr.geometry_type || null,
4180
+ feature_count: internal.getFeatureCount(lyr),
4181
+ field_count: fields.length,
4182
+ fields: fields
4183
+ };
4184
+ if (lyr.geometry_type) {
4185
+ context.crs = getCrsContext(dataset);
4186
+ }
4187
+ if (dataset.info && dataset.info.input_formats) {
4188
+ context.input_formats = dataset.info.input_formats.slice();
4189
+ }
4190
+ return context;
4191
+ }
4192
+
4193
+ function getCrsContext(dataset) {
4194
+ var crs = null;
4195
+ try {
4196
+ crs = internal.getProjInfo(dataset);
4197
+ } catch(e) {}
4198
+ return crs || null;
4199
+ }
4200
+
4201
+ function getFieldContexts(lyr) {
4202
+ if (!lyr.data || lyr.data.size() === 0) return [];
4203
+ return lyr.data.getFields().map(function(name) {
4204
+ return {
4205
+ name: name,
4206
+ type: getSampledFieldType(lyr.data, name)
4207
+ };
4208
+ });
4209
+ }
4210
+
4211
+ function getSampledFieldType(table, name) {
4212
+ var n = Math.min(table.size(), FIELD_TYPE_SCAN_LIMIT);
4213
+ var rec, type;
4214
+ for (var i = 0; i < n; i++) {
4215
+ rec = table.getReadOnlyRecordAt(i);
4216
+ type = rec ? internal.getValueType(rec[name]) : null;
4217
+ if (type) return type;
4218
+ }
4219
+ return null;
4220
+ }
4221
+
4222
+ function getLayerTargetId(gui, lyr) {
4223
+ return internal.formatOptionValue(internal.getLayerTargetId(gui.model, lyr));
4224
+ }
4225
+
4102
4226
  function Console(gui) {
4103
4227
  var model = gui.model;
4104
4228
  var CURSOR = '$ ';
@@ -4462,6 +4586,10 @@
4462
4586
  clear();
4463
4587
  } else if (cmd == 'tips') {
4464
4588
  printExamples();
4589
+ } else if (cmd == 'context') {
4590
+ toLog(stringifyRuntimeStateContext(gui));
4591
+ } else if (cmd == 'context download') {
4592
+ saveRuntimeContext();
4465
4593
  } else if (cmd == 'history') {
4466
4594
  toLog(gui.session.toCommandLineString());
4467
4595
  } else if (cmd == 'layers') {
@@ -4614,12 +4742,19 @@
4614
4742
  printExample("See a list of all console commands", "$ help");
4615
4743
  printExample("Get help using a single command", "$ help innerlines");
4616
4744
  printExample("Get information about imported datasets", "$ info");
4745
+ printExample("Print bot/debug runtime context as JSON", "$ context");
4617
4746
  printExample("Display browser session as shell commands", "$ history");
4618
4747
  printExample("Delete one state from a national dataset","$ filter 'STATE != \"Alaska\"'");
4619
4748
  printExample("Aggregate counties to states by dissolving shared edges" ,"$ dissolve 'STATE'");
4620
4749
  printExample("Clear the console", "$ clear");
4621
4750
  }
4622
4751
 
4752
+ function saveRuntimeContext() {
4753
+ var json = stringifyRuntimeStateContext(gui);
4754
+ saveBlobToLocalFile2('mapshaper-runtime-context.json', new Blob([json], {type: 'application/json'}));
4755
+ toLog('Saved runtime context to mapshaper-runtime-context.json', 'console-message');
4756
+ }
4757
+
4623
4758
  }
4624
4759
 
4625
4760
  // Test if map should be re-framed to show updated layer
@@ -4968,6 +5103,8 @@
4968
5103
  var opts = getExportOpts();
4969
5104
  if (opts.format == 'geopackage') {
4970
5105
  await loadGeopackageLib();
5106
+ } else if (opts.format == 'geoparquet') {
5107
+ await loadGeoParquetLib();
4971
5108
  }
4972
5109
  opts.active_layer = gui.model.getActiveLayer().layer; // kludge to support restoring active layer in gui
4973
5110
  if (opts.format == internal.PACKAGE_EXT) {
@@ -5108,7 +5245,7 @@
5108
5245
 
5109
5246
  function getExportFormats() {
5110
5247
  // return ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'kml', 'svg', internal.PACKAGE_EXT];
5111
- return ['shapefile', 'json', 'geojson', 'dsv', 'topojson', 'flatgeobuf', 'geopackage', 'kml', internal.PACKAGE_EXT, 'svg'];
5248
+ return ['shapefile', 'json', 'geojson', 'dsv', 'topojson', 'flatgeobuf', 'geopackage', 'geoparquet', 'kml', internal.PACKAGE_EXT, 'svg'];
5112
5249
  }
5113
5250
 
5114
5251
  function initFormatMenu() {
@@ -15143,6 +15280,18 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
15143
15280
  }
15144
15281
  };
15145
15282
 
15283
+ gui.getMessages = function() {
15284
+ return entries.map(function(entry) {
15285
+ return {
15286
+ severity: entry.severity,
15287
+ title: entry.title,
15288
+ body: entry.body,
15289
+ count: entry.count,
15290
+ time: entry.time.toISOString()
15291
+ };
15292
+ });
15293
+ };
15294
+
15146
15295
  function severityRank(s) {
15147
15296
  return s === 'error' ? 2 : s === 'warn' ? 1 : 0;
15148
15297
  }
@@ -15311,6 +15460,14 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
15311
15460
  return gui.container.hasClass('console-open');
15312
15461
  };
15313
15462
 
15463
+ gui.getRuntimeStateContext = function() {
15464
+ return getRuntimeStateContext(gui);
15465
+ };
15466
+
15467
+ gui.stringifyRuntimeStateContext = function() {
15468
+ return stringifyRuntimeStateContext(gui);
15469
+ };
15470
+
15314
15471
  // Make this instance interactive and editable
15315
15472
  gui.focus = function() {
15316
15473
  var curr = GUI.__active;
@@ -15424,6 +15581,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
15424
15581
  new LayerControl(gui);
15425
15582
  HeaderMenu();
15426
15583
  gui.console = new Console(gui);
15584
+ window.mapshaper.getRuntimeStateContext = gui.getRuntimeStateContext;
15585
+ window.mapshaper.stringifyRuntimeStateContext = gui.stringifyRuntimeStateContext;
15427
15586
 
15428
15587
  startEditing = function() {};
15429
15588