mapshaper 0.6.22 → 0.6.24
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 +155 -109
- package/package.json +1 -1
- package/www/index.html +3 -1
- package/www/mapshaper-gui.js +66 -43
- package/www/mapshaper.js +155 -109
- package/www/page.css +19 -14
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.24";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -10620,7 +10620,8 @@
|
|
|
10620
10620
|
buf = new Uint8Array(buf);
|
|
10621
10621
|
}
|
|
10622
10622
|
opts = opts || {};
|
|
10623
|
-
var
|
|
10623
|
+
var gunzip$1 = runningInBrowser() ? utils.promisify(gunzip) : utils.promisify(require('zlib').gunzip);
|
|
10624
|
+
var out = await gunzip$1(buf, opts);
|
|
10624
10625
|
if (opts.filename && !isImportableAsBinary(opts.filename)) {
|
|
10625
10626
|
out = strFromU8(out);
|
|
10626
10627
|
}
|
|
@@ -10628,8 +10629,6 @@
|
|
|
10628
10629
|
}
|
|
10629
10630
|
|
|
10630
10631
|
function gunzipSync(buf, filename) {
|
|
10631
|
-
// TODO: use native module in Node
|
|
10632
|
-
// require('zlib').
|
|
10633
10632
|
if (buf instanceof ArrayBuffer) {
|
|
10634
10633
|
buf = new Uint8Array(buf);
|
|
10635
10634
|
}
|
|
@@ -10768,16 +10767,39 @@
|
|
|
10768
10767
|
// gui: (optional) gui instance
|
|
10769
10768
|
//
|
|
10770
10769
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10771
|
-
|
|
10770
|
+
var obj = {
|
|
10772
10771
|
version: 1,
|
|
10773
10772
|
created: (new Date).toISOString(),
|
|
10774
|
-
datasets: await Promise.all(datasets.map(
|
|
10773
|
+
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10775
10774
|
};
|
|
10775
|
+
if (opts.compact) {
|
|
10776
|
+
await applyCompression(obj);
|
|
10777
|
+
}
|
|
10778
|
+
return obj;
|
|
10779
|
+
}
|
|
10780
|
+
|
|
10781
|
+
async function applyCompression(obj, opts) {
|
|
10782
|
+
var promises = [];
|
|
10783
|
+
obj.datasets.forEach(d => {
|
|
10784
|
+
if (d.arcs) promises.push(compressArcs(d.arcs, opts));
|
|
10785
|
+
});
|
|
10786
|
+
await Promise.all(promises);
|
|
10787
|
+
}
|
|
10788
|
+
|
|
10789
|
+
async function compressArcs(obj, opts) {
|
|
10790
|
+
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10791
|
+
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10792
|
+
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
10793
|
+
var results = await Promise.all(promises);
|
|
10794
|
+
obj.nn = results.shift();
|
|
10795
|
+
obj.xx = results.shift();
|
|
10796
|
+
obj.yy = results.shift();
|
|
10797
|
+
if (obj.zz) obj.zz = results.shift();
|
|
10776
10798
|
}
|
|
10777
10799
|
|
|
10778
10800
|
async function exportDataset(dataset, opts) {
|
|
10779
10801
|
return {
|
|
10780
|
-
arcs: dataset.arcs ?
|
|
10802
|
+
arcs: dataset.arcs ? exportArcs(dataset.arcs) : null,
|
|
10781
10803
|
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10782
10804
|
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10783
10805
|
};
|
|
@@ -10787,38 +10809,22 @@
|
|
|
10787
10809
|
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10788
10810
|
}
|
|
10789
10811
|
|
|
10790
|
-
|
|
10812
|
+
function exportArcs(arcs) {
|
|
10791
10813
|
var data = arcs.getVertexData();
|
|
10792
|
-
|
|
10814
|
+
return {
|
|
10793
10815
|
nn: typedArrayToBuffer(data.nn),
|
|
10794
10816
|
xx: typedArrayToBuffer(data.xx),
|
|
10795
10817
|
yy: typedArrayToBuffer(data.yy),
|
|
10796
10818
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10797
10819
|
zlimit: arcs.getRetainedInterval()
|
|
10798
10820
|
};
|
|
10799
|
-
|
|
10800
|
-
// gzipping typically sees about 70% compression on unrounded coordinates
|
|
10801
|
-
// -- possibly not worth the time
|
|
10802
|
-
if (opts.compact) {
|
|
10803
|
-
var gzipOpts = {level: 1, consume: false};
|
|
10804
|
-
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10805
|
-
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
10806
|
-
var results = await Promise.all(promises);
|
|
10807
|
-
obj.nn = results.shift();
|
|
10808
|
-
obj.xx = results.shift();
|
|
10809
|
-
obj.yy = results.shift();
|
|
10810
|
-
if (obj.zz) obj.zz = results.shift();
|
|
10811
|
-
}
|
|
10812
|
-
return obj;
|
|
10813
10821
|
}
|
|
10814
10822
|
|
|
10815
10823
|
async function exportLayer(lyr) {
|
|
10816
|
-
// console.time('table')
|
|
10817
10824
|
var data = null;
|
|
10818
10825
|
if (lyr.data) {
|
|
10819
10826
|
data = await exportTable2(lyr.data);
|
|
10820
10827
|
}
|
|
10821
|
-
// console.timeEnd('table')
|
|
10822
10828
|
return {
|
|
10823
10829
|
name: lyr.name || null,
|
|
10824
10830
|
geometry_type: lyr.geometry_type || null,
|
|
@@ -10845,6 +10851,7 @@
|
|
|
10845
10851
|
exportPackedDatasets: exportPackedDatasets,
|
|
10846
10852
|
pack: pack,
|
|
10847
10853
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10854
|
+
applyCompression: applyCompression,
|
|
10848
10855
|
exportDataset: exportDataset
|
|
10849
10856
|
});
|
|
10850
10857
|
|
|
@@ -24922,6 +24929,9 @@ ${svg}
|
|
|
24922
24929
|
|
|
24923
24930
|
parser.command('info')
|
|
24924
24931
|
.describe('print information about data layers')
|
|
24932
|
+
.option('save-to', {
|
|
24933
|
+
describe: 'name of file to save info in JSON format'
|
|
24934
|
+
})
|
|
24925
24935
|
.option('target', targetOpt);
|
|
24926
24936
|
|
|
24927
24937
|
parser.command('inspect')
|
|
@@ -27457,12 +27467,14 @@ ${svg}
|
|
|
27457
27467
|
// Import datasets contained in a BSON blob
|
|
27458
27468
|
// Return command target as a dataset
|
|
27459
27469
|
//
|
|
27460
|
-
async function
|
|
27461
|
-
|
|
27470
|
+
async function unpackSessionData(buf) {
|
|
27471
|
+
return restoreSessionData(unpack(buf, {}));
|
|
27472
|
+
}
|
|
27473
|
+
|
|
27474
|
+
async function restoreSessionData(obj) {
|
|
27462
27475
|
if (!isValidSession(obj)) {
|
|
27463
27476
|
stop('Invalid mapshaper session data object');
|
|
27464
27477
|
}
|
|
27465
|
-
|
|
27466
27478
|
var datasets = await Promise.all(obj.datasets.map(importDataset));
|
|
27467
27479
|
return Object.assign(obj, {datasets: datasets});
|
|
27468
27480
|
}
|
|
@@ -27539,7 +27551,8 @@ ${svg}
|
|
|
27539
27551
|
|
|
27540
27552
|
var Unpack = /*#__PURE__*/Object.freeze({
|
|
27541
27553
|
__proto__: null,
|
|
27542
|
-
|
|
27554
|
+
unpackSessionData: unpackSessionData,
|
|
27555
|
+
restoreSessionData: restoreSessionData
|
|
27543
27556
|
});
|
|
27544
27557
|
|
|
27545
27558
|
cmd.importFiles = async function(catalog, opts) {
|
|
@@ -27593,7 +27606,7 @@ ${svg}
|
|
|
27593
27606
|
|
|
27594
27607
|
async function importMshpFile(file, catalog, opts) {
|
|
27595
27608
|
var buf = cli.readFile(file, null, opts.input);
|
|
27596
|
-
var obj = await
|
|
27609
|
+
var obj = await unpackSessionData(buf);
|
|
27597
27610
|
obj.datasets.forEach(catalog.addDataset, catalog);
|
|
27598
27611
|
return obj.target;
|
|
27599
27612
|
}
|
|
@@ -38240,55 +38253,27 @@ ${svg}
|
|
|
38240
38253
|
|
|
38241
38254
|
var MAX_RULE_LEN = 50;
|
|
38242
38255
|
|
|
38243
|
-
cmd.
|
|
38244
|
-
var
|
|
38245
|
-
layers.
|
|
38246
|
-
|
|
38247
|
-
var tableStr = getAttributeTableInfo(o.layer);
|
|
38248
|
-
var tableWidth = measureLongestLine(tableStr);
|
|
38249
|
-
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
38250
|
-
str += '\n';
|
|
38251
|
-
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
38252
|
-
str += title + '\n';
|
|
38253
|
-
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
38254
|
-
str += getLayerInfo(o.layer, o.dataset);
|
|
38255
|
-
str += tableStr;
|
|
38256
|
+
cmd.info = function(targets, opts) {
|
|
38257
|
+
var layers = expandCommandTargets(targets);
|
|
38258
|
+
var arr = layers.map(function(o) {
|
|
38259
|
+
return getLayerInfo(o.layer, o.dataset);
|
|
38256
38260
|
});
|
|
38257
|
-
message(
|
|
38258
|
-
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
function stringDisplayWidth(str) {
|
|
38265
|
-
var w = 0;
|
|
38266
|
-
for (var i = 0, n=str.length; i < n; i++) {
|
|
38267
|
-
w += charDisplayWidth(str.charCodeAt(i));
|
|
38261
|
+
message(formatInfo(arr));
|
|
38262
|
+
if (opts.save_to) {
|
|
38263
|
+
var output = [{
|
|
38264
|
+
filename: opts.save_to + (opts.save_to.endsWith('.json') ? '' : '.json'),
|
|
38265
|
+
content: JSON.stringify(arr, null, 2)
|
|
38266
|
+
}];
|
|
38267
|
+
writeFiles(output, opts);
|
|
38268
38268
|
}
|
|
38269
|
-
|
|
38270
|
-
}
|
|
38269
|
+
};
|
|
38271
38270
|
|
|
38272
|
-
//
|
|
38273
|
-
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
38274
|
-
function charDisplayWidth(c) {
|
|
38275
|
-
if (c >= 0x1100 &&
|
|
38276
|
-
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
38277
|
-
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
38278
|
-
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
38279
|
-
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
38280
|
-
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
38281
|
-
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
38282
|
-
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
38283
|
-
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
38284
|
-
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
38285
|
-
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
38286
|
-
return 1;
|
|
38287
|
-
}
|
|
38271
|
+
cmd.printInfo = cmd.info; // old name
|
|
38288
38272
|
|
|
38289
|
-
function
|
|
38273
|
+
function getLayerInfo(lyr, dataset) {
|
|
38290
38274
|
var n = getFeatureCount(lyr);
|
|
38291
38275
|
var o = {
|
|
38276
|
+
layer_name: lyr.name,
|
|
38292
38277
|
geometry_type: lyr.geometry_type,
|
|
38293
38278
|
feature_count: n,
|
|
38294
38279
|
null_shape_count: 0,
|
|
@@ -38296,31 +38281,47 @@ ${svg}
|
|
|
38296
38281
|
};
|
|
38297
38282
|
if (lyr.shapes && lyr.shapes.length > 0) {
|
|
38298
38283
|
o.null_shape_count = countNullShapes(lyr.shapes);
|
|
38299
|
-
o.bbox =getLayerBounds(lyr, dataset.arcs).toArray();
|
|
38284
|
+
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
38300
38285
|
o.proj4 = getProjInfo(dataset);
|
|
38301
38286
|
}
|
|
38287
|
+
o.source_file = getLayerSourceFile(lyr, dataset) || null;
|
|
38288
|
+
o.attribute_data = getAttributeTableInfo(lyr);
|
|
38302
38289
|
return o;
|
|
38303
38290
|
}
|
|
38304
38291
|
|
|
38305
|
-
//
|
|
38306
|
-
function
|
|
38307
|
-
|
|
38308
|
-
|
|
38309
|
-
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
38292
|
+
// i: (optional) record index
|
|
38293
|
+
function getAttributeTableInfo(lyr, i) {
|
|
38294
|
+
if (!lyr.data || lyr.data.size() === 0 || lyr.data.getFields().length === 0) {
|
|
38295
|
+
return null;
|
|
38310
38296
|
}
|
|
38311
|
-
|
|
38297
|
+
var fields = applyFieldOrder(lyr.data.getFields(), 'ascending');
|
|
38298
|
+
var valueName = i === undefined ? 'first_value' : 'value';
|
|
38299
|
+
return fields.map(function(fname) {
|
|
38300
|
+
return {
|
|
38301
|
+
field: fname,
|
|
38302
|
+
[valueName]: lyr.data.getReadOnlyRecordAt(i || 0)[fname]
|
|
38303
|
+
};
|
|
38304
|
+
});
|
|
38312
38305
|
}
|
|
38313
38306
|
|
|
38314
|
-
function
|
|
38315
|
-
var
|
|
38316
|
-
|
|
38317
|
-
|
|
38318
|
-
|
|
38319
|
-
|
|
38307
|
+
function formatInfo(arr) {
|
|
38308
|
+
var str = '';
|
|
38309
|
+
arr.forEach(function(info, i) {
|
|
38310
|
+
var title = 'Layer: ' + (info.layer_name || '[unnamed layer]');
|
|
38311
|
+
var tableStr = formatAttributeTableInfo(info.attribute_data);
|
|
38312
|
+
var tableWidth = measureLongestLine(tableStr);
|
|
38313
|
+
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
38314
|
+
str += '\n';
|
|
38315
|
+
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
38316
|
+
str += title + '\n';
|
|
38317
|
+
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
38318
|
+
str += formatLayerInfo(info);
|
|
38319
|
+
str += tableStr;
|
|
38320
|
+
});
|
|
38321
|
+
return str;
|
|
38320
38322
|
}
|
|
38321
38323
|
|
|
38322
|
-
function
|
|
38323
|
-
var data = getLayerData(lyr, dataset);
|
|
38324
|
+
function formatLayerInfo(data) {
|
|
38324
38325
|
var str = '';
|
|
38325
38326
|
str += "Type: " + (data.geometry_type || "tabular data") + "\n";
|
|
38326
38327
|
str += utils.format("Records: %,d\n",data.feature_count);
|
|
@@ -38331,21 +38332,19 @@ ${svg}
|
|
|
38331
38332
|
str += "Bounds: " + data.bbox.join(',') + "\n";
|
|
38332
38333
|
str += "CRS: " + data.proj4 + "\n";
|
|
38333
38334
|
}
|
|
38334
|
-
str += "Source: " + (
|
|
38335
|
+
str += "Source: " + (data.source_file || 'n/a') + "\n";
|
|
38335
38336
|
return str;
|
|
38336
38337
|
}
|
|
38337
38338
|
|
|
38338
|
-
function
|
|
38339
|
-
if (!
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
var vals = fields.map(function(fname) {
|
|
38348
|
-
return data.getReadOnlyRecordAt(i || 0)[fname];
|
|
38339
|
+
function formatAttributeTableInfo(arr) {
|
|
38340
|
+
if (!arr) return "Attribute data: [none]\n";
|
|
38341
|
+
var header = "\nAttribute data\n";
|
|
38342
|
+
var valKey = 'first_value' in arr[0] ? 'first_value' : 'value';
|
|
38343
|
+
var vals = [];
|
|
38344
|
+
var fields = [];
|
|
38345
|
+
arr.forEach(function(o) {
|
|
38346
|
+
fields.push(o.field);
|
|
38347
|
+
vals.push(o[valKey]);
|
|
38349
38348
|
});
|
|
38350
38349
|
var maxIntegralChars = vals.reduce(function(max, val) {
|
|
38351
38350
|
if (utils.isNumber(val)) {
|
|
@@ -38357,20 +38356,66 @@ ${svg}
|
|
|
38357
38356
|
var col2Arr = vals.reduce(function(memo, val) {
|
|
38358
38357
|
memo.push(formatTableValue(val, maxIntegralChars));
|
|
38359
38358
|
return memo;
|
|
38360
|
-
}, [
|
|
38359
|
+
}, [valKey == 'first_value' ? 'First value' : 'Value']);
|
|
38361
38360
|
var col1Chars = maxChars(col1Arr);
|
|
38362
38361
|
var col2Chars = maxChars(col2Arr);
|
|
38363
38362
|
var sepStr = (utils.rpad('', col1Chars + 2, '-') + '+' +
|
|
38364
38363
|
utils.rpad('', col2Chars + 2, '-')).substr(0, MAX_RULE_LEN);
|
|
38365
38364
|
var sepLine = sepStr + '\n';
|
|
38366
|
-
var table =
|
|
38365
|
+
var table = '';
|
|
38367
38366
|
col1Arr.forEach(function(col1, i) {
|
|
38368
38367
|
var w = stringDisplayWidth(col1);
|
|
38369
38368
|
table += ' ' + col1 + utils.rpad('', col1Chars - w, ' ') + ' | ' +
|
|
38370
38369
|
col2Arr[i] + '\n';
|
|
38371
38370
|
if (i === 0) table += sepLine; // separator after first line
|
|
38372
38371
|
});
|
|
38373
|
-
return table + sepLine;
|
|
38372
|
+
return header + sepLine + table + sepLine;
|
|
38373
|
+
}
|
|
38374
|
+
|
|
38375
|
+
function measureLongestLine(str) {
|
|
38376
|
+
return Math.max.apply(null, str.split('\n').map(function(line) {return stringDisplayWidth(line);}));
|
|
38377
|
+
}
|
|
38378
|
+
|
|
38379
|
+
function stringDisplayWidth(str) {
|
|
38380
|
+
var w = 0;
|
|
38381
|
+
for (var i = 0, n=str.length; i < n; i++) {
|
|
38382
|
+
w += charDisplayWidth(str.charCodeAt(i));
|
|
38383
|
+
}
|
|
38384
|
+
return w;
|
|
38385
|
+
}
|
|
38386
|
+
|
|
38387
|
+
// see https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
|
38388
|
+
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
38389
|
+
function charDisplayWidth(c) {
|
|
38390
|
+
if (c >= 0x1100 &&
|
|
38391
|
+
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
38392
|
+
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
38393
|
+
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
38394
|
+
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
38395
|
+
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
38396
|
+
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
38397
|
+
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
38398
|
+
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
38399
|
+
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
38400
|
+
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
38401
|
+
return 1;
|
|
38402
|
+
}
|
|
38403
|
+
|
|
38404
|
+
// TODO: consider polygons with zero area or other invalid geometries
|
|
38405
|
+
function countNullShapes(shapes) {
|
|
38406
|
+
var count = 0;
|
|
38407
|
+
for (var i=0; i<shapes.length; i++) {
|
|
38408
|
+
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
38409
|
+
}
|
|
38410
|
+
return count;
|
|
38411
|
+
}
|
|
38412
|
+
|
|
38413
|
+
function countNullRecords(records) {
|
|
38414
|
+
var count = 0;
|
|
38415
|
+
for (var i=0; i<records.length; i++) {
|
|
38416
|
+
if (!records[i]) count++;
|
|
38417
|
+
}
|
|
38418
|
+
return count;
|
|
38374
38419
|
}
|
|
38375
38420
|
|
|
38376
38421
|
function maxChars(arr) {
|
|
@@ -38424,8 +38469,9 @@ ${svg}
|
|
|
38424
38469
|
|
|
38425
38470
|
var Info = /*#__PURE__*/Object.freeze({
|
|
38426
38471
|
__proto__: null,
|
|
38427
|
-
|
|
38472
|
+
getLayerInfo: getLayerInfo,
|
|
38428
38473
|
getAttributeTableInfo: getAttributeTableInfo,
|
|
38474
|
+
formatAttributeTableInfo: formatAttributeTableInfo,
|
|
38429
38475
|
formatTableValue: formatTableValue
|
|
38430
38476
|
});
|
|
38431
38477
|
|
|
@@ -38477,7 +38523,7 @@ ${svg}
|
|
|
38477
38523
|
function getFeatureInfo(id, lyr, arcs) {
|
|
38478
38524
|
var msg = "Feature " + id + '\n';
|
|
38479
38525
|
msg += getShapeInfo(id, lyr, arcs);
|
|
38480
|
-
msg += getAttributeTableInfo(lyr, id);
|
|
38526
|
+
msg += formatAttributeTableInfo(getAttributeTableInfo(lyr, id));
|
|
38481
38527
|
return msg;
|
|
38482
38528
|
}
|
|
38483
38529
|
|
|
@@ -40589,7 +40635,7 @@ ${svg}
|
|
|
40589
40635
|
|
|
40590
40636
|
function getRunCommandData(target) {
|
|
40591
40637
|
var lyr = target.layers[0];
|
|
40592
|
-
var data =
|
|
40638
|
+
var data = getLayerInfo(lyr, target.dataset);
|
|
40593
40639
|
data.layer = lyr;
|
|
40594
40640
|
data.dataset = target.dataset;
|
|
40595
40641
|
return data;
|
|
@@ -42939,7 +42985,7 @@ ${svg}
|
|
|
42939
42985
|
cmd.include(opts);
|
|
42940
42986
|
|
|
42941
42987
|
} else if (name == 'info') {
|
|
42942
|
-
cmd.
|
|
42988
|
+
cmd.info(targets, opts);
|
|
42943
42989
|
|
|
42944
42990
|
} else if (name == 'inlay') {
|
|
42945
42991
|
outputLayers = cmd.inlay(targetLayers, source, targetDataset, opts);
|
|
@@ -43305,13 +43351,13 @@ ${svg}
|
|
|
43305
43351
|
commands = runAndRemoveInfoCommands(commands);
|
|
43306
43352
|
if (commands.length === 0) return done(null);
|
|
43307
43353
|
|
|
43308
|
-
// add options to -i -o -join -clip -erase commands to bypass file i/o
|
|
43354
|
+
// add options to -i -o -join -clip -erase etc. commands to bypass file i/o
|
|
43309
43355
|
// TODO: find a less kludgy solution
|
|
43310
43356
|
commands.forEach(function(cmd) {
|
|
43311
43357
|
if (commandTakesFileInput(cmd.name) && inputObj) {
|
|
43312
43358
|
cmd.options.input = inputObj;
|
|
43313
43359
|
}
|
|
43314
|
-
if (cmd.name == 'o' &&
|
|
43360
|
+
if (outputArr && (cmd.name == 'o' || cmd.name == 'info' && cmd.options.save_to)) {
|
|
43315
43361
|
cmd.options.output = outputArr;
|
|
43316
43362
|
}
|
|
43317
43363
|
});
|
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
<img class="pin-btn pinned" src="images/eye2.png">
|
|
103
103
|
</div>
|
|
104
104
|
<div class="layer-list"></div>
|
|
105
|
-
<
|
|
105
|
+
<h4>Sources</h4>
|
|
106
106
|
<div class="file-list"></div>
|
|
107
107
|
<div>
|
|
108
108
|
<div id="add-file-btn" class="dialog-btn btn">Add a file</div>
|
|
@@ -159,6 +159,8 @@
|
|
|
159
159
|
"precision=0.001"</div></div></div></div>
|
|
160
160
|
<!-- <div class="cancel-btn btn dialog-btn">Cancel</div> -->
|
|
161
161
|
<div class="save-btn btn dialog-btn">Export</div>
|
|
162
|
+
<span id="save-preference"><input type="checkbox"/>choose directory</span>
|
|
163
|
+
|
|
162
164
|
</div>
|
|
163
165
|
</div>
|
|
164
166
|
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -807,6 +807,19 @@
|
|
|
807
807
|
return !!(mapshaper.manifest && mapshaper.manifest.allow_saving) && typeof fetch == 'function';
|
|
808
808
|
};
|
|
809
809
|
|
|
810
|
+
GUI.setSavedValue = function(name, val) {
|
|
811
|
+
try {
|
|
812
|
+
window.localStorage.setItem(name, JSON.stringify(val));
|
|
813
|
+
} catch(e) {}
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
GUI.getSavedValue = function(name) {
|
|
817
|
+
try {
|
|
818
|
+
return JSON.parse(window.localStorage.getItem(name));
|
|
819
|
+
} catch(e) {}
|
|
820
|
+
return null;
|
|
821
|
+
};
|
|
822
|
+
|
|
810
823
|
GUI.getUrlVars = function() {
|
|
811
824
|
var q = window.location.search.substring(1);
|
|
812
825
|
return q.split('&').reduce(function(memo, chunk) {
|
|
@@ -1232,8 +1245,9 @@
|
|
|
1232
1245
|
}
|
|
1233
1246
|
|
|
1234
1247
|
async function saveBlobToLocalFile(filename, blob, done) {
|
|
1248
|
+
var chooseDir = GUI.getSavedValue('choose-save-dir');
|
|
1235
1249
|
done = done || function() {};
|
|
1236
|
-
if (
|
|
1250
|
+
if (chooseDir) {
|
|
1237
1251
|
saveBlobToSelectedFile(filename, blob, done);
|
|
1238
1252
|
} else {
|
|
1239
1253
|
saveBlobToDownloadsFolder(filename, blob, done);
|
|
@@ -1241,7 +1255,7 @@
|
|
|
1241
1255
|
}
|
|
1242
1256
|
|
|
1243
1257
|
function showSaveDialog(filename, blob, done) {
|
|
1244
|
-
showPopupAlert(`Save ${filename} to:`)
|
|
1258
|
+
var alert = showPopupAlert(`Save ${filename} to:`)
|
|
1245
1259
|
.button('selected folder', function() {
|
|
1246
1260
|
saveBlobToSelectedFile(filename, blob, done);
|
|
1247
1261
|
})
|
|
@@ -1251,6 +1265,7 @@
|
|
|
1251
1265
|
.onCancel(done);
|
|
1252
1266
|
}
|
|
1253
1267
|
|
|
1268
|
+
|
|
1254
1269
|
async function saveBlobToSelectedFile(filename, blob, done) {
|
|
1255
1270
|
// see: https://developer.chrome.com/articles/file-system-access/
|
|
1256
1271
|
// note: saving multiple files to a directory using showDirectoryPicker()
|
|
@@ -1422,7 +1437,9 @@
|
|
|
1422
1437
|
closeMenu(100);
|
|
1423
1438
|
}).text('restore');
|
|
1424
1439
|
El('span').addClass('save-menu-btn').appendTo(line).on('click', async function(e) {
|
|
1425
|
-
var
|
|
1440
|
+
var obj = await idb.get(item.id);
|
|
1441
|
+
await internal.applyCompression(obj, {consume: true});
|
|
1442
|
+
var buf = internal.pack(obj);
|
|
1426
1443
|
saveBlobToLocalFile('mapshaper_snapshot.msx', new Blob([buf]));
|
|
1427
1444
|
}).text('export');
|
|
1428
1445
|
El('span').addClass('save-menu-btn').appendTo(line).on('click', async function(e) {
|
|
@@ -1470,20 +1487,24 @@
|
|
|
1470
1487
|
}
|
|
1471
1488
|
|
|
1472
1489
|
async function saveSnapshot(gui) {
|
|
1473
|
-
var
|
|
1490
|
+
var obj = await captureSnapshot(gui);
|
|
1491
|
+
// storing an unpacked object is usually a bit faster (~20%)
|
|
1492
|
+
// note: we don't know the size of unpacked snapshot objects
|
|
1493
|
+
// obj = internal.pack(obj);
|
|
1474
1494
|
var entryId = String(++snapshotCount).padStart(3, '0');
|
|
1475
1495
|
var snapshotId = sessionId + '_' + entryId; // e.g. session_d89fw_001
|
|
1496
|
+
var size = obj.length;
|
|
1476
1497
|
var entry = {
|
|
1477
1498
|
created: Date.now(),
|
|
1478
1499
|
session: sessionId,
|
|
1479
1500
|
id: snapshotId,
|
|
1480
1501
|
name: snapshotCount + '.',
|
|
1481
1502
|
number: snapshotCount,
|
|
1482
|
-
size:
|
|
1483
|
-
display_size: formatSize(
|
|
1503
|
+
size: size,
|
|
1504
|
+
display_size: formatSize(size)
|
|
1484
1505
|
};
|
|
1485
1506
|
|
|
1486
|
-
await idb.set(entry.id,
|
|
1507
|
+
await idb.set(entry.id, obj);
|
|
1487
1508
|
await addToIndex(entry);
|
|
1488
1509
|
renderMenu();
|
|
1489
1510
|
}
|
|
@@ -1492,9 +1513,8 @@
|
|
|
1492
1513
|
function formatSize(bytes) {
|
|
1493
1514
|
var kb = Math.round(bytes / 1000);
|
|
1494
1515
|
var mb = (bytes / 1e6).toFixed(1);
|
|
1495
|
-
if (kb
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1516
|
+
if (!kb) return '';
|
|
1517
|
+
if (kb < 990) return kb + 'kB';
|
|
1498
1518
|
return mb + 'MB';
|
|
1499
1519
|
}
|
|
1500
1520
|
|
|
@@ -1516,13 +1536,13 @@
|
|
|
1516
1536
|
}
|
|
1517
1537
|
|
|
1518
1538
|
async function restoreSnapshotById(id, gui) {
|
|
1519
|
-
var
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1539
|
+
var data;
|
|
1540
|
+
try {
|
|
1541
|
+
data = await internal.restoreSessionData(await idb.get(id));
|
|
1542
|
+
} catch(e) {
|
|
1543
|
+
console.error(e);
|
|
1544
|
+
stop$1('Snapshot is not available');
|
|
1523
1545
|
}
|
|
1524
|
-
var data = await internal.unpackSession(buf);
|
|
1525
|
-
buf = null;
|
|
1526
1546
|
gui.model.clear();
|
|
1527
1547
|
importDatasets(data.datasets, gui);
|
|
1528
1548
|
gui.clearMode();
|
|
@@ -1535,7 +1555,7 @@
|
|
|
1535
1555
|
if (buf instanceof ArrayBuffer) {
|
|
1536
1556
|
buf = new Uint8Array(buf);
|
|
1537
1557
|
}
|
|
1538
|
-
var data = await internal.
|
|
1558
|
+
var data = await internal.unpackSessionData(buf);
|
|
1539
1559
|
importDatasets(data.datasets, gui);
|
|
1540
1560
|
}
|
|
1541
1561
|
|
|
@@ -1558,7 +1578,7 @@
|
|
|
1558
1578
|
// console.timeEnd('msx')
|
|
1559
1579
|
delete lyr.active;
|
|
1560
1580
|
obj.gui = getGuiState(gui);
|
|
1561
|
-
return
|
|
1581
|
+
return obj;
|
|
1562
1582
|
}
|
|
1563
1583
|
|
|
1564
1584
|
// TODO: capture gui state information to allow restoring more of the UI
|
|
@@ -3025,22 +3045,12 @@
|
|
|
3025
3045
|
}
|
|
3026
3046
|
|
|
3027
3047
|
function getHistory() {
|
|
3028
|
-
|
|
3029
|
-
try {
|
|
3030
|
-
hist = JSON.parse(window.localStorage.getItem('console_history'));
|
|
3031
|
-
} catch(e) {
|
|
3032
|
-
}
|
|
3033
|
-
return hist && hist.length > 0 ? hist : [];
|
|
3048
|
+
return GUI.getSavedValue('console_history') || [];
|
|
3034
3049
|
}
|
|
3035
3050
|
|
|
3036
3051
|
function saveHistory() {
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
if (history.length) {
|
|
3040
|
-
window.localStorage.setItem('console_history', JSON.stringify(history.slice(-50)));
|
|
3041
|
-
}
|
|
3042
|
-
} catch(e) {
|
|
3043
|
-
}
|
|
3052
|
+
history = history.filter(Boolean); // TODO: fix condition that leaves a blank line on the history
|
|
3053
|
+
GUI.setSavedValue('console_history', history.slice(-100));
|
|
3044
3054
|
}
|
|
3045
3055
|
|
|
3046
3056
|
function toLog(str, cname) {
|
|
@@ -3656,10 +3666,20 @@
|
|
|
3656
3666
|
internal.writeFiles = function() {
|
|
3657
3667
|
error$1(unsupportedMsg);
|
|
3658
3668
|
};
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3669
|
+
return;
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
new SimpleButton(menu.findChild('.save-btn').addClass('default-btn')).on('click', onExportClick);
|
|
3673
|
+
gui.addMode('export', turnOn, turnOff, exportBtn);
|
|
3674
|
+
gui.keyboard.onMenuSubmit(menu, onExportClick);
|
|
3675
|
+
if (window.showSaveFilePicker) {
|
|
3676
|
+
menu.findChild('#save-preference')
|
|
3677
|
+
.css('display', 'inline-block')
|
|
3678
|
+
.findChild('input')
|
|
3679
|
+
.on('change', function() {
|
|
3680
|
+
GUI.setSavedValue('choose-save-dir', this.checked);
|
|
3681
|
+
})
|
|
3682
|
+
.attr('checked', GUI.getSavedValue('choose-save-dir') || false);
|
|
3663
3683
|
}
|
|
3664
3684
|
|
|
3665
3685
|
function turnOn() {
|
|
@@ -8697,7 +8717,6 @@
|
|
|
8697
8717
|
function active(e) {
|
|
8698
8718
|
return e.id > -1 && gui.interaction.getMode() == 'add-points';
|
|
8699
8719
|
}
|
|
8700
|
-
|
|
8701
8720
|
}
|
|
8702
8721
|
|
|
8703
8722
|
function Pencil(gui, mouse, hit) {
|
|
@@ -8720,10 +8739,7 @@
|
|
|
8720
8739
|
}
|
|
8721
8740
|
|
|
8722
8741
|
function initDrawing(gui, ext, mouse, hit) {
|
|
8723
|
-
|
|
8724
8742
|
initPointDrawing(gui, new Pencil(gui, mouse, hit));
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
8743
|
}
|
|
8728
8744
|
|
|
8729
8745
|
var darkStroke = "#334",
|
|
@@ -9780,19 +9796,26 @@
|
|
|
9780
9796
|
bx = t.bx,
|
|
9781
9797
|
by = t.by;
|
|
9782
9798
|
var x, y, xp, yp;
|
|
9799
|
+
var count = 0;
|
|
9783
9800
|
if (!vec.hasNext()) return;
|
|
9784
|
-
x =
|
|
9785
|
-
y =
|
|
9801
|
+
x = round(vec.x * mx + bx);
|
|
9802
|
+
y = round(vec.y * my + by);
|
|
9786
9803
|
ctx.moveTo(x, y);
|
|
9787
9804
|
while (vec.hasNext()) {
|
|
9805
|
+
xp = x;
|
|
9806
|
+
yp = y;
|
|
9788
9807
|
x = round(vec.x * mx + bx);
|
|
9789
9808
|
y = round(vec.y * my + by);
|
|
9790
9809
|
if (x != xp || y != yp) {
|
|
9791
9810
|
ctx.lineTo(x, y);
|
|
9792
|
-
|
|
9793
|
-
yp = y;
|
|
9811
|
+
count++;
|
|
9794
9812
|
}
|
|
9795
9813
|
}
|
|
9814
|
+
if (count === 0) {
|
|
9815
|
+
// draw a tiny line if all coords round to the same location,
|
|
9816
|
+
// so tiny shapes with strokes will consistently be drawn as dots,
|
|
9817
|
+
ctx.lineTo(x + 0.1, y);
|
|
9818
|
+
}
|
|
9796
9819
|
}
|
|
9797
9820
|
|
|
9798
9821
|
function roundToPix(x) {
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.24";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -10620,7 +10620,8 @@
|
|
|
10620
10620
|
buf = new Uint8Array(buf);
|
|
10621
10621
|
}
|
|
10622
10622
|
opts = opts || {};
|
|
10623
|
-
var
|
|
10623
|
+
var gunzip$1 = runningInBrowser() ? utils.promisify(gunzip) : utils.promisify(require('zlib').gunzip);
|
|
10624
|
+
var out = await gunzip$1(buf, opts);
|
|
10624
10625
|
if (opts.filename && !isImportableAsBinary(opts.filename)) {
|
|
10625
10626
|
out = strFromU8(out);
|
|
10626
10627
|
}
|
|
@@ -10628,8 +10629,6 @@
|
|
|
10628
10629
|
}
|
|
10629
10630
|
|
|
10630
10631
|
function gunzipSync(buf, filename) {
|
|
10631
|
-
// TODO: use native module in Node
|
|
10632
|
-
// require('zlib').
|
|
10633
10632
|
if (buf instanceof ArrayBuffer) {
|
|
10634
10633
|
buf = new Uint8Array(buf);
|
|
10635
10634
|
}
|
|
@@ -10768,16 +10767,39 @@
|
|
|
10768
10767
|
// gui: (optional) gui instance
|
|
10769
10768
|
//
|
|
10770
10769
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10771
|
-
|
|
10770
|
+
var obj = {
|
|
10772
10771
|
version: 1,
|
|
10773
10772
|
created: (new Date).toISOString(),
|
|
10774
|
-
datasets: await Promise.all(datasets.map(
|
|
10773
|
+
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10775
10774
|
};
|
|
10775
|
+
if (opts.compact) {
|
|
10776
|
+
await applyCompression(obj);
|
|
10777
|
+
}
|
|
10778
|
+
return obj;
|
|
10779
|
+
}
|
|
10780
|
+
|
|
10781
|
+
async function applyCompression(obj, opts) {
|
|
10782
|
+
var promises = [];
|
|
10783
|
+
obj.datasets.forEach(d => {
|
|
10784
|
+
if (d.arcs) promises.push(compressArcs(d.arcs, opts));
|
|
10785
|
+
});
|
|
10786
|
+
await Promise.all(promises);
|
|
10787
|
+
}
|
|
10788
|
+
|
|
10789
|
+
async function compressArcs(obj, opts) {
|
|
10790
|
+
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10791
|
+
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10792
|
+
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
10793
|
+
var results = await Promise.all(promises);
|
|
10794
|
+
obj.nn = results.shift();
|
|
10795
|
+
obj.xx = results.shift();
|
|
10796
|
+
obj.yy = results.shift();
|
|
10797
|
+
if (obj.zz) obj.zz = results.shift();
|
|
10776
10798
|
}
|
|
10777
10799
|
|
|
10778
10800
|
async function exportDataset(dataset, opts) {
|
|
10779
10801
|
return {
|
|
10780
|
-
arcs: dataset.arcs ?
|
|
10802
|
+
arcs: dataset.arcs ? exportArcs(dataset.arcs) : null,
|
|
10781
10803
|
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10782
10804
|
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10783
10805
|
};
|
|
@@ -10787,38 +10809,22 @@
|
|
|
10787
10809
|
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10788
10810
|
}
|
|
10789
10811
|
|
|
10790
|
-
|
|
10812
|
+
function exportArcs(arcs) {
|
|
10791
10813
|
var data = arcs.getVertexData();
|
|
10792
|
-
|
|
10814
|
+
return {
|
|
10793
10815
|
nn: typedArrayToBuffer(data.nn),
|
|
10794
10816
|
xx: typedArrayToBuffer(data.xx),
|
|
10795
10817
|
yy: typedArrayToBuffer(data.yy),
|
|
10796
10818
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10797
10819
|
zlimit: arcs.getRetainedInterval()
|
|
10798
10820
|
};
|
|
10799
|
-
|
|
10800
|
-
// gzipping typically sees about 70% compression on unrounded coordinates
|
|
10801
|
-
// -- possibly not worth the time
|
|
10802
|
-
if (opts.compact) {
|
|
10803
|
-
var gzipOpts = {level: 1, consume: false};
|
|
10804
|
-
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10805
|
-
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
10806
|
-
var results = await Promise.all(promises);
|
|
10807
|
-
obj.nn = results.shift();
|
|
10808
|
-
obj.xx = results.shift();
|
|
10809
|
-
obj.yy = results.shift();
|
|
10810
|
-
if (obj.zz) obj.zz = results.shift();
|
|
10811
|
-
}
|
|
10812
|
-
return obj;
|
|
10813
10821
|
}
|
|
10814
10822
|
|
|
10815
10823
|
async function exportLayer(lyr) {
|
|
10816
|
-
// console.time('table')
|
|
10817
10824
|
var data = null;
|
|
10818
10825
|
if (lyr.data) {
|
|
10819
10826
|
data = await exportTable2(lyr.data);
|
|
10820
10827
|
}
|
|
10821
|
-
// console.timeEnd('table')
|
|
10822
10828
|
return {
|
|
10823
10829
|
name: lyr.name || null,
|
|
10824
10830
|
geometry_type: lyr.geometry_type || null,
|
|
@@ -10845,6 +10851,7 @@
|
|
|
10845
10851
|
exportPackedDatasets: exportPackedDatasets,
|
|
10846
10852
|
pack: pack,
|
|
10847
10853
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10854
|
+
applyCompression: applyCompression,
|
|
10848
10855
|
exportDataset: exportDataset
|
|
10849
10856
|
});
|
|
10850
10857
|
|
|
@@ -24922,6 +24929,9 @@ ${svg}
|
|
|
24922
24929
|
|
|
24923
24930
|
parser.command('info')
|
|
24924
24931
|
.describe('print information about data layers')
|
|
24932
|
+
.option('save-to', {
|
|
24933
|
+
describe: 'name of file to save info in JSON format'
|
|
24934
|
+
})
|
|
24925
24935
|
.option('target', targetOpt);
|
|
24926
24936
|
|
|
24927
24937
|
parser.command('inspect')
|
|
@@ -27457,12 +27467,14 @@ ${svg}
|
|
|
27457
27467
|
// Import datasets contained in a BSON blob
|
|
27458
27468
|
// Return command target as a dataset
|
|
27459
27469
|
//
|
|
27460
|
-
async function
|
|
27461
|
-
|
|
27470
|
+
async function unpackSessionData(buf) {
|
|
27471
|
+
return restoreSessionData(unpack(buf, {}));
|
|
27472
|
+
}
|
|
27473
|
+
|
|
27474
|
+
async function restoreSessionData(obj) {
|
|
27462
27475
|
if (!isValidSession(obj)) {
|
|
27463
27476
|
stop('Invalid mapshaper session data object');
|
|
27464
27477
|
}
|
|
27465
|
-
|
|
27466
27478
|
var datasets = await Promise.all(obj.datasets.map(importDataset));
|
|
27467
27479
|
return Object.assign(obj, {datasets: datasets});
|
|
27468
27480
|
}
|
|
@@ -27539,7 +27551,8 @@ ${svg}
|
|
|
27539
27551
|
|
|
27540
27552
|
var Unpack = /*#__PURE__*/Object.freeze({
|
|
27541
27553
|
__proto__: null,
|
|
27542
|
-
|
|
27554
|
+
unpackSessionData: unpackSessionData,
|
|
27555
|
+
restoreSessionData: restoreSessionData
|
|
27543
27556
|
});
|
|
27544
27557
|
|
|
27545
27558
|
cmd.importFiles = async function(catalog, opts) {
|
|
@@ -27593,7 +27606,7 @@ ${svg}
|
|
|
27593
27606
|
|
|
27594
27607
|
async function importMshpFile(file, catalog, opts) {
|
|
27595
27608
|
var buf = cli.readFile(file, null, opts.input);
|
|
27596
|
-
var obj = await
|
|
27609
|
+
var obj = await unpackSessionData(buf);
|
|
27597
27610
|
obj.datasets.forEach(catalog.addDataset, catalog);
|
|
27598
27611
|
return obj.target;
|
|
27599
27612
|
}
|
|
@@ -38240,55 +38253,27 @@ ${svg}
|
|
|
38240
38253
|
|
|
38241
38254
|
var MAX_RULE_LEN = 50;
|
|
38242
38255
|
|
|
38243
|
-
cmd.
|
|
38244
|
-
var
|
|
38245
|
-
layers.
|
|
38246
|
-
|
|
38247
|
-
var tableStr = getAttributeTableInfo(o.layer);
|
|
38248
|
-
var tableWidth = measureLongestLine(tableStr);
|
|
38249
|
-
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
38250
|
-
str += '\n';
|
|
38251
|
-
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
38252
|
-
str += title + '\n';
|
|
38253
|
-
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
38254
|
-
str += getLayerInfo(o.layer, o.dataset);
|
|
38255
|
-
str += tableStr;
|
|
38256
|
+
cmd.info = function(targets, opts) {
|
|
38257
|
+
var layers = expandCommandTargets(targets);
|
|
38258
|
+
var arr = layers.map(function(o) {
|
|
38259
|
+
return getLayerInfo(o.layer, o.dataset);
|
|
38256
38260
|
});
|
|
38257
|
-
message(
|
|
38258
|
-
|
|
38259
|
-
|
|
38260
|
-
|
|
38261
|
-
|
|
38262
|
-
|
|
38263
|
-
|
|
38264
|
-
function stringDisplayWidth(str) {
|
|
38265
|
-
var w = 0;
|
|
38266
|
-
for (var i = 0, n=str.length; i < n; i++) {
|
|
38267
|
-
w += charDisplayWidth(str.charCodeAt(i));
|
|
38261
|
+
message(formatInfo(arr));
|
|
38262
|
+
if (opts.save_to) {
|
|
38263
|
+
var output = [{
|
|
38264
|
+
filename: opts.save_to + (opts.save_to.endsWith('.json') ? '' : '.json'),
|
|
38265
|
+
content: JSON.stringify(arr, null, 2)
|
|
38266
|
+
}];
|
|
38267
|
+
writeFiles(output, opts);
|
|
38268
38268
|
}
|
|
38269
|
-
|
|
38270
|
-
}
|
|
38269
|
+
};
|
|
38271
38270
|
|
|
38272
|
-
//
|
|
38273
|
-
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
38274
|
-
function charDisplayWidth(c) {
|
|
38275
|
-
if (c >= 0x1100 &&
|
|
38276
|
-
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
38277
|
-
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
38278
|
-
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
38279
|
-
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
38280
|
-
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
38281
|
-
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
38282
|
-
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
38283
|
-
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
38284
|
-
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
38285
|
-
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
38286
|
-
return 1;
|
|
38287
|
-
}
|
|
38271
|
+
cmd.printInfo = cmd.info; // old name
|
|
38288
38272
|
|
|
38289
|
-
function
|
|
38273
|
+
function getLayerInfo(lyr, dataset) {
|
|
38290
38274
|
var n = getFeatureCount(lyr);
|
|
38291
38275
|
var o = {
|
|
38276
|
+
layer_name: lyr.name,
|
|
38292
38277
|
geometry_type: lyr.geometry_type,
|
|
38293
38278
|
feature_count: n,
|
|
38294
38279
|
null_shape_count: 0,
|
|
@@ -38296,31 +38281,47 @@ ${svg}
|
|
|
38296
38281
|
};
|
|
38297
38282
|
if (lyr.shapes && lyr.shapes.length > 0) {
|
|
38298
38283
|
o.null_shape_count = countNullShapes(lyr.shapes);
|
|
38299
|
-
o.bbox =getLayerBounds(lyr, dataset.arcs).toArray();
|
|
38284
|
+
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
38300
38285
|
o.proj4 = getProjInfo(dataset);
|
|
38301
38286
|
}
|
|
38287
|
+
o.source_file = getLayerSourceFile(lyr, dataset) || null;
|
|
38288
|
+
o.attribute_data = getAttributeTableInfo(lyr);
|
|
38302
38289
|
return o;
|
|
38303
38290
|
}
|
|
38304
38291
|
|
|
38305
|
-
//
|
|
38306
|
-
function
|
|
38307
|
-
|
|
38308
|
-
|
|
38309
|
-
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
38292
|
+
// i: (optional) record index
|
|
38293
|
+
function getAttributeTableInfo(lyr, i) {
|
|
38294
|
+
if (!lyr.data || lyr.data.size() === 0 || lyr.data.getFields().length === 0) {
|
|
38295
|
+
return null;
|
|
38310
38296
|
}
|
|
38311
|
-
|
|
38297
|
+
var fields = applyFieldOrder(lyr.data.getFields(), 'ascending');
|
|
38298
|
+
var valueName = i === undefined ? 'first_value' : 'value';
|
|
38299
|
+
return fields.map(function(fname) {
|
|
38300
|
+
return {
|
|
38301
|
+
field: fname,
|
|
38302
|
+
[valueName]: lyr.data.getReadOnlyRecordAt(i || 0)[fname]
|
|
38303
|
+
};
|
|
38304
|
+
});
|
|
38312
38305
|
}
|
|
38313
38306
|
|
|
38314
|
-
function
|
|
38315
|
-
var
|
|
38316
|
-
|
|
38317
|
-
|
|
38318
|
-
|
|
38319
|
-
|
|
38307
|
+
function formatInfo(arr) {
|
|
38308
|
+
var str = '';
|
|
38309
|
+
arr.forEach(function(info, i) {
|
|
38310
|
+
var title = 'Layer: ' + (info.layer_name || '[unnamed layer]');
|
|
38311
|
+
var tableStr = formatAttributeTableInfo(info.attribute_data);
|
|
38312
|
+
var tableWidth = measureLongestLine(tableStr);
|
|
38313
|
+
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
38314
|
+
str += '\n';
|
|
38315
|
+
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
38316
|
+
str += title + '\n';
|
|
38317
|
+
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
38318
|
+
str += formatLayerInfo(info);
|
|
38319
|
+
str += tableStr;
|
|
38320
|
+
});
|
|
38321
|
+
return str;
|
|
38320
38322
|
}
|
|
38321
38323
|
|
|
38322
|
-
function
|
|
38323
|
-
var data = getLayerData(lyr, dataset);
|
|
38324
|
+
function formatLayerInfo(data) {
|
|
38324
38325
|
var str = '';
|
|
38325
38326
|
str += "Type: " + (data.geometry_type || "tabular data") + "\n";
|
|
38326
38327
|
str += utils.format("Records: %,d\n",data.feature_count);
|
|
@@ -38331,21 +38332,19 @@ ${svg}
|
|
|
38331
38332
|
str += "Bounds: " + data.bbox.join(',') + "\n";
|
|
38332
38333
|
str += "CRS: " + data.proj4 + "\n";
|
|
38333
38334
|
}
|
|
38334
|
-
str += "Source: " + (
|
|
38335
|
+
str += "Source: " + (data.source_file || 'n/a') + "\n";
|
|
38335
38336
|
return str;
|
|
38336
38337
|
}
|
|
38337
38338
|
|
|
38338
|
-
function
|
|
38339
|
-
if (!
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
var vals = fields.map(function(fname) {
|
|
38348
|
-
return data.getReadOnlyRecordAt(i || 0)[fname];
|
|
38339
|
+
function formatAttributeTableInfo(arr) {
|
|
38340
|
+
if (!arr) return "Attribute data: [none]\n";
|
|
38341
|
+
var header = "\nAttribute data\n";
|
|
38342
|
+
var valKey = 'first_value' in arr[0] ? 'first_value' : 'value';
|
|
38343
|
+
var vals = [];
|
|
38344
|
+
var fields = [];
|
|
38345
|
+
arr.forEach(function(o) {
|
|
38346
|
+
fields.push(o.field);
|
|
38347
|
+
vals.push(o[valKey]);
|
|
38349
38348
|
});
|
|
38350
38349
|
var maxIntegralChars = vals.reduce(function(max, val) {
|
|
38351
38350
|
if (utils.isNumber(val)) {
|
|
@@ -38357,20 +38356,66 @@ ${svg}
|
|
|
38357
38356
|
var col2Arr = vals.reduce(function(memo, val) {
|
|
38358
38357
|
memo.push(formatTableValue(val, maxIntegralChars));
|
|
38359
38358
|
return memo;
|
|
38360
|
-
}, [
|
|
38359
|
+
}, [valKey == 'first_value' ? 'First value' : 'Value']);
|
|
38361
38360
|
var col1Chars = maxChars(col1Arr);
|
|
38362
38361
|
var col2Chars = maxChars(col2Arr);
|
|
38363
38362
|
var sepStr = (utils.rpad('', col1Chars + 2, '-') + '+' +
|
|
38364
38363
|
utils.rpad('', col2Chars + 2, '-')).substr(0, MAX_RULE_LEN);
|
|
38365
38364
|
var sepLine = sepStr + '\n';
|
|
38366
|
-
var table =
|
|
38365
|
+
var table = '';
|
|
38367
38366
|
col1Arr.forEach(function(col1, i) {
|
|
38368
38367
|
var w = stringDisplayWidth(col1);
|
|
38369
38368
|
table += ' ' + col1 + utils.rpad('', col1Chars - w, ' ') + ' | ' +
|
|
38370
38369
|
col2Arr[i] + '\n';
|
|
38371
38370
|
if (i === 0) table += sepLine; // separator after first line
|
|
38372
38371
|
});
|
|
38373
|
-
return table + sepLine;
|
|
38372
|
+
return header + sepLine + table + sepLine;
|
|
38373
|
+
}
|
|
38374
|
+
|
|
38375
|
+
function measureLongestLine(str) {
|
|
38376
|
+
return Math.max.apply(null, str.split('\n').map(function(line) {return stringDisplayWidth(line);}));
|
|
38377
|
+
}
|
|
38378
|
+
|
|
38379
|
+
function stringDisplayWidth(str) {
|
|
38380
|
+
var w = 0;
|
|
38381
|
+
for (var i = 0, n=str.length; i < n; i++) {
|
|
38382
|
+
w += charDisplayWidth(str.charCodeAt(i));
|
|
38383
|
+
}
|
|
38384
|
+
return w;
|
|
38385
|
+
}
|
|
38386
|
+
|
|
38387
|
+
// see https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
|
38388
|
+
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
38389
|
+
function charDisplayWidth(c) {
|
|
38390
|
+
if (c >= 0x1100 &&
|
|
38391
|
+
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
38392
|
+
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
38393
|
+
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
38394
|
+
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
38395
|
+
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
38396
|
+
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
38397
|
+
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
38398
|
+
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
38399
|
+
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
38400
|
+
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
38401
|
+
return 1;
|
|
38402
|
+
}
|
|
38403
|
+
|
|
38404
|
+
// TODO: consider polygons with zero area or other invalid geometries
|
|
38405
|
+
function countNullShapes(shapes) {
|
|
38406
|
+
var count = 0;
|
|
38407
|
+
for (var i=0; i<shapes.length; i++) {
|
|
38408
|
+
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
38409
|
+
}
|
|
38410
|
+
return count;
|
|
38411
|
+
}
|
|
38412
|
+
|
|
38413
|
+
function countNullRecords(records) {
|
|
38414
|
+
var count = 0;
|
|
38415
|
+
for (var i=0; i<records.length; i++) {
|
|
38416
|
+
if (!records[i]) count++;
|
|
38417
|
+
}
|
|
38418
|
+
return count;
|
|
38374
38419
|
}
|
|
38375
38420
|
|
|
38376
38421
|
function maxChars(arr) {
|
|
@@ -38424,8 +38469,9 @@ ${svg}
|
|
|
38424
38469
|
|
|
38425
38470
|
var Info = /*#__PURE__*/Object.freeze({
|
|
38426
38471
|
__proto__: null,
|
|
38427
|
-
|
|
38472
|
+
getLayerInfo: getLayerInfo,
|
|
38428
38473
|
getAttributeTableInfo: getAttributeTableInfo,
|
|
38474
|
+
formatAttributeTableInfo: formatAttributeTableInfo,
|
|
38429
38475
|
formatTableValue: formatTableValue
|
|
38430
38476
|
});
|
|
38431
38477
|
|
|
@@ -38477,7 +38523,7 @@ ${svg}
|
|
|
38477
38523
|
function getFeatureInfo(id, lyr, arcs) {
|
|
38478
38524
|
var msg = "Feature " + id + '\n';
|
|
38479
38525
|
msg += getShapeInfo(id, lyr, arcs);
|
|
38480
|
-
msg += getAttributeTableInfo(lyr, id);
|
|
38526
|
+
msg += formatAttributeTableInfo(getAttributeTableInfo(lyr, id));
|
|
38481
38527
|
return msg;
|
|
38482
38528
|
}
|
|
38483
38529
|
|
|
@@ -40589,7 +40635,7 @@ ${svg}
|
|
|
40589
40635
|
|
|
40590
40636
|
function getRunCommandData(target) {
|
|
40591
40637
|
var lyr = target.layers[0];
|
|
40592
|
-
var data =
|
|
40638
|
+
var data = getLayerInfo(lyr, target.dataset);
|
|
40593
40639
|
data.layer = lyr;
|
|
40594
40640
|
data.dataset = target.dataset;
|
|
40595
40641
|
return data;
|
|
@@ -42939,7 +42985,7 @@ ${svg}
|
|
|
42939
42985
|
cmd.include(opts);
|
|
42940
42986
|
|
|
42941
42987
|
} else if (name == 'info') {
|
|
42942
|
-
cmd.
|
|
42988
|
+
cmd.info(targets, opts);
|
|
42943
42989
|
|
|
42944
42990
|
} else if (name == 'inlay') {
|
|
42945
42991
|
outputLayers = cmd.inlay(targetLayers, source, targetDataset, opts);
|
|
@@ -43305,13 +43351,13 @@ ${svg}
|
|
|
43305
43351
|
commands = runAndRemoveInfoCommands(commands);
|
|
43306
43352
|
if (commands.length === 0) return done(null);
|
|
43307
43353
|
|
|
43308
|
-
// add options to -i -o -join -clip -erase commands to bypass file i/o
|
|
43354
|
+
// add options to -i -o -join -clip -erase etc. commands to bypass file i/o
|
|
43309
43355
|
// TODO: find a less kludgy solution
|
|
43310
43356
|
commands.forEach(function(cmd) {
|
|
43311
43357
|
if (commandTakesFileInput(cmd.name) && inputObj) {
|
|
43312
43358
|
cmd.options.input = inputObj;
|
|
43313
43359
|
}
|
|
43314
|
-
if (cmd.name == 'o' &&
|
|
43360
|
+
if (outputArr && (cmd.name == 'o' || cmd.name == 'info' && cmd.options.save_to)) {
|
|
43315
43361
|
cmd.options.output = outputArr;
|
|
43316
43362
|
}
|
|
43317
43363
|
});
|
package/www/page.css
CHANGED
|
@@ -292,9 +292,6 @@ div.error-box {
|
|
|
292
292
|
font-size: 16px;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
div.error-box > div {
|
|
296
|
-
|
|
297
|
-
}
|
|
298
295
|
|
|
299
296
|
/* --- Splash screen -------------- */
|
|
300
297
|
|
|
@@ -516,22 +513,26 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
516
513
|
}
|
|
517
514
|
|
|
518
515
|
.info-box h4 {
|
|
519
|
-
font-size:
|
|
516
|
+
font-size: 1.085em;
|
|
520
517
|
font-weight: normal;
|
|
521
|
-
margin: 0 0
|
|
518
|
+
margin: 0 0 2px 0;
|
|
522
519
|
}
|
|
523
520
|
|
|
524
521
|
.info-box p {
|
|
525
522
|
white-space: pre-line;
|
|
526
523
|
margin: 0 0 7px 0;
|
|
524
|
+
line-height: 1.2;
|
|
525
|
+
font-size: 90%;
|
|
527
526
|
}
|
|
528
527
|
|
|
529
528
|
.option-menu {
|
|
530
529
|
padding: 0 0 9px 0;
|
|
531
530
|
}
|
|
532
531
|
|
|
533
|
-
|
|
534
|
-
.option-menu input[type="checkbox"]
|
|
532
|
+
/*.option-menu input[type="radio"],
|
|
533
|
+
.option-menu input[type="checkbox"] */
|
|
534
|
+
.info-box input[type="radio"],
|
|
535
|
+
.info-box input[type="checkbox"]
|
|
535
536
|
{
|
|
536
537
|
position: relative;
|
|
537
538
|
top: 1px;
|
|
@@ -539,16 +540,16 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
539
540
|
height: 12px;
|
|
540
541
|
}
|
|
541
542
|
|
|
542
|
-
.
|
|
543
|
+
.info-box .tip-button {
|
|
543
544
|
margin-left: 12px;
|
|
544
545
|
margin-top: 3px;
|
|
545
546
|
}
|
|
546
547
|
|
|
547
|
-
.
|
|
548
|
+
.info-box input[type="checkbox"] {
|
|
548
549
|
margin: 3px 5px 0 1px;
|
|
549
550
|
}
|
|
550
551
|
|
|
551
|
-
.
|
|
552
|
+
.info-box input.radio {
|
|
552
553
|
margin: 0 5px 0 0;
|
|
553
554
|
}
|
|
554
555
|
|
|
@@ -1079,10 +1080,7 @@ img.close-btn:hover,
|
|
|
1079
1080
|
height: 100%;
|
|
1080
1081
|
}
|
|
1081
1082
|
|
|
1082
|
-
|
|
1083
|
-
line-height: 1.2;
|
|
1084
|
-
font-size: 90%;
|
|
1085
|
-
}
|
|
1083
|
+
|
|
1086
1084
|
|
|
1087
1085
|
.basemap-styles {
|
|
1088
1086
|
margin: 0 -2px;
|
|
@@ -1212,6 +1210,13 @@ div.basemap-style-btn.active img {
|
|
|
1212
1210
|
top: 23px;
|
|
1213
1211
|
}
|
|
1214
1212
|
|
|
1213
|
+
#save-preference {
|
|
1214
|
+
display: none;
|
|
1215
|
+
position: relative;
|
|
1216
|
+
top: 1px;
|
|
1217
|
+
left: 5px;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1215
1220
|
.nav-sub-menu {
|
|
1216
1221
|
position: absolute;
|
|
1217
1222
|
z-index: -1;
|