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/mapshaper.js +994 -56
- package/package.json +7 -3
- package/www/ai-config.js +62 -0
- package/www/geoparquet.js +14311 -0
- package/www/index.html +2 -2
- package/www/mapshaper-gui.js +162 -3
- package/www/mapshaper.js +994 -56
- package/www/modules.js +13695 -11919
- package/www/sponsor.html +4 -4
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">
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -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.
|
|
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
|
|