mapshaper 0.6.44 → 0.6.45
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 +238 -161
- package/package.json +2 -2
- package/www/index.html +1 -1
- package/www/mapshaper-gui.js +63 -7
- package/www/mapshaper.js +238 -161
- package/www/page.css +9 -5
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.45";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1882,12 +1882,67 @@
|
|
|
1882
1882
|
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1883
1883
|
}
|
|
1884
1884
|
|
|
1885
|
+
function countFilteredVertices(zz, zlimit) {
|
|
1886
|
+
var count = 0;
|
|
1887
|
+
for (var i=0, n = zz.length; i<n; i++) {
|
|
1888
|
+
if (zz[i] >= zlimit) count++;
|
|
1889
|
+
}
|
|
1890
|
+
return count;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
function filterVertexData(o, zlimit) {
|
|
1894
|
+
if (!o.zz) error('Expected simplification data');
|
|
1895
|
+
var xx = o.xx,
|
|
1896
|
+
yy = o.yy,
|
|
1897
|
+
zz = o.zz,
|
|
1898
|
+
len2 = countFilteredVertices(zz, zlimit),
|
|
1899
|
+
arcCount = o.nn.length,
|
|
1900
|
+
xx2 = new Float64Array(len2),
|
|
1901
|
+
yy2 = new Float64Array(len2),
|
|
1902
|
+
zz2 = new Float64Array(len2),
|
|
1903
|
+
nn2 = new Int32Array(arcCount),
|
|
1904
|
+
i = 0, i2 = 0,
|
|
1905
|
+
n, n2;
|
|
1906
|
+
|
|
1907
|
+
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
1908
|
+
n2 = 0;
|
|
1909
|
+
n = o.nn[arcId];
|
|
1910
|
+
for (var end = i+n; i < end; i++) {
|
|
1911
|
+
if (zz[i] >= zlimit) {
|
|
1912
|
+
xx2[i2] = xx[i];
|
|
1913
|
+
yy2[i2] = yy[i];
|
|
1914
|
+
zz2[i2] = zz[i];
|
|
1915
|
+
i2++;
|
|
1916
|
+
n2++;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (n2 == 1) {
|
|
1920
|
+
error("Collapsed arc");
|
|
1921
|
+
// This should not happen (endpoints should be z == Infinity)
|
|
1922
|
+
// Could handle like this, instead of throwing an error:
|
|
1923
|
+
// n2 = 0;
|
|
1924
|
+
// xx2.pop();
|
|
1925
|
+
// yy2.pop();
|
|
1926
|
+
// zz2.pop();
|
|
1927
|
+
}
|
|
1928
|
+
nn2[arcId] = n2;
|
|
1929
|
+
}
|
|
1930
|
+
return {
|
|
1931
|
+
xx: xx2,
|
|
1932
|
+
yy: yy2,
|
|
1933
|
+
zz: zz2,
|
|
1934
|
+
nn: nn2
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1885
1938
|
var ArcUtils = /*#__PURE__*/Object.freeze({
|
|
1886
1939
|
__proto__: null,
|
|
1887
1940
|
absArcId: absArcId,
|
|
1888
1941
|
calcArcBounds: calcArcBounds,
|
|
1889
1942
|
deleteVertex: deleteVertex,
|
|
1890
|
-
insertVertex: insertVertex
|
|
1943
|
+
insertVertex: insertVertex,
|
|
1944
|
+
countFilteredVertices: countFilteredVertices,
|
|
1945
|
+
filterVertexData: filterVertexData
|
|
1891
1946
|
});
|
|
1892
1947
|
|
|
1893
1948
|
var WGS84 = {
|
|
@@ -5359,17 +5414,6 @@
|
|
|
5359
5414
|
initZData(zz || null);
|
|
5360
5415
|
};
|
|
5361
5416
|
|
|
5362
|
-
// Give access to raw data arrays...
|
|
5363
|
-
this.getVertexData = function() {
|
|
5364
|
-
return {
|
|
5365
|
-
xx: _xx,
|
|
5366
|
-
yy: _yy,
|
|
5367
|
-
zz: _zz,
|
|
5368
|
-
bb: _bb,
|
|
5369
|
-
nn: _nn,
|
|
5370
|
-
ii: _ii
|
|
5371
|
-
};
|
|
5372
|
-
};
|
|
5373
5417
|
|
|
5374
5418
|
this.getCopy = function() {
|
|
5375
5419
|
var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
|
|
@@ -5381,55 +5425,28 @@
|
|
|
5381
5425
|
return copy;
|
|
5382
5426
|
};
|
|
5383
5427
|
|
|
5428
|
+
|
|
5429
|
+
// Give access to raw data arrays...
|
|
5430
|
+
this.getVertexData = getVertexData;
|
|
5431
|
+
|
|
5432
|
+
function getVertexData() {
|
|
5433
|
+
return {
|
|
5434
|
+
xx: _xx,
|
|
5435
|
+
yy: _yy,
|
|
5436
|
+
zz: _zz,
|
|
5437
|
+
bb: _bb,
|
|
5438
|
+
nn: _nn,
|
|
5439
|
+
ii: _ii
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5384
5443
|
function getFilteredPointCount() {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
var count = 0;
|
|
5388
|
-
for (var i=0, n = zz.length; i<n; i++) {
|
|
5389
|
-
if (zz[i] >= z) count++;
|
|
5390
|
-
}
|
|
5391
|
-
return count;
|
|
5444
|
+
if (!_zz || !_zlimit) return this.getPointCount();
|
|
5445
|
+
return countFilteredVertices(_zz, _zlimit);
|
|
5392
5446
|
}
|
|
5393
5447
|
|
|
5394
5448
|
function getFilteredVertexData() {
|
|
5395
|
-
|
|
5396
|
-
var arcCount = _nn.length;
|
|
5397
|
-
var xx2 = new Float64Array(len2),
|
|
5398
|
-
yy2 = new Float64Array(len2),
|
|
5399
|
-
zz2 = new Float64Array(len2),
|
|
5400
|
-
nn2 = new Int32Array(arcCount),
|
|
5401
|
-
i=0, i2 = 0,
|
|
5402
|
-
n, n2;
|
|
5403
|
-
|
|
5404
|
-
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
5405
|
-
n2 = 0;
|
|
5406
|
-
n = _nn[arcId];
|
|
5407
|
-
for (var end = i+n; i < end; i++) {
|
|
5408
|
-
if (_zz[i] >= _zlimit) {
|
|
5409
|
-
xx2[i2] = _xx[i];
|
|
5410
|
-
yy2[i2] = _yy[i];
|
|
5411
|
-
zz2[i2] = _zz[i];
|
|
5412
|
-
i2++;
|
|
5413
|
-
n2++;
|
|
5414
|
-
}
|
|
5415
|
-
}
|
|
5416
|
-
if (n2 == 1) {
|
|
5417
|
-
error("Collapsed arc");
|
|
5418
|
-
// This should not happen (endpoints should be z == Infinity)
|
|
5419
|
-
// Could handle like this, instead of throwing an error:
|
|
5420
|
-
// n2 = 0;
|
|
5421
|
-
// xx2.pop();
|
|
5422
|
-
// yy2.pop();
|
|
5423
|
-
// zz2.pop();
|
|
5424
|
-
}
|
|
5425
|
-
nn2[arcId] = n2;
|
|
5426
|
-
}
|
|
5427
|
-
return {
|
|
5428
|
-
xx: xx2,
|
|
5429
|
-
yy: yy2,
|
|
5430
|
-
zz: zz2,
|
|
5431
|
-
nn: nn2
|
|
5432
|
-
};
|
|
5449
|
+
return filterVertexData(getVertexData(), _zlimit);
|
|
5433
5450
|
}
|
|
5434
5451
|
|
|
5435
5452
|
this.getFilteredCopy = function() {
|
|
@@ -10828,28 +10845,59 @@
|
|
|
10828
10845
|
}
|
|
10829
10846
|
|
|
10830
10847
|
// gui: (optional) gui instance
|
|
10831
|
-
//
|
|
10848
|
+
// opts examples:
|
|
10849
|
+
// exporting from command line: { compact: true, file: 'tmp.msx', final: true }
|
|
10850
|
+
// exporting from gui export menu: {compact: true, format: 'msx'}
|
|
10851
|
+
// saving gui temp snapshot: {compact: false}
|
|
10832
10852
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10833
10853
|
var obj = {
|
|
10834
10854
|
version: 1,
|
|
10835
10855
|
created: (new Date).toISOString(),
|
|
10836
|
-
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10856
|
+
datasets: await Promise.all(datasets.map(dataset => exportDataset(dataset, opts)))
|
|
10837
10857
|
};
|
|
10838
|
-
if (opts.compact) {
|
|
10839
|
-
await applyCompression(obj);
|
|
10840
|
-
}
|
|
10841
10858
|
return obj;
|
|
10842
10859
|
}
|
|
10843
10860
|
|
|
10844
|
-
async function
|
|
10845
|
-
var
|
|
10846
|
-
|
|
10847
|
-
|
|
10861
|
+
async function exportDataset(dataset, opts) {
|
|
10862
|
+
var arcs = dataset.arcs;
|
|
10863
|
+
var arcData = null;
|
|
10864
|
+
if (arcs) {
|
|
10865
|
+
arcData = arcs.getVertexData();
|
|
10866
|
+
arcData.zlimit = arcs.getRetainedInterval(); // TODO: add this to getVertexData()
|
|
10867
|
+
arcData = await exportArcData(arcData, opts);
|
|
10868
|
+
}
|
|
10869
|
+
return {
|
|
10870
|
+
arcs: arcData,
|
|
10871
|
+
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10872
|
+
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10873
|
+
};
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10876
|
+
// compress unpacked + uncompressed snapshot data in-place
|
|
10877
|
+
async function compressSnapshotForExport(obj) {
|
|
10878
|
+
var promises = obj.datasets.map(d => {
|
|
10879
|
+
compressDatasetForExport(d);
|
|
10848
10880
|
});
|
|
10849
10881
|
await Promise.all(promises);
|
|
10882
|
+
return;
|
|
10850
10883
|
}
|
|
10851
10884
|
|
|
10852
|
-
async function
|
|
10885
|
+
async function compressDatasetForExport(obj) {
|
|
10886
|
+
if (!obj.arcs) return;
|
|
10887
|
+
var arcData = importArcData(obj.arcs); // convert buffers to typed arrays
|
|
10888
|
+
obj.arcs = await exportArcData(arcData, {compact: true}); // re-export to compressed buffers
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
function flattenArcs(arcData) {
|
|
10892
|
+
if (arcData.zz && arcData.zlimit) {
|
|
10893
|
+
// replace unfiltered arc data with flattened arc data
|
|
10894
|
+
arcData = filterVertexData(arcData, arcData.zlimit);
|
|
10895
|
+
delete arcData.zz;
|
|
10896
|
+
}
|
|
10897
|
+
return arcData;
|
|
10898
|
+
}
|
|
10899
|
+
|
|
10900
|
+
async function gzipArcData(obj, opts) {
|
|
10853
10901
|
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10854
10902
|
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10855
10903
|
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
@@ -10860,27 +10908,36 @@
|
|
|
10860
10908
|
if (obj.zz) obj.zz = results.shift();
|
|
10861
10909
|
}
|
|
10862
10910
|
|
|
10863
|
-
|
|
10911
|
+
function importArcData(obj) {
|
|
10864
10912
|
return {
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10913
|
+
nn: new Uint32Array(obj.nn.buffer, 0, obj.nn.length / 4),
|
|
10914
|
+
xx: new Float64Array(obj.xx.buffer, 0, obj.xx.length / 8),
|
|
10915
|
+
yy: new Float64Array(obj.yy.buffer, 0, obj.yy.length / 8),
|
|
10916
|
+
zz: obj.zz ? new Float64Array(obj.zz.buffer, 0, obj.zz.length / 8) : null,
|
|
10917
|
+
zlimit: obj.zlimit || 0
|
|
10868
10918
|
};
|
|
10869
10919
|
}
|
|
10870
10920
|
|
|
10871
|
-
function
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
var
|
|
10877
|
-
return {
|
|
10921
|
+
async function exportArcData(data, opts) {
|
|
10922
|
+
// TODO: consider removing arcs that are not referenced by any layer
|
|
10923
|
+
if (opts.compact && data.zz) {
|
|
10924
|
+
data = flattenArcs(data); // bake in any simplification
|
|
10925
|
+
}
|
|
10926
|
+
var output = {
|
|
10878
10927
|
nn: typedArrayToBuffer(data.nn),
|
|
10879
10928
|
xx: typedArrayToBuffer(data.xx),
|
|
10880
10929
|
yy: typedArrayToBuffer(data.yy),
|
|
10881
10930
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10882
|
-
zlimit:
|
|
10931
|
+
zlimit: data.zlimit || 0
|
|
10883
10932
|
};
|
|
10933
|
+
if (opts.compact && data.zz) {
|
|
10934
|
+
await gzipArcData(output);
|
|
10935
|
+
}
|
|
10936
|
+
return output;
|
|
10937
|
+
}
|
|
10938
|
+
|
|
10939
|
+
function typedArrayToBuffer(arr) {
|
|
10940
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10884
10941
|
}
|
|
10885
10942
|
|
|
10886
10943
|
async function exportLayer(lyr) {
|
|
@@ -10914,8 +10971,8 @@
|
|
|
10914
10971
|
exportPackedDatasets: exportPackedDatasets,
|
|
10915
10972
|
pack: pack,
|
|
10916
10973
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10917
|
-
applyCompression: applyCompression,
|
|
10918
10974
|
exportDataset: exportDataset,
|
|
10975
|
+
compressSnapshotForExport: compressSnapshotForExport,
|
|
10919
10976
|
exportInfo: exportInfo
|
|
10920
10977
|
});
|
|
10921
10978
|
|
|
@@ -15952,6 +16009,67 @@
|
|
|
15952
16009
|
formatIntersectingSegment: formatIntersectingSegment
|
|
15953
16010
|
});
|
|
15954
16011
|
|
|
16012
|
+
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16013
|
+
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16014
|
+
// Return a NodeCollection
|
|
16015
|
+
function cleanArcReferences(dataset) {
|
|
16016
|
+
var nodes = new NodeCollection(dataset.arcs);
|
|
16017
|
+
var map = findDuplicateArcs(nodes);
|
|
16018
|
+
var dropCount;
|
|
16019
|
+
if (map) {
|
|
16020
|
+
replaceIndexedArcIds(dataset, map);
|
|
16021
|
+
}
|
|
16022
|
+
dropCount = deleteUnusedArcs(dataset);
|
|
16023
|
+
if (dropCount > 0) {
|
|
16024
|
+
// rebuild nodes if arcs have changed
|
|
16025
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
16026
|
+
}
|
|
16027
|
+
return nodes;
|
|
16028
|
+
}
|
|
16029
|
+
|
|
16030
|
+
function deleteUnusedArcs(dataset) {
|
|
16031
|
+
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16032
|
+
var count1 = dataset.arcs.size();
|
|
16033
|
+
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16034
|
+
var count2 = dataset.arcs.size();
|
|
16035
|
+
var deleteCount = count1 - count2;
|
|
16036
|
+
if (deleteCount > 0) {
|
|
16037
|
+
replaceIndexedArcIds(dataset, map);
|
|
16038
|
+
}
|
|
16039
|
+
return deleteCount;
|
|
16040
|
+
}
|
|
16041
|
+
|
|
16042
|
+
// @map an Object mapping old to new ids
|
|
16043
|
+
function replaceIndexedArcIds(dataset, map) {
|
|
16044
|
+
var remapPath = function(ids) {
|
|
16045
|
+
var arcId, absId, id2;
|
|
16046
|
+
for (var i=0; i<ids.length; i++) {
|
|
16047
|
+
arcId = ids[i];
|
|
16048
|
+
absId = absArcId(arcId);
|
|
16049
|
+
id2 = map[absId];
|
|
16050
|
+
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16051
|
+
}
|
|
16052
|
+
return ids;
|
|
16053
|
+
};
|
|
16054
|
+
dataset.layers.forEach(function(lyr) {
|
|
16055
|
+
if (layerHasPaths(lyr)) {
|
|
16056
|
+
editShapes(lyr.shapes, remapPath);
|
|
16057
|
+
}
|
|
16058
|
+
});
|
|
16059
|
+
}
|
|
16060
|
+
|
|
16061
|
+
function findDuplicateArcs(nodes) {
|
|
16062
|
+
var map = new Int32Array(nodes.arcs.size()),
|
|
16063
|
+
count = 0,
|
|
16064
|
+
i2;
|
|
16065
|
+
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16066
|
+
i2 = nodes.findDuplicateArc(i);
|
|
16067
|
+
map[i] = i2;
|
|
16068
|
+
if (i != i2) count++;
|
|
16069
|
+
}
|
|
16070
|
+
return count > 0 ? map : null;
|
|
16071
|
+
}
|
|
16072
|
+
|
|
15955
16073
|
// Functions for dividing polygons and polygons at points where arc-segments intersect
|
|
15956
16074
|
|
|
15957
16075
|
// TODO:
|
|
@@ -16041,68 +16159,6 @@
|
|
|
16041
16159
|
}
|
|
16042
16160
|
|
|
16043
16161
|
|
|
16044
|
-
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16045
|
-
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16046
|
-
// Return a NodeCollection
|
|
16047
|
-
function cleanArcReferences(dataset) {
|
|
16048
|
-
var nodes = new NodeCollection(dataset.arcs);
|
|
16049
|
-
var map = findDuplicateArcs(nodes);
|
|
16050
|
-
var dropCount;
|
|
16051
|
-
if (map) {
|
|
16052
|
-
replaceIndexedArcIds(dataset, map);
|
|
16053
|
-
}
|
|
16054
|
-
dropCount = deleteUnusedArcs(dataset);
|
|
16055
|
-
if (dropCount > 0) {
|
|
16056
|
-
// rebuild nodes if arcs have changed
|
|
16057
|
-
nodes = new NodeCollection(dataset.arcs);
|
|
16058
|
-
}
|
|
16059
|
-
return nodes;
|
|
16060
|
-
}
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
// @map an Object mapping old to new ids
|
|
16064
|
-
function replaceIndexedArcIds(dataset, map) {
|
|
16065
|
-
var remapPath = function(ids) {
|
|
16066
|
-
var arcId, absId, id2;
|
|
16067
|
-
for (var i=0; i<ids.length; i++) {
|
|
16068
|
-
arcId = ids[i];
|
|
16069
|
-
absId = absArcId(arcId);
|
|
16070
|
-
id2 = map[absId];
|
|
16071
|
-
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16072
|
-
}
|
|
16073
|
-
return ids;
|
|
16074
|
-
};
|
|
16075
|
-
dataset.layers.forEach(function(lyr) {
|
|
16076
|
-
if (layerHasPaths(lyr)) {
|
|
16077
|
-
editShapes(lyr.shapes, remapPath);
|
|
16078
|
-
}
|
|
16079
|
-
});
|
|
16080
|
-
}
|
|
16081
|
-
|
|
16082
|
-
function findDuplicateArcs(nodes) {
|
|
16083
|
-
var map = new Int32Array(nodes.arcs.size()),
|
|
16084
|
-
count = 0,
|
|
16085
|
-
i2;
|
|
16086
|
-
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16087
|
-
i2 = nodes.findDuplicateArc(i);
|
|
16088
|
-
map[i] = i2;
|
|
16089
|
-
if (i != i2) count++;
|
|
16090
|
-
}
|
|
16091
|
-
return count > 0 ? map : null;
|
|
16092
|
-
}
|
|
16093
|
-
|
|
16094
|
-
function deleteUnusedArcs(dataset) {
|
|
16095
|
-
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16096
|
-
var count1 = dataset.arcs.size();
|
|
16097
|
-
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16098
|
-
var count2 = dataset.arcs.size();
|
|
16099
|
-
var deleteCount = count1 - count2;
|
|
16100
|
-
if (deleteCount > 0) {
|
|
16101
|
-
replaceIndexedArcIds(dataset, map);
|
|
16102
|
-
}
|
|
16103
|
-
return deleteCount;
|
|
16104
|
-
}
|
|
16105
|
-
|
|
16106
16162
|
// Return a function for updating a path (array of arc ids)
|
|
16107
16163
|
// @map array generated by insertCutPoints()
|
|
16108
16164
|
// @arcCount number of arcs in divided collection (kludge)
|
|
@@ -17458,8 +17514,9 @@
|
|
|
17458
17514
|
exporter = GeoJSON.exporters[lyr.geometry_type],
|
|
17459
17515
|
geom = shape ? exporter(shape, dataset.arcs, opts) : null,
|
|
17460
17516
|
obj = null;
|
|
17517
|
+
|
|
17461
17518
|
if (asFeatures) {
|
|
17462
|
-
obj =
|
|
17519
|
+
obj = composeFeature(geom, properties ? properties[i] : null, opts);
|
|
17463
17520
|
if (ids) {
|
|
17464
17521
|
obj.id = ids[i];
|
|
17465
17522
|
}
|
|
@@ -17483,6 +17540,20 @@
|
|
|
17483
17540
|
}, []);
|
|
17484
17541
|
}
|
|
17485
17542
|
|
|
17543
|
+
function composeFeature(geom, properties, opts) {
|
|
17544
|
+
var feat = GeoJSON.toFeature(geom, properties);
|
|
17545
|
+
if (Array.isArray(opts.hoist) && properties) {
|
|
17546
|
+
// don't modify properties of source feature
|
|
17547
|
+
feat.properties = Object.assign({}, properties);
|
|
17548
|
+
opts.hoist.forEach(field => {
|
|
17549
|
+
if (properties.hasOwnProperty(field)) {
|
|
17550
|
+
feat[field] = properties[field];
|
|
17551
|
+
delete feat.properties[field];
|
|
17552
|
+
}
|
|
17553
|
+
});
|
|
17554
|
+
}
|
|
17555
|
+
return feat;
|
|
17556
|
+
}
|
|
17486
17557
|
|
|
17487
17558
|
function getRFC7946Warnings(dataset) {
|
|
17488
17559
|
var P = getDatasetCRS(dataset);
|
|
@@ -21576,6 +21647,14 @@ ${svg}
|
|
|
21576
21647
|
}
|
|
21577
21648
|
return memo.concat(exportFileContent(dataset, opts));
|
|
21578
21649
|
}, []);
|
|
21650
|
+
|
|
21651
|
+
if (opts.bbox_index) {
|
|
21652
|
+
// If rounding or quantization are applied during export, bounds may
|
|
21653
|
+
// change somewhat... consider adding a bounds property to each layer during
|
|
21654
|
+
// export when appropriate.
|
|
21655
|
+
files.push(createIndexFile(datasets));
|
|
21656
|
+
}
|
|
21657
|
+
|
|
21579
21658
|
// need unique names for multiple output files
|
|
21580
21659
|
assignUniqueFileNames(files);
|
|
21581
21660
|
|
|
@@ -21633,15 +21712,7 @@ ${svg}
|
|
|
21633
21712
|
}
|
|
21634
21713
|
|
|
21635
21714
|
validateLayerData(dataset.layers);
|
|
21636
|
-
|
|
21637
21715
|
files = exporter(dataset, opts).concat(files);
|
|
21638
|
-
// If rounding or quantization are applied during export, bounds may
|
|
21639
|
-
// change somewhat... consider adding a bounds property to each layer during
|
|
21640
|
-
// export when appropriate.
|
|
21641
|
-
if (opts.bbox_index) {
|
|
21642
|
-
files.push(createIndexFile(dataset));
|
|
21643
|
-
}
|
|
21644
|
-
|
|
21645
21716
|
validateFileNames(files);
|
|
21646
21717
|
return files;
|
|
21647
21718
|
}
|
|
@@ -21662,13 +21733,16 @@ ${svg}
|
|
|
21662
21733
|
// Generate json file with bounding boxes and names of each export layer
|
|
21663
21734
|
// TODO: consider making this a command, or at least make format settable
|
|
21664
21735
|
//
|
|
21665
|
-
function createIndexFile(
|
|
21666
|
-
var index =
|
|
21667
|
-
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
|
|
21736
|
+
function createIndexFile(datasets) {
|
|
21737
|
+
var index = [];
|
|
21738
|
+
datasets.forEach(function(dataset) {
|
|
21739
|
+
dataset.layers.forEach(function(lyr) {
|
|
21740
|
+
var bounds = getLayerBounds(lyr, dataset.arcs);
|
|
21741
|
+
index.push({
|
|
21742
|
+
bbox: bounds.toArray(),
|
|
21743
|
+
name: lyr.name
|
|
21744
|
+
});
|
|
21745
|
+
});
|
|
21672
21746
|
});
|
|
21673
21747
|
|
|
21674
21748
|
return {
|
|
@@ -23391,7 +23465,7 @@ ${svg}
|
|
|
23391
23465
|
.option('string-fields', stringFieldsOpt)
|
|
23392
23466
|
.option('field-types', fieldTypesOpt)
|
|
23393
23467
|
.option('name', {
|
|
23394
|
-
describe: '
|
|
23468
|
+
describe: 'rename the imported layer(s)'
|
|
23395
23469
|
})
|
|
23396
23470
|
.option('geometry-type', {
|
|
23397
23471
|
// undocumented; GeoJSON import rejects all but one kind of geometry
|
|
@@ -23560,6 +23634,10 @@ ${svg}
|
|
|
23560
23634
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
23561
23635
|
type: 'flag'
|
|
23562
23636
|
})
|
|
23637
|
+
.option('hoist', {
|
|
23638
|
+
describe: '[GeoJSON] move properties to the root level of each Feature',
|
|
23639
|
+
type: 'strings'
|
|
23640
|
+
})
|
|
23563
23641
|
.option('width', {
|
|
23564
23642
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
23565
23643
|
type: 'number'
|
|
@@ -33510,7 +33588,6 @@ ${svg}
|
|
|
33510
33588
|
stop('Missing a data field to classify');
|
|
33511
33589
|
}
|
|
33512
33590
|
|
|
33513
|
-
|
|
33514
33591
|
// get the number of classes and the number of values
|
|
33515
33592
|
//
|
|
33516
33593
|
// expand categories if value is '*'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mapshaper",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.45",
|
|
4
4
|
"description": "A tool for editing vector datasets for mapping and GIS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shapefile",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"browserify": "^17.0.0",
|
|
69
69
|
"csv-spectrum": "^1.0.0",
|
|
70
70
|
"eslint": "^8.16.0",
|
|
71
|
-
"mocha": "^10.
|
|
71
|
+
"mocha": "^10.2.0",
|
|
72
72
|
"rollup": "^2.73.0",
|
|
73
73
|
"shell-quote": "^1.7.4",
|
|
74
74
|
"underscore": "^1.13.1"
|
package/www/index.html
CHANGED
|
@@ -170,8 +170,8 @@ precision=0.001. Click to see all options.</div></div></div></a>
|
|
|
170
170
|
<input id="ofile-name" class="text-input" type="text" placeholder="output file name" />
|
|
171
171
|
</div> -->
|
|
172
172
|
|
|
173
|
-
<!-- <div class="cancel-btn btn dialog-btn">Cancel</div> -->
|
|
174
173
|
<div class="save-btn btn dialog-btn">Export</div>
|
|
174
|
+
<!-- <span id="save-to-clipboard" class="inline-checkbox" style="display: inline-block;"><input type="checkbox"/>save to clipboard</span> -->
|
|
175
175
|
<span id="save-preference" class="inline-checkbox" style="display: none;"><input type="checkbox"/>choose directory</span>
|
|
176
176
|
|
|
177
177
|
</div>
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -1442,7 +1442,7 @@
|
|
|
1442
1442
|
}).text('restore');
|
|
1443
1443
|
El('span').addClass('save-menu-btn').appendTo(line).on('click', async function(e) {
|
|
1444
1444
|
var obj = await idb.get(item.id);
|
|
1445
|
-
await internal.
|
|
1445
|
+
await internal.compressSnapshotForExport(obj);
|
|
1446
1446
|
var buf = internal.pack(obj);
|
|
1447
1447
|
// choose output filename and directory every time
|
|
1448
1448
|
// saveBlobToLocalFile('mapshaper_snapshot.msx', new Blob([buf]));
|
|
@@ -6372,6 +6372,61 @@
|
|
|
6372
6372
|
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
6373
6373
|
}
|
|
6374
6374
|
|
|
6375
|
+
function countFilteredVertices(zz, zlimit) {
|
|
6376
|
+
var count = 0;
|
|
6377
|
+
for (var i=0, n = zz.length; i<n; i++) {
|
|
6378
|
+
if (zz[i] >= zlimit) count++;
|
|
6379
|
+
}
|
|
6380
|
+
return count;
|
|
6381
|
+
}
|
|
6382
|
+
|
|
6383
|
+
function filterVertexData(o, zlimit) {
|
|
6384
|
+
if (!o.zz) error('Expected simplification data');
|
|
6385
|
+
var xx = o.xx,
|
|
6386
|
+
yy = o.yy,
|
|
6387
|
+
zz = o.zz,
|
|
6388
|
+
len2 = countFilteredVertices(zz, zlimit),
|
|
6389
|
+
arcCount = o.nn.length,
|
|
6390
|
+
xx2 = new Float64Array(len2),
|
|
6391
|
+
yy2 = new Float64Array(len2),
|
|
6392
|
+
zz2 = new Float64Array(len2),
|
|
6393
|
+
nn2 = new Int32Array(arcCount),
|
|
6394
|
+
i = 0, i2 = 0,
|
|
6395
|
+
n, n2;
|
|
6396
|
+
|
|
6397
|
+
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
6398
|
+
n2 = 0;
|
|
6399
|
+
n = o.nn[arcId];
|
|
6400
|
+
for (var end = i+n; i < end; i++) {
|
|
6401
|
+
if (zz[i] >= zlimit) {
|
|
6402
|
+
xx2[i2] = xx[i];
|
|
6403
|
+
yy2[i2] = yy[i];
|
|
6404
|
+
zz2[i2] = zz[i];
|
|
6405
|
+
i2++;
|
|
6406
|
+
n2++;
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6409
|
+
if (n2 == 1) {
|
|
6410
|
+
error("Collapsed arc");
|
|
6411
|
+
// This should not happen (endpoints should be z == Infinity)
|
|
6412
|
+
// Could handle like this, instead of throwing an error:
|
|
6413
|
+
// n2 = 0;
|
|
6414
|
+
// xx2.pop();
|
|
6415
|
+
// yy2.pop();
|
|
6416
|
+
// zz2.pop();
|
|
6417
|
+
} else if (n2 === 0) {
|
|
6418
|
+
// collapsed arc... ignoring
|
|
6419
|
+
}
|
|
6420
|
+
nn2[arcId] = n2;
|
|
6421
|
+
}
|
|
6422
|
+
return {
|
|
6423
|
+
xx: xx2,
|
|
6424
|
+
yy: yy2,
|
|
6425
|
+
zz: zz2,
|
|
6426
|
+
nn: nn2
|
|
6427
|
+
};
|
|
6428
|
+
}
|
|
6429
|
+
|
|
6375
6430
|
function getShapeHitTest(displayLayer, ext, interactionMode) {
|
|
6376
6431
|
var geoType = displayLayer.layer.geometry_type;
|
|
6377
6432
|
var test;
|
|
@@ -8023,14 +8078,13 @@
|
|
|
8023
8078
|
});
|
|
8024
8079
|
|
|
8025
8080
|
self.show = function(id, ids, lyr, pinned) {
|
|
8026
|
-
var table = lyr.data; // table can be null (e.g. if layer has no attribute data)
|
|
8027
8081
|
var editable = pinned && gui.interaction.getMode() == 'data';
|
|
8028
8082
|
var maxHeight = parent.node().clientHeight - 36;
|
|
8029
8083
|
currId = id;
|
|
8030
8084
|
// stash a function for refreshing the current popup when data changes
|
|
8031
8085
|
// while the popup is being displayed (e.g. while dragging a label)
|
|
8032
8086
|
refresh = function() {
|
|
8033
|
-
render(content, id,
|
|
8087
|
+
render(content, id, lyr, editable);
|
|
8034
8088
|
};
|
|
8035
8089
|
refresh();
|
|
8036
8090
|
if (ids && ids.length > 1) {
|
|
@@ -8069,7 +8123,8 @@
|
|
|
8069
8123
|
tab.show();
|
|
8070
8124
|
}
|
|
8071
8125
|
|
|
8072
|
-
function render(el, recId,
|
|
8126
|
+
function render(el, recId, lyr, editable) {
|
|
8127
|
+
var table = lyr.data; // table can be null (e.g. if layer has no attribute data)
|
|
8073
8128
|
var rec = table && (editable ? table.getRecordAt(recId) : table.getReadOnlyRecordAt(recId)) || {};
|
|
8074
8129
|
var tableEl = El('table').addClass('selectable'),
|
|
8075
8130
|
rows = 0;
|
|
@@ -8111,14 +8166,14 @@
|
|
|
8111
8166
|
if (editable) {
|
|
8112
8167
|
// render "add field" button
|
|
8113
8168
|
var line = El('div').appendTo(el);
|
|
8114
|
-
El('span').addClass('
|
|
8169
|
+
El('span').addClass('add-field-btn').appendTo(line).on('click', async function(e) {
|
|
8115
8170
|
// show "add field" dialog
|
|
8116
|
-
renderAddFieldPopup(recId,
|
|
8171
|
+
renderAddFieldPopup(recId, lyr);
|
|
8117
8172
|
}).text('+ add field');
|
|
8118
8173
|
}
|
|
8119
8174
|
}
|
|
8120
8175
|
|
|
8121
|
-
function renderAddFieldPopup(recId,
|
|
8176
|
+
function renderAddFieldPopup(recId, lyr) {
|
|
8122
8177
|
var popup = showPopupAlert('', 'Add field');
|
|
8123
8178
|
var el = popup.container();
|
|
8124
8179
|
el.addClass('option-menu');
|
|
@@ -8132,6 +8187,7 @@
|
|
|
8132
8187
|
var val = el.findChild('.field-value');
|
|
8133
8188
|
var box = el.findChild('.all');
|
|
8134
8189
|
var btn = el.findChild('.btn').on('click', function() {
|
|
8190
|
+
var table = internal.getLayerDataTable(lyr); // creates new table if missing
|
|
8135
8191
|
var all = box.node().checked;
|
|
8136
8192
|
var nameStr = name.node().value.trim();
|
|
8137
8193
|
if (!nameStr) return;
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.45";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1882,12 +1882,67 @@
|
|
|
1882
1882
|
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1883
1883
|
}
|
|
1884
1884
|
|
|
1885
|
+
function countFilteredVertices(zz, zlimit) {
|
|
1886
|
+
var count = 0;
|
|
1887
|
+
for (var i=0, n = zz.length; i<n; i++) {
|
|
1888
|
+
if (zz[i] >= zlimit) count++;
|
|
1889
|
+
}
|
|
1890
|
+
return count;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
function filterVertexData(o, zlimit) {
|
|
1894
|
+
if (!o.zz) error('Expected simplification data');
|
|
1895
|
+
var xx = o.xx,
|
|
1896
|
+
yy = o.yy,
|
|
1897
|
+
zz = o.zz,
|
|
1898
|
+
len2 = countFilteredVertices(zz, zlimit),
|
|
1899
|
+
arcCount = o.nn.length,
|
|
1900
|
+
xx2 = new Float64Array(len2),
|
|
1901
|
+
yy2 = new Float64Array(len2),
|
|
1902
|
+
zz2 = new Float64Array(len2),
|
|
1903
|
+
nn2 = new Int32Array(arcCount),
|
|
1904
|
+
i = 0, i2 = 0,
|
|
1905
|
+
n, n2;
|
|
1906
|
+
|
|
1907
|
+
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
1908
|
+
n2 = 0;
|
|
1909
|
+
n = o.nn[arcId];
|
|
1910
|
+
for (var end = i+n; i < end; i++) {
|
|
1911
|
+
if (zz[i] >= zlimit) {
|
|
1912
|
+
xx2[i2] = xx[i];
|
|
1913
|
+
yy2[i2] = yy[i];
|
|
1914
|
+
zz2[i2] = zz[i];
|
|
1915
|
+
i2++;
|
|
1916
|
+
n2++;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
if (n2 == 1) {
|
|
1920
|
+
error("Collapsed arc");
|
|
1921
|
+
// This should not happen (endpoints should be z == Infinity)
|
|
1922
|
+
// Could handle like this, instead of throwing an error:
|
|
1923
|
+
// n2 = 0;
|
|
1924
|
+
// xx2.pop();
|
|
1925
|
+
// yy2.pop();
|
|
1926
|
+
// zz2.pop();
|
|
1927
|
+
}
|
|
1928
|
+
nn2[arcId] = n2;
|
|
1929
|
+
}
|
|
1930
|
+
return {
|
|
1931
|
+
xx: xx2,
|
|
1932
|
+
yy: yy2,
|
|
1933
|
+
zz: zz2,
|
|
1934
|
+
nn: nn2
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1885
1938
|
var ArcUtils = /*#__PURE__*/Object.freeze({
|
|
1886
1939
|
__proto__: null,
|
|
1887
1940
|
absArcId: absArcId,
|
|
1888
1941
|
calcArcBounds: calcArcBounds,
|
|
1889
1942
|
deleteVertex: deleteVertex,
|
|
1890
|
-
insertVertex: insertVertex
|
|
1943
|
+
insertVertex: insertVertex,
|
|
1944
|
+
countFilteredVertices: countFilteredVertices,
|
|
1945
|
+
filterVertexData: filterVertexData
|
|
1891
1946
|
});
|
|
1892
1947
|
|
|
1893
1948
|
var WGS84 = {
|
|
@@ -5359,17 +5414,6 @@
|
|
|
5359
5414
|
initZData(zz || null);
|
|
5360
5415
|
};
|
|
5361
5416
|
|
|
5362
|
-
// Give access to raw data arrays...
|
|
5363
|
-
this.getVertexData = function() {
|
|
5364
|
-
return {
|
|
5365
|
-
xx: _xx,
|
|
5366
|
-
yy: _yy,
|
|
5367
|
-
zz: _zz,
|
|
5368
|
-
bb: _bb,
|
|
5369
|
-
nn: _nn,
|
|
5370
|
-
ii: _ii
|
|
5371
|
-
};
|
|
5372
|
-
};
|
|
5373
5417
|
|
|
5374
5418
|
this.getCopy = function() {
|
|
5375
5419
|
var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
|
|
@@ -5381,55 +5425,28 @@
|
|
|
5381
5425
|
return copy;
|
|
5382
5426
|
};
|
|
5383
5427
|
|
|
5428
|
+
|
|
5429
|
+
// Give access to raw data arrays...
|
|
5430
|
+
this.getVertexData = getVertexData;
|
|
5431
|
+
|
|
5432
|
+
function getVertexData() {
|
|
5433
|
+
return {
|
|
5434
|
+
xx: _xx,
|
|
5435
|
+
yy: _yy,
|
|
5436
|
+
zz: _zz,
|
|
5437
|
+
bb: _bb,
|
|
5438
|
+
nn: _nn,
|
|
5439
|
+
ii: _ii
|
|
5440
|
+
};
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5384
5443
|
function getFilteredPointCount() {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
var count = 0;
|
|
5388
|
-
for (var i=0, n = zz.length; i<n; i++) {
|
|
5389
|
-
if (zz[i] >= z) count++;
|
|
5390
|
-
}
|
|
5391
|
-
return count;
|
|
5444
|
+
if (!_zz || !_zlimit) return this.getPointCount();
|
|
5445
|
+
return countFilteredVertices(_zz, _zlimit);
|
|
5392
5446
|
}
|
|
5393
5447
|
|
|
5394
5448
|
function getFilteredVertexData() {
|
|
5395
|
-
|
|
5396
|
-
var arcCount = _nn.length;
|
|
5397
|
-
var xx2 = new Float64Array(len2),
|
|
5398
|
-
yy2 = new Float64Array(len2),
|
|
5399
|
-
zz2 = new Float64Array(len2),
|
|
5400
|
-
nn2 = new Int32Array(arcCount),
|
|
5401
|
-
i=0, i2 = 0,
|
|
5402
|
-
n, n2;
|
|
5403
|
-
|
|
5404
|
-
for (var arcId=0; arcId < arcCount; arcId++) {
|
|
5405
|
-
n2 = 0;
|
|
5406
|
-
n = _nn[arcId];
|
|
5407
|
-
for (var end = i+n; i < end; i++) {
|
|
5408
|
-
if (_zz[i] >= _zlimit) {
|
|
5409
|
-
xx2[i2] = _xx[i];
|
|
5410
|
-
yy2[i2] = _yy[i];
|
|
5411
|
-
zz2[i2] = _zz[i];
|
|
5412
|
-
i2++;
|
|
5413
|
-
n2++;
|
|
5414
|
-
}
|
|
5415
|
-
}
|
|
5416
|
-
if (n2 == 1) {
|
|
5417
|
-
error("Collapsed arc");
|
|
5418
|
-
// This should not happen (endpoints should be z == Infinity)
|
|
5419
|
-
// Could handle like this, instead of throwing an error:
|
|
5420
|
-
// n2 = 0;
|
|
5421
|
-
// xx2.pop();
|
|
5422
|
-
// yy2.pop();
|
|
5423
|
-
// zz2.pop();
|
|
5424
|
-
}
|
|
5425
|
-
nn2[arcId] = n2;
|
|
5426
|
-
}
|
|
5427
|
-
return {
|
|
5428
|
-
xx: xx2,
|
|
5429
|
-
yy: yy2,
|
|
5430
|
-
zz: zz2,
|
|
5431
|
-
nn: nn2
|
|
5432
|
-
};
|
|
5449
|
+
return filterVertexData(getVertexData(), _zlimit);
|
|
5433
5450
|
}
|
|
5434
5451
|
|
|
5435
5452
|
this.getFilteredCopy = function() {
|
|
@@ -10828,28 +10845,59 @@
|
|
|
10828
10845
|
}
|
|
10829
10846
|
|
|
10830
10847
|
// gui: (optional) gui instance
|
|
10831
|
-
//
|
|
10848
|
+
// opts examples:
|
|
10849
|
+
// exporting from command line: { compact: true, file: 'tmp.msx', final: true }
|
|
10850
|
+
// exporting from gui export menu: {compact: true, format: 'msx'}
|
|
10851
|
+
// saving gui temp snapshot: {compact: false}
|
|
10832
10852
|
async function exportDatasetsToPack(datasets, opts) {
|
|
10833
10853
|
var obj = {
|
|
10834
10854
|
version: 1,
|
|
10835
10855
|
created: (new Date).toISOString(),
|
|
10836
|
-
datasets: await Promise.all(datasets.map(exportDataset))
|
|
10856
|
+
datasets: await Promise.all(datasets.map(dataset => exportDataset(dataset, opts)))
|
|
10837
10857
|
};
|
|
10838
|
-
if (opts.compact) {
|
|
10839
|
-
await applyCompression(obj);
|
|
10840
|
-
}
|
|
10841
10858
|
return obj;
|
|
10842
10859
|
}
|
|
10843
10860
|
|
|
10844
|
-
async function
|
|
10845
|
-
var
|
|
10846
|
-
|
|
10847
|
-
|
|
10861
|
+
async function exportDataset(dataset, opts) {
|
|
10862
|
+
var arcs = dataset.arcs;
|
|
10863
|
+
var arcData = null;
|
|
10864
|
+
if (arcs) {
|
|
10865
|
+
arcData = arcs.getVertexData();
|
|
10866
|
+
arcData.zlimit = arcs.getRetainedInterval(); // TODO: add this to getVertexData()
|
|
10867
|
+
arcData = await exportArcData(arcData, opts);
|
|
10868
|
+
}
|
|
10869
|
+
return {
|
|
10870
|
+
arcs: arcData,
|
|
10871
|
+
info: dataset.info ? exportInfo(dataset.info) : null,
|
|
10872
|
+
layers: await Promise.all((dataset.layers || []).map(exportLayer))
|
|
10873
|
+
};
|
|
10874
|
+
}
|
|
10875
|
+
|
|
10876
|
+
// compress unpacked + uncompressed snapshot data in-place
|
|
10877
|
+
async function compressSnapshotForExport(obj) {
|
|
10878
|
+
var promises = obj.datasets.map(d => {
|
|
10879
|
+
compressDatasetForExport(d);
|
|
10848
10880
|
});
|
|
10849
10881
|
await Promise.all(promises);
|
|
10882
|
+
return;
|
|
10850
10883
|
}
|
|
10851
10884
|
|
|
10852
|
-
async function
|
|
10885
|
+
async function compressDatasetForExport(obj) {
|
|
10886
|
+
if (!obj.arcs) return;
|
|
10887
|
+
var arcData = importArcData(obj.arcs); // convert buffers to typed arrays
|
|
10888
|
+
obj.arcs = await exportArcData(arcData, {compact: true}); // re-export to compressed buffers
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
function flattenArcs(arcData) {
|
|
10892
|
+
if (arcData.zz && arcData.zlimit) {
|
|
10893
|
+
// replace unfiltered arc data with flattened arc data
|
|
10894
|
+
arcData = filterVertexData(arcData, arcData.zlimit);
|
|
10895
|
+
delete arcData.zz;
|
|
10896
|
+
}
|
|
10897
|
+
return arcData;
|
|
10898
|
+
}
|
|
10899
|
+
|
|
10900
|
+
async function gzipArcData(obj, opts) {
|
|
10853
10901
|
var gzipOpts = Object.assign({level: 1, consume: false}, opts);
|
|
10854
10902
|
var promises = [gzipAsync(obj.nn, gzipOpts), gzipAsync(obj.xx, gzipOpts), gzipAsync(obj.yy, gzipOpts)];
|
|
10855
10903
|
if (obj.zz) promises.push(gzipAsync(obj.zz, gzipOpts));
|
|
@@ -10860,27 +10908,36 @@
|
|
|
10860
10908
|
if (obj.zz) obj.zz = results.shift();
|
|
10861
10909
|
}
|
|
10862
10910
|
|
|
10863
|
-
|
|
10911
|
+
function importArcData(obj) {
|
|
10864
10912
|
return {
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10913
|
+
nn: new Uint32Array(obj.nn.buffer, 0, obj.nn.length / 4),
|
|
10914
|
+
xx: new Float64Array(obj.xx.buffer, 0, obj.xx.length / 8),
|
|
10915
|
+
yy: new Float64Array(obj.yy.buffer, 0, obj.yy.length / 8),
|
|
10916
|
+
zz: obj.zz ? new Float64Array(obj.zz.buffer, 0, obj.zz.length / 8) : null,
|
|
10917
|
+
zlimit: obj.zlimit || 0
|
|
10868
10918
|
};
|
|
10869
10919
|
}
|
|
10870
10920
|
|
|
10871
|
-
function
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
var
|
|
10877
|
-
return {
|
|
10921
|
+
async function exportArcData(data, opts) {
|
|
10922
|
+
// TODO: consider removing arcs that are not referenced by any layer
|
|
10923
|
+
if (opts.compact && data.zz) {
|
|
10924
|
+
data = flattenArcs(data); // bake in any simplification
|
|
10925
|
+
}
|
|
10926
|
+
var output = {
|
|
10878
10927
|
nn: typedArrayToBuffer(data.nn),
|
|
10879
10928
|
xx: typedArrayToBuffer(data.xx),
|
|
10880
10929
|
yy: typedArrayToBuffer(data.yy),
|
|
10881
10930
|
zz: data.zz ? typedArrayToBuffer(data.zz) : null,
|
|
10882
|
-
zlimit:
|
|
10931
|
+
zlimit: data.zlimit || 0
|
|
10883
10932
|
};
|
|
10933
|
+
if (opts.compact && data.zz) {
|
|
10934
|
+
await gzipArcData(output);
|
|
10935
|
+
}
|
|
10936
|
+
return output;
|
|
10937
|
+
}
|
|
10938
|
+
|
|
10939
|
+
function typedArrayToBuffer(arr) {
|
|
10940
|
+
return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10884
10941
|
}
|
|
10885
10942
|
|
|
10886
10943
|
async function exportLayer(lyr) {
|
|
@@ -10914,8 +10971,8 @@
|
|
|
10914
10971
|
exportPackedDatasets: exportPackedDatasets,
|
|
10915
10972
|
pack: pack,
|
|
10916
10973
|
exportDatasetsToPack: exportDatasetsToPack,
|
|
10917
|
-
applyCompression: applyCompression,
|
|
10918
10974
|
exportDataset: exportDataset,
|
|
10975
|
+
compressSnapshotForExport: compressSnapshotForExport,
|
|
10919
10976
|
exportInfo: exportInfo
|
|
10920
10977
|
});
|
|
10921
10978
|
|
|
@@ -15952,6 +16009,67 @@
|
|
|
15952
16009
|
formatIntersectingSegment: formatIntersectingSegment
|
|
15953
16010
|
});
|
|
15954
16011
|
|
|
16012
|
+
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16013
|
+
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16014
|
+
// Return a NodeCollection
|
|
16015
|
+
function cleanArcReferences(dataset) {
|
|
16016
|
+
var nodes = new NodeCollection(dataset.arcs);
|
|
16017
|
+
var map = findDuplicateArcs(nodes);
|
|
16018
|
+
var dropCount;
|
|
16019
|
+
if (map) {
|
|
16020
|
+
replaceIndexedArcIds(dataset, map);
|
|
16021
|
+
}
|
|
16022
|
+
dropCount = deleteUnusedArcs(dataset);
|
|
16023
|
+
if (dropCount > 0) {
|
|
16024
|
+
// rebuild nodes if arcs have changed
|
|
16025
|
+
nodes = new NodeCollection(dataset.arcs);
|
|
16026
|
+
}
|
|
16027
|
+
return nodes;
|
|
16028
|
+
}
|
|
16029
|
+
|
|
16030
|
+
function deleteUnusedArcs(dataset) {
|
|
16031
|
+
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16032
|
+
var count1 = dataset.arcs.size();
|
|
16033
|
+
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16034
|
+
var count2 = dataset.arcs.size();
|
|
16035
|
+
var deleteCount = count1 - count2;
|
|
16036
|
+
if (deleteCount > 0) {
|
|
16037
|
+
replaceIndexedArcIds(dataset, map);
|
|
16038
|
+
}
|
|
16039
|
+
return deleteCount;
|
|
16040
|
+
}
|
|
16041
|
+
|
|
16042
|
+
// @map an Object mapping old to new ids
|
|
16043
|
+
function replaceIndexedArcIds(dataset, map) {
|
|
16044
|
+
var remapPath = function(ids) {
|
|
16045
|
+
var arcId, absId, id2;
|
|
16046
|
+
for (var i=0; i<ids.length; i++) {
|
|
16047
|
+
arcId = ids[i];
|
|
16048
|
+
absId = absArcId(arcId);
|
|
16049
|
+
id2 = map[absId];
|
|
16050
|
+
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16051
|
+
}
|
|
16052
|
+
return ids;
|
|
16053
|
+
};
|
|
16054
|
+
dataset.layers.forEach(function(lyr) {
|
|
16055
|
+
if (layerHasPaths(lyr)) {
|
|
16056
|
+
editShapes(lyr.shapes, remapPath);
|
|
16057
|
+
}
|
|
16058
|
+
});
|
|
16059
|
+
}
|
|
16060
|
+
|
|
16061
|
+
function findDuplicateArcs(nodes) {
|
|
16062
|
+
var map = new Int32Array(nodes.arcs.size()),
|
|
16063
|
+
count = 0,
|
|
16064
|
+
i2;
|
|
16065
|
+
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16066
|
+
i2 = nodes.findDuplicateArc(i);
|
|
16067
|
+
map[i] = i2;
|
|
16068
|
+
if (i != i2) count++;
|
|
16069
|
+
}
|
|
16070
|
+
return count > 0 ? map : null;
|
|
16071
|
+
}
|
|
16072
|
+
|
|
15955
16073
|
// Functions for dividing polygons and polygons at points where arc-segments intersect
|
|
15956
16074
|
|
|
15957
16075
|
// TODO:
|
|
@@ -16041,68 +16159,6 @@
|
|
|
16041
16159
|
}
|
|
16042
16160
|
|
|
16043
16161
|
|
|
16044
|
-
// Remap any references to duplicate arcs in paths to use the same arcs
|
|
16045
|
-
// Remove any unused arcs from the dataset's ArcCollection.
|
|
16046
|
-
// Return a NodeCollection
|
|
16047
|
-
function cleanArcReferences(dataset) {
|
|
16048
|
-
var nodes = new NodeCollection(dataset.arcs);
|
|
16049
|
-
var map = findDuplicateArcs(nodes);
|
|
16050
|
-
var dropCount;
|
|
16051
|
-
if (map) {
|
|
16052
|
-
replaceIndexedArcIds(dataset, map);
|
|
16053
|
-
}
|
|
16054
|
-
dropCount = deleteUnusedArcs(dataset);
|
|
16055
|
-
if (dropCount > 0) {
|
|
16056
|
-
// rebuild nodes if arcs have changed
|
|
16057
|
-
nodes = new NodeCollection(dataset.arcs);
|
|
16058
|
-
}
|
|
16059
|
-
return nodes;
|
|
16060
|
-
}
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
// @map an Object mapping old to new ids
|
|
16064
|
-
function replaceIndexedArcIds(dataset, map) {
|
|
16065
|
-
var remapPath = function(ids) {
|
|
16066
|
-
var arcId, absId, id2;
|
|
16067
|
-
for (var i=0; i<ids.length; i++) {
|
|
16068
|
-
arcId = ids[i];
|
|
16069
|
-
absId = absArcId(arcId);
|
|
16070
|
-
id2 = map[absId];
|
|
16071
|
-
ids[i] = arcId == absId ? id2 : ~id2;
|
|
16072
|
-
}
|
|
16073
|
-
return ids;
|
|
16074
|
-
};
|
|
16075
|
-
dataset.layers.forEach(function(lyr) {
|
|
16076
|
-
if (layerHasPaths(lyr)) {
|
|
16077
|
-
editShapes(lyr.shapes, remapPath);
|
|
16078
|
-
}
|
|
16079
|
-
});
|
|
16080
|
-
}
|
|
16081
|
-
|
|
16082
|
-
function findDuplicateArcs(nodes) {
|
|
16083
|
-
var map = new Int32Array(nodes.arcs.size()),
|
|
16084
|
-
count = 0,
|
|
16085
|
-
i2;
|
|
16086
|
-
for (var i=0, n=nodes.arcs.size(); i<n; i++) {
|
|
16087
|
-
i2 = nodes.findDuplicateArc(i);
|
|
16088
|
-
map[i] = i2;
|
|
16089
|
-
if (i != i2) count++;
|
|
16090
|
-
}
|
|
16091
|
-
return count > 0 ? map : null;
|
|
16092
|
-
}
|
|
16093
|
-
|
|
16094
|
-
function deleteUnusedArcs(dataset) {
|
|
16095
|
-
var test = getArcPresenceTest2(dataset.layers, dataset.arcs);
|
|
16096
|
-
var count1 = dataset.arcs.size();
|
|
16097
|
-
var map = dataset.arcs.deleteArcs(test); // condenses arcs
|
|
16098
|
-
var count2 = dataset.arcs.size();
|
|
16099
|
-
var deleteCount = count1 - count2;
|
|
16100
|
-
if (deleteCount > 0) {
|
|
16101
|
-
replaceIndexedArcIds(dataset, map);
|
|
16102
|
-
}
|
|
16103
|
-
return deleteCount;
|
|
16104
|
-
}
|
|
16105
|
-
|
|
16106
16162
|
// Return a function for updating a path (array of arc ids)
|
|
16107
16163
|
// @map array generated by insertCutPoints()
|
|
16108
16164
|
// @arcCount number of arcs in divided collection (kludge)
|
|
@@ -17458,8 +17514,9 @@
|
|
|
17458
17514
|
exporter = GeoJSON.exporters[lyr.geometry_type],
|
|
17459
17515
|
geom = shape ? exporter(shape, dataset.arcs, opts) : null,
|
|
17460
17516
|
obj = null;
|
|
17517
|
+
|
|
17461
17518
|
if (asFeatures) {
|
|
17462
|
-
obj =
|
|
17519
|
+
obj = composeFeature(geom, properties ? properties[i] : null, opts);
|
|
17463
17520
|
if (ids) {
|
|
17464
17521
|
obj.id = ids[i];
|
|
17465
17522
|
}
|
|
@@ -17483,6 +17540,20 @@
|
|
|
17483
17540
|
}, []);
|
|
17484
17541
|
}
|
|
17485
17542
|
|
|
17543
|
+
function composeFeature(geom, properties, opts) {
|
|
17544
|
+
var feat = GeoJSON.toFeature(geom, properties);
|
|
17545
|
+
if (Array.isArray(opts.hoist) && properties) {
|
|
17546
|
+
// don't modify properties of source feature
|
|
17547
|
+
feat.properties = Object.assign({}, properties);
|
|
17548
|
+
opts.hoist.forEach(field => {
|
|
17549
|
+
if (properties.hasOwnProperty(field)) {
|
|
17550
|
+
feat[field] = properties[field];
|
|
17551
|
+
delete feat.properties[field];
|
|
17552
|
+
}
|
|
17553
|
+
});
|
|
17554
|
+
}
|
|
17555
|
+
return feat;
|
|
17556
|
+
}
|
|
17486
17557
|
|
|
17487
17558
|
function getRFC7946Warnings(dataset) {
|
|
17488
17559
|
var P = getDatasetCRS(dataset);
|
|
@@ -21576,6 +21647,14 @@ ${svg}
|
|
|
21576
21647
|
}
|
|
21577
21648
|
return memo.concat(exportFileContent(dataset, opts));
|
|
21578
21649
|
}, []);
|
|
21650
|
+
|
|
21651
|
+
if (opts.bbox_index) {
|
|
21652
|
+
// If rounding or quantization are applied during export, bounds may
|
|
21653
|
+
// change somewhat... consider adding a bounds property to each layer during
|
|
21654
|
+
// export when appropriate.
|
|
21655
|
+
files.push(createIndexFile(datasets));
|
|
21656
|
+
}
|
|
21657
|
+
|
|
21579
21658
|
// need unique names for multiple output files
|
|
21580
21659
|
assignUniqueFileNames(files);
|
|
21581
21660
|
|
|
@@ -21633,15 +21712,7 @@ ${svg}
|
|
|
21633
21712
|
}
|
|
21634
21713
|
|
|
21635
21714
|
validateLayerData(dataset.layers);
|
|
21636
|
-
|
|
21637
21715
|
files = exporter(dataset, opts).concat(files);
|
|
21638
|
-
// If rounding or quantization are applied during export, bounds may
|
|
21639
|
-
// change somewhat... consider adding a bounds property to each layer during
|
|
21640
|
-
// export when appropriate.
|
|
21641
|
-
if (opts.bbox_index) {
|
|
21642
|
-
files.push(createIndexFile(dataset));
|
|
21643
|
-
}
|
|
21644
|
-
|
|
21645
21716
|
validateFileNames(files);
|
|
21646
21717
|
return files;
|
|
21647
21718
|
}
|
|
@@ -21662,13 +21733,16 @@ ${svg}
|
|
|
21662
21733
|
// Generate json file with bounding boxes and names of each export layer
|
|
21663
21734
|
// TODO: consider making this a command, or at least make format settable
|
|
21664
21735
|
//
|
|
21665
|
-
function createIndexFile(
|
|
21666
|
-
var index =
|
|
21667
|
-
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
|
|
21736
|
+
function createIndexFile(datasets) {
|
|
21737
|
+
var index = [];
|
|
21738
|
+
datasets.forEach(function(dataset) {
|
|
21739
|
+
dataset.layers.forEach(function(lyr) {
|
|
21740
|
+
var bounds = getLayerBounds(lyr, dataset.arcs);
|
|
21741
|
+
index.push({
|
|
21742
|
+
bbox: bounds.toArray(),
|
|
21743
|
+
name: lyr.name
|
|
21744
|
+
});
|
|
21745
|
+
});
|
|
21672
21746
|
});
|
|
21673
21747
|
|
|
21674
21748
|
return {
|
|
@@ -23391,7 +23465,7 @@ ${svg}
|
|
|
23391
23465
|
.option('string-fields', stringFieldsOpt)
|
|
23392
23466
|
.option('field-types', fieldTypesOpt)
|
|
23393
23467
|
.option('name', {
|
|
23394
|
-
describe: '
|
|
23468
|
+
describe: 'rename the imported layer(s)'
|
|
23395
23469
|
})
|
|
23396
23470
|
.option('geometry-type', {
|
|
23397
23471
|
// undocumented; GeoJSON import rejects all but one kind of geometry
|
|
@@ -23560,6 +23634,10 @@ ${svg}
|
|
|
23560
23634
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
23561
23635
|
type: 'flag'
|
|
23562
23636
|
})
|
|
23637
|
+
.option('hoist', {
|
|
23638
|
+
describe: '[GeoJSON] move properties to the root level of each Feature',
|
|
23639
|
+
type: 'strings'
|
|
23640
|
+
})
|
|
23563
23641
|
.option('width', {
|
|
23564
23642
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
23565
23643
|
type: 'number'
|
|
@@ -33510,7 +33588,6 @@ ${svg}
|
|
|
33510
33588
|
stop('Missing a data field to classify');
|
|
33511
33589
|
}
|
|
33512
33590
|
|
|
33513
|
-
|
|
33514
33591
|
// get the number of classes and the number of values
|
|
33515
33592
|
//
|
|
33516
33593
|
// expand categories if value is '*'
|
package/www/page.css
CHANGED
|
@@ -58,6 +58,7 @@ body {
|
|
|
58
58
|
.colored-text,
|
|
59
59
|
.save-menu-link,
|
|
60
60
|
.save-menu-btn,
|
|
61
|
+
.add-field-btn,
|
|
61
62
|
.nav-menu-item {
|
|
62
63
|
color: #10699b;
|
|
63
64
|
}
|
|
@@ -1314,6 +1315,7 @@ div.basemap-style-btn.active img {
|
|
|
1314
1315
|
|
|
1315
1316
|
.save-menu {
|
|
1316
1317
|
text-align: right;
|
|
1318
|
+
padding-bottom: 5px;
|
|
1317
1319
|
}
|
|
1318
1320
|
|
|
1319
1321
|
.save-menu-entry {
|
|
@@ -1324,27 +1326,29 @@ div.basemap-style-btn.active img {
|
|
|
1324
1326
|
background: white;
|
|
1325
1327
|
}
|
|
1326
1328
|
|
|
1327
|
-
|
|
1329
|
+
.save-menu-btn {
|
|
1328
1330
|
display: inline-block;
|
|
1329
1331
|
border-radius: 4px;
|
|
1330
1332
|
border: 1px solid #aaa;
|
|
1331
1333
|
font-size: 12px;
|
|
1332
1334
|
margin-left: 2px;
|
|
1333
1335
|
padding: 1px 2px 3px 2px;
|
|
1334
|
-
}
|
|
1336
|
+
}
|
|
1335
1337
|
|
|
1336
|
-
.
|
|
1338
|
+
.add-field-btn {
|
|
1337
1339
|
display: inline-block;
|
|
1338
1340
|
font-size: 12px;
|
|
1339
1341
|
margin-top: 2px;
|
|
1340
1342
|
}
|
|
1341
1343
|
|
|
1342
|
-
.save-menu-btn:hover
|
|
1344
|
+
.save-menu-btn:hover,
|
|
1345
|
+
.add-field-btn:hover {
|
|
1343
1346
|
color: black;
|
|
1344
1347
|
}
|
|
1345
1348
|
|
|
1346
1349
|
.save-menu-link,
|
|
1347
|
-
.save-menu-btn
|
|
1350
|
+
.save-menu-btn,
|
|
1351
|
+
.add-field-btn {
|
|
1348
1352
|
cursor: pointer;
|
|
1349
1353
|
}
|
|
1350
1354
|
|