mapshaper 0.7.6 → 0.7.8
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 +1263 -70
- package/package.json +4 -2
- package/www/geoparquet.js +7095 -0
- package/www/index.html +8 -12
- package/www/mapshaper-gui.js +21 -4
- package/www/mapshaper.js +1263 -70
- package/www/modules.js +13695 -11919
- package/www/page.css +88 -3
- package/www/sponsor.html +4 -4
package/www/mapshaper.js
CHANGED
|
@@ -4879,7 +4879,7 @@
|
|
|
4879
4879
|
this.ty -= cy * (sy - 1);
|
|
4880
4880
|
};
|
|
4881
4881
|
|
|
4882
|
-
var mproj$
|
|
4882
|
+
var mproj$2 = require$1('mproj');
|
|
4883
4883
|
|
|
4884
4884
|
// Constructor function for a compound projection consisting of a default
|
|
4885
4885
|
// projection and one or more rectangular frames that are projected separately
|
|
@@ -4893,7 +4893,7 @@
|
|
|
4893
4893
|
var mainFrame = initFrame(mainParams);
|
|
4894
4894
|
var mainP = mainFrame.crs;
|
|
4895
4895
|
var frames = [mainFrame];
|
|
4896
|
-
var mixedP = initMixedProjection(mproj$
|
|
4896
|
+
var mixedP = initMixedProjection(mproj$2);
|
|
4897
4897
|
|
|
4898
4898
|
// This CRS masquerades as the main projection... the version with
|
|
4899
4899
|
// custom insets is exposed to savvy users
|
|
@@ -4937,7 +4937,7 @@
|
|
|
4937
4937
|
function initFrame(params) {
|
|
4938
4938
|
return {
|
|
4939
4939
|
bounds: new Bounds(bboxToRadians(params.bbox)),
|
|
4940
|
-
crs: mproj$
|
|
4940
|
+
crs: mproj$2.pj_init(params.proj)
|
|
4941
4941
|
};
|
|
4942
4942
|
}
|
|
4943
4943
|
|
|
@@ -4949,7 +4949,7 @@
|
|
|
4949
4949
|
}
|
|
4950
4950
|
|
|
4951
4951
|
function projectFrameOrigin(origin, P) {
|
|
4952
|
-
var xy = mproj$
|
|
4952
|
+
var xy = mproj$2.pj_fwd_deg({lam: origin[0], phi: origin[1]}, P);
|
|
4953
4953
|
return [xy.x, xy.y];
|
|
4954
4954
|
}
|
|
4955
4955
|
|
|
@@ -4958,7 +4958,7 @@
|
|
|
4958
4958
|
for (var i=0, n=frames.length; i<n; i++) {
|
|
4959
4959
|
frame = frames[i];
|
|
4960
4960
|
if (frame.bounds.containsPoint(lp.lam, lp.phi)) {
|
|
4961
|
-
xy2 = mproj$
|
|
4961
|
+
xy2 = mproj$2.pj_fwd(lp, frame.crs);
|
|
4962
4962
|
if (frame.matrix) {
|
|
4963
4963
|
frame.matrix.transformXY(xy2.x, xy2.y, xy2);
|
|
4964
4964
|
}
|
|
@@ -5161,7 +5161,7 @@
|
|
|
5161
5161
|
probablyDecimalDegreeBounds: probablyDecimalDegreeBounds
|
|
5162
5162
|
});
|
|
5163
5163
|
|
|
5164
|
-
var mproj = require$1('mproj');
|
|
5164
|
+
var mproj$1 = require$1('mproj');
|
|
5165
5165
|
|
|
5166
5166
|
var asyncLoader = null;
|
|
5167
5167
|
|
|
@@ -5202,7 +5202,7 @@
|
|
|
5202
5202
|
else if (x > 180) x = 180;
|
|
5203
5203
|
}
|
|
5204
5204
|
xy = [x, y];
|
|
5205
|
-
mproj.pj_transform_point(src, dest, xy);
|
|
5205
|
+
mproj$1.pj_transform_point(src, dest, xy);
|
|
5206
5206
|
return xy;
|
|
5207
5207
|
};
|
|
5208
5208
|
}
|
|
@@ -5212,8 +5212,8 @@
|
|
|
5212
5212
|
function getProjTransform2(src, dest) {
|
|
5213
5213
|
var xx = [0],
|
|
5214
5214
|
yy = [0],
|
|
5215
|
-
preK = src.is_latlong ? mproj.internal.DEG_TO_RAD : 1,
|
|
5216
|
-
postK = dest.is_latlong ? mproj.internal.RAD_TO_DEG : 1,
|
|
5215
|
+
preK = src.is_latlong ? mproj$1.internal.DEG_TO_RAD : 1,
|
|
5216
|
+
postK = dest.is_latlong ? mproj$1.internal.RAD_TO_DEG : 1,
|
|
5217
5217
|
clampSrc = isLatLngCRS(src);
|
|
5218
5218
|
|
|
5219
5219
|
return function(x, y) {
|
|
@@ -5227,7 +5227,7 @@
|
|
|
5227
5227
|
yy[0] = y * preK;
|
|
5228
5228
|
try {
|
|
5229
5229
|
dest = dest.__mixed_crs || dest;
|
|
5230
|
-
mproj.pj_transform(src, dest, xx, yy);
|
|
5230
|
+
mproj$1.pj_transform(src, dest, xx, yy);
|
|
5231
5231
|
fail = xx[0] == Infinity; // mproj invalid coord value
|
|
5232
5232
|
} catch(e) {
|
|
5233
5233
|
fail = true;
|
|
@@ -5258,19 +5258,29 @@
|
|
|
5258
5258
|
}
|
|
5259
5259
|
|
|
5260
5260
|
function crsToProj4(P) {
|
|
5261
|
-
return mproj.internal.get_proj_defn(P);
|
|
5261
|
+
return mproj$1.internal.get_proj_defn(P);
|
|
5262
5262
|
}
|
|
5263
5263
|
|
|
5264
5264
|
function crsToPrj(P) {
|
|
5265
5265
|
var wkt;
|
|
5266
5266
|
try {
|
|
5267
|
-
wkt = mproj.internal.wkt_from_proj4(P);
|
|
5267
|
+
wkt = mproj$1.internal.wkt_from_proj4(P);
|
|
5268
5268
|
} catch(e) {
|
|
5269
5269
|
// console.log(e)
|
|
5270
5270
|
}
|
|
5271
5271
|
return wkt;
|
|
5272
5272
|
}
|
|
5273
5273
|
|
|
5274
|
+
function crsToWkt2(P) {
|
|
5275
|
+
var wkt;
|
|
5276
|
+
try {
|
|
5277
|
+
wkt = mproj$1.internal.wkt2_from_proj4(P);
|
|
5278
|
+
} catch(e) {
|
|
5279
|
+
// WKT2 export may be unavailable for some custom definitions.
|
|
5280
|
+
}
|
|
5281
|
+
return wkt;
|
|
5282
|
+
}
|
|
5283
|
+
|
|
5274
5284
|
function crsAreEqual(a, b) {
|
|
5275
5285
|
var str = crsToProj4(a);
|
|
5276
5286
|
return !!str && str == crsToProj4(b);
|
|
@@ -5287,7 +5297,7 @@
|
|
|
5287
5297
|
var defn;
|
|
5288
5298
|
// prepend '+proj=' to bare proj names
|
|
5289
5299
|
str = str.replace(/(^| )([\w]+)($| )/, function(a, b, c, d) {
|
|
5290
|
-
if (c in mproj.internal.pj_list) {
|
|
5300
|
+
if (c in mproj$1.internal.pj_list) {
|
|
5291
5301
|
return b + '+proj=' + c + d;
|
|
5292
5302
|
}
|
|
5293
5303
|
return a;
|
|
@@ -5335,7 +5345,7 @@
|
|
|
5335
5345
|
P = defn;
|
|
5336
5346
|
} else {
|
|
5337
5347
|
try {
|
|
5338
|
-
P = mproj.pj_init(defn);
|
|
5348
|
+
P = mproj$1.pj_init(defn);
|
|
5339
5349
|
} catch(e) {
|
|
5340
5350
|
stop$1('Unable to use projection', defn, '(' + e.message + ')');
|
|
5341
5351
|
}
|
|
@@ -5399,8 +5409,8 @@
|
|
|
5399
5409
|
// Returns k, the ratio of coordinate distance to distance on the ground
|
|
5400
5410
|
function getScaleFactorAtXY(x, y, crs) {
|
|
5401
5411
|
var dist = 1 / crs.to_meter;
|
|
5402
|
-
var lp = mproj.pj_inv_deg({x: x, y: y}, crs);
|
|
5403
|
-
var lp2 = mproj.pj_inv_deg({x: x + dist, y: y}, crs);
|
|
5412
|
+
var lp = mproj$1.pj_inv_deg({x: x, y: y}, crs);
|
|
5413
|
+
var lp2 = mproj$1.pj_inv_deg({x: x + dist, y: y}, crs);
|
|
5404
5414
|
var k = 1 / geom.greatCircleDistance(lp.lam, lp.phi, lp2.lam, lp2.phi);
|
|
5405
5415
|
return k;
|
|
5406
5416
|
}
|
|
@@ -5438,7 +5448,7 @@
|
|
|
5438
5448
|
}
|
|
5439
5449
|
|
|
5440
5450
|
function printProjections() {
|
|
5441
|
-
var index = mproj.internal.pj_list;
|
|
5451
|
+
var index = mproj$1.internal.pj_list;
|
|
5442
5452
|
var msg = 'Proj4 projections\n';
|
|
5443
5453
|
Object.keys(index).sort().forEach(function(id) {
|
|
5444
5454
|
msg += ' ' + utils.rpad(id, 7, ' ') + ' ' + index[id].name + '\n';
|
|
@@ -5453,18 +5463,46 @@
|
|
|
5453
5463
|
function wkt1ToProj(str) {
|
|
5454
5464
|
var proj4;
|
|
5455
5465
|
try {
|
|
5456
|
-
proj4 = mproj.internal.wkt_to_proj4(str);
|
|
5466
|
+
proj4 = mproj$1.internal.wkt_to_proj4(str);
|
|
5457
5467
|
} catch(e) {
|
|
5458
5468
|
stop$1('Unusable .prj file (' + e.message + ')');
|
|
5459
5469
|
}
|
|
5460
5470
|
return proj4;
|
|
5461
5471
|
}
|
|
5462
5472
|
|
|
5473
|
+
function wkt2ToProj(str) {
|
|
5474
|
+
var proj4;
|
|
5475
|
+
try {
|
|
5476
|
+
proj4 = mproj$1.internal.wkt2_to_proj4(str);
|
|
5477
|
+
} catch(e) {
|
|
5478
|
+
stop$1('Unusable WKT2 CRS (' + e.message + ')');
|
|
5479
|
+
}
|
|
5480
|
+
return proj4;
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5483
|
+
function wktToProj(str) {
|
|
5484
|
+
var proj4;
|
|
5485
|
+
try {
|
|
5486
|
+
proj4 = mproj$1.internal.wkt2_to_proj4(str);
|
|
5487
|
+
} catch(e) {
|
|
5488
|
+
try {
|
|
5489
|
+
proj4 = mproj$1.internal.wkt_to_proj4(str);
|
|
5490
|
+
} catch(e2) {
|
|
5491
|
+
stop$1('Unusable WKT CRS (' + e2.message + ')');
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
return proj4;
|
|
5495
|
+
}
|
|
5496
|
+
|
|
5463
5497
|
// Convert contents of a .prj file to a projection object
|
|
5464
5498
|
function parsePrj(str) {
|
|
5465
5499
|
return parseCrsString$1(wkt1ToProj(str));
|
|
5466
5500
|
}
|
|
5467
5501
|
|
|
5502
|
+
function parseWkt(str) {
|
|
5503
|
+
return parseCrsString$1(wktToProj(str));
|
|
5504
|
+
}
|
|
5505
|
+
|
|
5468
5506
|
// Extract an EPSG (or other authority) code from a short string like
|
|
5469
5507
|
// "epsg:4326" or "ESRI:54030". Returns {org, code} or null.
|
|
5470
5508
|
function parseAuthorityCodeString(str) {
|
|
@@ -5522,6 +5560,7 @@
|
|
|
5522
5560
|
crsAreEqual: crsAreEqual,
|
|
5523
5561
|
crsToPrj: crsToPrj,
|
|
5524
5562
|
crsToProj4: crsToProj4,
|
|
5563
|
+
crsToWkt2: crsToWkt2,
|
|
5525
5564
|
findProjLibs: findProjLibs,
|
|
5526
5565
|
getCrsInfo: getCrsInfo,
|
|
5527
5566
|
getDatasetCRS: getDatasetCRS,
|
|
@@ -5544,6 +5583,7 @@
|
|
|
5544
5583
|
parseAuthorityCodeString: parseAuthorityCodeString,
|
|
5545
5584
|
parseCrsString: parseCrsString$1,
|
|
5546
5585
|
parsePrj: parsePrj,
|
|
5586
|
+
parseWkt: parseWkt,
|
|
5547
5587
|
printProjections: printProjections,
|
|
5548
5588
|
projectPoint: projectPoint,
|
|
5549
5589
|
requireDatasetsHaveCompatibleCRS: requireDatasetsHaveCompatibleCRS,
|
|
@@ -5551,7 +5591,9 @@
|
|
|
5551
5591
|
setDatasetCrsInfo: setDatasetCrsInfo,
|
|
5552
5592
|
setProjectionLoader: setProjectionLoader,
|
|
5553
5593
|
toLngLat: toLngLat,
|
|
5554
|
-
wkt1ToProj: wkt1ToProj
|
|
5594
|
+
wkt1ToProj: wkt1ToProj,
|
|
5595
|
+
wkt2ToProj: wkt2ToProj,
|
|
5596
|
+
wktToProj: wktToProj
|
|
5555
5597
|
});
|
|
5556
5598
|
|
|
5557
5599
|
// Coordinate iterators
|
|
@@ -8024,6 +8066,8 @@
|
|
|
8024
8066
|
type = null;
|
|
8025
8067
|
if (ext == 'dbf' || ext == 'shp' || ext == 'kml' || ext == 'svg' || ext == 'fgb' || ext == 'gpkg') {
|
|
8026
8068
|
type = ext;
|
|
8069
|
+
} else if (ext == 'parquet' || ext == 'geoparquet') {
|
|
8070
|
+
type = 'parquet';
|
|
8027
8071
|
} else if (isAuxiliaryInputFileType(ext)) {
|
|
8028
8072
|
type = ext;
|
|
8029
8073
|
} else if (/json$/.test(ext)) { // matches topojson, geojson, json
|
|
@@ -8165,7 +8209,7 @@
|
|
|
8165
8209
|
function isSupportedBinaryInputType(path) {
|
|
8166
8210
|
var ext = getFileExtension(path).toLowerCase();
|
|
8167
8211
|
return ext == 'shp' || ext == 'shx' || ext == 'dbf' ||
|
|
8168
|
-
ext == 'fgb' || ext == 'gpkg' || ext == PACKAGE_EXT; // GUI also supports zip files
|
|
8212
|
+
ext == 'fgb' || ext == 'gpkg' || ext == 'parquet' || ext == 'geoparquet' || ext == PACKAGE_EXT; // GUI also supports zip files
|
|
8169
8213
|
}
|
|
8170
8214
|
|
|
8171
8215
|
function isImportableAsBinary(path) {
|
|
@@ -18443,7 +18487,7 @@
|
|
|
18443
18487
|
function exportSVG(dataset, opts) {
|
|
18444
18488
|
var namespace = 'xmlns="http://www.w3.org/2000/svg"';
|
|
18445
18489
|
var defs = [];
|
|
18446
|
-
var frame, svg, layers;
|
|
18490
|
+
var frame, svg, layers, metadataJSON;
|
|
18447
18491
|
var style = '';
|
|
18448
18492
|
|
|
18449
18493
|
// kludge for map keys
|
|
@@ -18467,6 +18511,9 @@
|
|
|
18467
18511
|
frame = getFrameData(dataset, opts);
|
|
18468
18512
|
fitDatasetToFrame(dataset, frame);
|
|
18469
18513
|
setCoordinatePrecision(dataset, opts.precision || 0.01);
|
|
18514
|
+
if (opts.metadata) {
|
|
18515
|
+
metadataJSON = JSON.stringify(getGeospatialMetadata(dataset, frame));
|
|
18516
|
+
}
|
|
18470
18517
|
|
|
18471
18518
|
// error if one or more svg_data fields are not present in any layers
|
|
18472
18519
|
if (opts.svg_data) validateSvgDataFields(dataset.layers, opts.svg_data);
|
|
@@ -18486,6 +18533,10 @@
|
|
|
18486
18533
|
return stringify(obj);
|
|
18487
18534
|
}).join('\n');
|
|
18488
18535
|
|
|
18536
|
+
if (metadataJSON) {
|
|
18537
|
+
svg = getMetadataBlock(metadataJSON, [0, 0, frame.width, frame.height]) + svg;
|
|
18538
|
+
}
|
|
18539
|
+
|
|
18489
18540
|
if (defs.length > 0) {
|
|
18490
18541
|
svg = '<defs>\n' + utils.pluck(defs, 'svg').join('') + '</defs>\n' + svg;
|
|
18491
18542
|
}
|
|
@@ -18513,6 +18564,57 @@ ${svg}
|
|
|
18513
18564
|
}];
|
|
18514
18565
|
}
|
|
18515
18566
|
|
|
18567
|
+
function getMetadataBlock(metadataJSON, viewBox) {
|
|
18568
|
+
var x = 0;
|
|
18569
|
+
var y = 0;
|
|
18570
|
+
var width = viewBox && viewBox[2] || 0;
|
|
18571
|
+
var height = viewBox && viewBox[3] || 0;
|
|
18572
|
+
return '<metadata>' + metadataJSON + '</metadata>\n' +
|
|
18573
|
+
'<g id="mapshaper-metadata">\n' +
|
|
18574
|
+
'<rect x="' + x + '" y="' + y + '" width="' + width + '" height="' + height + '" opacity="0"/>\n' +
|
|
18575
|
+
'<text opacity="0" font-size="0.1">' + metadataJSON + '</text>\n' +
|
|
18576
|
+
'</g>\n';
|
|
18577
|
+
}
|
|
18578
|
+
|
|
18579
|
+
function getGeospatialMetadata(dataset, frame) {
|
|
18580
|
+
return {
|
|
18581
|
+
crs: getSVGMetadataCRS(dataset),
|
|
18582
|
+
bbox: frame.bbox || null
|
|
18583
|
+
};
|
|
18584
|
+
}
|
|
18585
|
+
|
|
18586
|
+
function getSVGMetadataCRS(dataset) {
|
|
18587
|
+
var crs = getDatasetCRS(dataset);
|
|
18588
|
+
var info = getDatasetCrsInfo(dataset);
|
|
18589
|
+
var proj4 = null;
|
|
18590
|
+
if (crs) {
|
|
18591
|
+
proj4 = crsToProj4(crs);
|
|
18592
|
+
}
|
|
18593
|
+
if (proj4) return proj4;
|
|
18594
|
+
return getAuthorityCodeString(info) || null;
|
|
18595
|
+
}
|
|
18596
|
+
|
|
18597
|
+
function getAuthorityCodeString(info) {
|
|
18598
|
+
var authority = null;
|
|
18599
|
+
if (info && info.crs_string) {
|
|
18600
|
+
authority = parseAuthorityCodeString(info.crs_string);
|
|
18601
|
+
}
|
|
18602
|
+
if (!authority && info && info.wkt1) {
|
|
18603
|
+
authority = parseAuthorityCodeFromWkt(info.wkt1);
|
|
18604
|
+
}
|
|
18605
|
+
if (!authority && info && info.geopackage_crs) {
|
|
18606
|
+
authority = parseGeoPackageAuthority(info.geopackage_crs);
|
|
18607
|
+
}
|
|
18608
|
+
return authority ? authority.authority + ':' + authority.code : null;
|
|
18609
|
+
}
|
|
18610
|
+
|
|
18611
|
+
function parseGeoPackageAuthority(o) {
|
|
18612
|
+
if (!o) return null;
|
|
18613
|
+
var authority = o.organization || o.authority || null;
|
|
18614
|
+
var code = o.organization_coordsys_id || o.code || null;
|
|
18615
|
+
return authority && code != null ? {authority: String(authority).toUpperCase(), code: String(code)} : null;
|
|
18616
|
+
}
|
|
18617
|
+
|
|
18516
18618
|
function exportFurnitureLayerForSVG(lyr, frame, opts) {
|
|
18517
18619
|
var layerObj = getEmptyLayerForSVG(lyr, opts);
|
|
18518
18620
|
layerObj.children = renderFurnitureLayer(lyr, frame);
|
|
@@ -24690,11 +24792,7 @@ ${svg}
|
|
|
24690
24792
|
}); });
|
|
24691
24793
|
}
|
|
24692
24794
|
|
|
24693
|
-
function
|
|
24694
|
-
|
|
24695
|
-
function buildHeader(t,r=0){let n,o=new Builder,i=0;t.columns&&(i=Header.createColumnsVector(o,t.columns.map(e=>{let t;return t=o.createString(e.name),Column.startColumn(o),Column.addName(o,t),Column.addType(o,e.type),Column.endColumn(o)})));let f=o.createString("L1");r&&(Crs.startCrs(o),Crs.addCode(o,r),n=Crs.endCrs(o)),Header.startHeader(o),n&&Header.addCrs(o,n),Header.addFeaturesCount(o,BigInt(t.featuresCount)),Header.addGeometryType(o,t.geometryType),Header.addIndexNodeSize(o,0),i&&Header.addColumns(o,i),Header.addName(o,f);let u=Header.endHeader(o);return o.finishSizePrefixed(u),o.asUint8Array()}function mapColumn(e,t){return {name:t,type:function(e){if("boolean"==typeof e)return ColumnType.Bool;if("number"==typeof e)return ColumnType.Double;if("string"==typeof e||null===e)return ColumnType.String;if(e instanceof Uint8Array)return ColumnType.Binary;if("object"==typeof e)return ColumnType.Json;throw Error(`Unknown type (value '${e}')`)}(e[t]),title:null,description:null,width:-1,precision:-1,scale:-1,nullable:true,unique:false,primary_key:false}}
|
|
24696
|
-
|
|
24697
|
-
function serialize(i,l=0){var n;let a,p,f=(a=(n=i).features[0].properties,p=null,a&&(p=Object.keys(a).map(e=>mapColumn(a,e))),{geometryType:inferGeometryType(n.features),columns:p,featuresCount:n.features.length}),c=buildHeader(f,l),g=i.features.map(e=>buildFeature("GeometryCollection"===e.geometry.type?parseGC(e.geometry):parseGeometry(e.geometry),e.properties,f)),d=g.map(e=>e.length).reduce((e,t)=>e+t),y=new Uint8Array(magicbytes.length+c.length+d);y.set(c,magicbytes.length);let h=magicbytes.length+c.length;for(let e of g)y.set(e,h),h+=e.length;return y.set(magicbytes),y}
|
|
24795
|
+
function buildHeader(t,r=0){let n,o=new Builder,i=0;t.columns&&(i=Header.createColumnsVector(o,t.columns.map(e=>{let t;return t=o.createString(e.name),Column.startColumn(o),Column.addName(o,t),Column.addType(o,e.type),Column.endColumn(o)})));let f=o.createString("L1");r&&(Crs.startCrs(o),Crs.addCode(o,r),n=Crs.endCrs(o)),Header.startHeader(o),n&&Header.addCrs(o,n),Header.addFeaturesCount(o,BigInt(t.featuresCount)),Header.addGeometryType(o,t.geometryType),Header.addIndexNodeSize(o,0),i&&Header.addColumns(o,i),Header.addName(o,f);let u=Header.endHeader(o);return o.finishSizePrefixed(u),o.asUint8Array()}
|
|
24698
24796
|
|
|
24699
24797
|
// bytes: Uint8Array
|
|
24700
24798
|
function getHeaderMeta(bytes) {
|
|
@@ -24730,6 +24828,7 @@ ${svg}
|
|
|
24730
24828
|
bb.setPosition(offset);
|
|
24731
24829
|
var feature = Feature.getSizePrefixedRootAsFeature(bb);
|
|
24732
24830
|
geojsonFeature = fromFeature(id++, feature, headerMeta);
|
|
24831
|
+
delete geojsonFeature.id;
|
|
24733
24832
|
offset += SIZE_PREFIX_LEN + featureLength;
|
|
24734
24833
|
return geojsonFeature;
|
|
24735
24834
|
};
|
|
@@ -24759,6 +24858,66 @@ ${svg}
|
|
|
24759
24858
|
return builder.asUint8Array();
|
|
24760
24859
|
}
|
|
24761
24860
|
|
|
24861
|
+
function serializeWithColumns(geojson, columns) {
|
|
24862
|
+
var headerMeta = {
|
|
24863
|
+
geometryType: inferGeometryType(geojson.features),
|
|
24864
|
+
columns: columns,
|
|
24865
|
+
featuresCount: geojson.features.length};
|
|
24866
|
+
var header = buildHeader(headerMeta);
|
|
24867
|
+
var features = geojson.features.map(function(feature) {
|
|
24868
|
+
var geometry = feature.geometry.type == 'GeometryCollection' ?
|
|
24869
|
+
parseGC(feature.geometry) :
|
|
24870
|
+
parseGeometry(feature.geometry);
|
|
24871
|
+
omitRedundantGeometryType(geometry, headerMeta.geometryType);
|
|
24872
|
+
return buildFeature(geometry, normalizeProperties(feature.properties, columns), headerMeta);
|
|
24873
|
+
});
|
|
24874
|
+
var featureBytes = features.reduce(function(sum, feature) {
|
|
24875
|
+
return sum + feature.length;
|
|
24876
|
+
}, 0);
|
|
24877
|
+
var output = new Uint8Array(magicbytes.length + header.length + featureBytes);
|
|
24878
|
+
var offset = magicbytes.length;
|
|
24879
|
+
output.set(header, offset);
|
|
24880
|
+
offset += header.length;
|
|
24881
|
+
features.forEach(function(feature) {
|
|
24882
|
+
output.set(feature, offset);
|
|
24883
|
+
offset += feature.length;
|
|
24884
|
+
});
|
|
24885
|
+
output.set(magicbytes);
|
|
24886
|
+
return output;
|
|
24887
|
+
}
|
|
24888
|
+
|
|
24889
|
+
function omitRedundantGeometryType(geometry, headerType) {
|
|
24890
|
+
if (headerType != GeometryType.Unknown && geometry.type == headerType) {
|
|
24891
|
+
geometry.type = GeometryType.Unknown;
|
|
24892
|
+
}
|
|
24893
|
+
}
|
|
24894
|
+
|
|
24895
|
+
function inferGeometryType(features) {
|
|
24896
|
+
var type;
|
|
24897
|
+
features.forEach(function(feature) {
|
|
24898
|
+
var next = GeometryType[feature.geometry.type] || GeometryType.Unknown;
|
|
24899
|
+
if (type === undefined) {
|
|
24900
|
+
type = next;
|
|
24901
|
+
} else if (type != next) {
|
|
24902
|
+
type = GeometryType.Unknown;
|
|
24903
|
+
}
|
|
24904
|
+
});
|
|
24905
|
+
if (type === undefined) {
|
|
24906
|
+
throw new Error('Could not infer geometry type for collection of features.');
|
|
24907
|
+
}
|
|
24908
|
+
return type;
|
|
24909
|
+
}
|
|
24910
|
+
|
|
24911
|
+
function normalizeProperties(properties, columns) {
|
|
24912
|
+
var copy = {};
|
|
24913
|
+
properties = properties || {};
|
|
24914
|
+
columns.forEach(function(column) {
|
|
24915
|
+
var val = properties[column.name];
|
|
24916
|
+
copy[column.name] = val === undefined ? null : val;
|
|
24917
|
+
});
|
|
24918
|
+
return copy;
|
|
24919
|
+
}
|
|
24920
|
+
|
|
24762
24921
|
function createColumnsVector(builder, columns) {
|
|
24763
24922
|
if (!columns || columns.length === 0) return 0;
|
|
24764
24923
|
var offsets = columns.map(function(col) {
|
|
@@ -24809,12 +24968,13 @@ ${svg}
|
|
|
24809
24968
|
var crsMeta = resolveOutputCRS(dataset);
|
|
24810
24969
|
return dataset.layers.map(function(lyr) {
|
|
24811
24970
|
var geojson = getFeatureCollection(lyr, dataset, opts);
|
|
24812
|
-
var
|
|
24971
|
+
var columns = getFlatGeobufColumns(lyr);
|
|
24972
|
+
var content = serializeWithColumns(geojson, columns);
|
|
24813
24973
|
var filename = lyr.name + '.' + extension;
|
|
24814
24974
|
if (crsMeta) {
|
|
24815
24975
|
content = rewriteHeaderWithCRS(content, crsMeta);
|
|
24816
24976
|
} else {
|
|
24817
|
-
message('Wrote', filename, 'without a CRS in the FlatGeobuf header (mapshaper could not derive
|
|
24977
|
+
message('Wrote', filename, 'without a CRS in the FlatGeobuf header (mapshaper could not derive CRS metadata for this dataset). Downstream tools may misinterpret the coordinates or refuse to load the file.');
|
|
24818
24978
|
}
|
|
24819
24979
|
return {
|
|
24820
24980
|
content: content,
|
|
@@ -24834,17 +24994,64 @@ ${svg}
|
|
|
24834
24994
|
};
|
|
24835
24995
|
}
|
|
24836
24996
|
|
|
24837
|
-
|
|
24997
|
+
function getFlatGeobufColumns(lyr) {
|
|
24998
|
+
var records = lyr.data ? lyr.data.getRecords() : [];
|
|
24999
|
+
return lyr.data ? lyr.data.getFields().map(function(name) {
|
|
25000
|
+
return {
|
|
25001
|
+
name: name,
|
|
25002
|
+
type: getFlatGeobufColumnType(name, records),
|
|
25003
|
+
title: null,
|
|
25004
|
+
description: null,
|
|
25005
|
+
width: -1,
|
|
25006
|
+
precision: -1,
|
|
25007
|
+
scale: -1,
|
|
25008
|
+
nullable: true,
|
|
25009
|
+
unique: false,
|
|
25010
|
+
primary_key: false
|
|
25011
|
+
};
|
|
25012
|
+
}) : [];
|
|
25013
|
+
}
|
|
25014
|
+
|
|
25015
|
+
function getFlatGeobufColumnType(name, records) {
|
|
25016
|
+
var type = getColumnType(name, records);
|
|
25017
|
+
if (type == 'boolean') return 2; // ColumnType.Bool
|
|
25018
|
+
if (type == 'number') return getFlatGeobufNumberType(name, records);
|
|
25019
|
+
if (type == 'object') return 12; // ColumnType.Json
|
|
25020
|
+
return 11; // ColumnType.String
|
|
25021
|
+
}
|
|
25022
|
+
|
|
25023
|
+
function getFlatGeobufNumberType(name, records) {
|
|
25024
|
+
var min = Infinity;
|
|
25025
|
+
var max = -Infinity;
|
|
25026
|
+
var hasValue = false;
|
|
25027
|
+
var val;
|
|
25028
|
+
for (var i = 0; i < records.length; i++) {
|
|
25029
|
+
val = records[i] ? records[i][name] : null;
|
|
25030
|
+
if (val === null || val === undefined) continue;
|
|
25031
|
+
if (!Number.isFinite(val) || Math.floor(val) !== val) {
|
|
25032
|
+
return 10; // ColumnType.Double
|
|
25033
|
+
}
|
|
25034
|
+
hasValue = true;
|
|
25035
|
+
if (val < min) min = val;
|
|
25036
|
+
if (val > max) max = val;
|
|
25037
|
+
}
|
|
25038
|
+
if (!hasValue) return 10; // ColumnType.Double
|
|
25039
|
+
if (min >= -2147483648 && max <= 2147483647) return 5; // ColumnType.Int
|
|
25040
|
+
if (Number.isSafeInteger(min) && Number.isSafeInteger(max)) return 7; // ColumnType.Long
|
|
25041
|
+
return 10; // ColumnType.Double
|
|
25042
|
+
}
|
|
25043
|
+
|
|
25044
|
+
// Try several strategies to derive CRS metadata for the dataset. Returns
|
|
24838
25045
|
// a CRS-meta object suitable for buildHeaderWithCRS(), or null if no
|
|
24839
|
-
//
|
|
24840
|
-
//
|
|
25046
|
+
// CRS metadata could be found. Prefer authority/code when available, but
|
|
25047
|
+
// also write WKT so custom CRSes can be read by CRS-aware tools.
|
|
24841
25048
|
function resolveOutputCRS(dataset) {
|
|
24842
25049
|
var info = (dataset && dataset.info) || {};
|
|
24843
25050
|
var meta;
|
|
24844
25051
|
|
|
24845
25052
|
// 1. Round-tripped from another FlatGeobuf
|
|
24846
25053
|
meta = normalizeCRS(info.flatgeobuf_crs);
|
|
24847
|
-
if (meta) return meta;
|
|
25054
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24848
25055
|
|
|
24849
25056
|
// 2. Round-tripped from a GeoPackage with an EPSG-coded SRS
|
|
24850
25057
|
if (info.geopackage_crs &&
|
|
@@ -24853,16 +25060,16 @@ ${svg}
|
|
|
24853
25060
|
org: 'EPSG',
|
|
24854
25061
|
code: info.geopackage_crs.organization_coordsys_id || info.geopackage_crs.srs_id
|
|
24855
25062
|
});
|
|
24856
|
-
if (meta) return meta;
|
|
25063
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24857
25064
|
}
|
|
24858
25065
|
|
|
24859
25066
|
// 3. Explicit "epsg:NNNN" / "esri:NNNN" string set by -proj or alike
|
|
24860
25067
|
meta = normalizeCRS(parseAuthorityCodeString(info.crs_string));
|
|
24861
|
-
if (meta) return meta;
|
|
25068
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24862
25069
|
|
|
24863
25070
|
// 4. AUTHORITY["EPSG", N] in a .prj/WKT1 string (typically from a Shapefile)
|
|
24864
25071
|
meta = normalizeCRS(parseAuthorityCodeFromWkt(info.wkt1));
|
|
24865
|
-
if (meta) return meta;
|
|
25072
|
+
if (meta) return addWktToCRS(meta, dataset);
|
|
24866
25073
|
|
|
24867
25074
|
// 5. Recognized CRS object: WGS-84 (any encoding) or Web Mercator.
|
|
24868
25075
|
// getDatasetCrsInfo() also auto-detects WGS-84 from lat/lng-like bounds,
|
|
@@ -24875,36 +25082,65 @@ ${svg}
|
|
|
24875
25082
|
}
|
|
24876
25083
|
if (crsInfo && crsInfo.crs) {
|
|
24877
25084
|
if (isWGS84(crsInfo.crs)) {
|
|
24878
|
-
return normalizeCRS({org: 'EPSG', code: 4326});
|
|
25085
|
+
return addWktToCRS(normalizeCRS({org: 'EPSG', code: 4326}), dataset, crsInfo);
|
|
24879
25086
|
}
|
|
24880
25087
|
if (isWebMercator(crsInfo.crs)) {
|
|
24881
|
-
return normalizeCRS({org: 'EPSG', code: 3857});
|
|
25088
|
+
return addWktToCRS(normalizeCRS({org: 'EPSG', code: 3857}), dataset, crsInfo);
|
|
24882
25089
|
}
|
|
25090
|
+
meta = addWktToCRS({}, dataset, crsInfo);
|
|
25091
|
+
if (meta) return meta;
|
|
24883
25092
|
}
|
|
24884
25093
|
|
|
24885
25094
|
return null;
|
|
24886
25095
|
}
|
|
24887
25096
|
|
|
24888
25097
|
function normalizeCRS(crs) {
|
|
24889
|
-
if (!crs
|
|
25098
|
+
if (!crs) return null;
|
|
24890
25099
|
var code = +crs.code;
|
|
24891
|
-
|
|
24892
|
-
code = Math.round(code);
|
|
25100
|
+
var hasCode = Number.isFinite(code) && code > 0;
|
|
25101
|
+
if (hasCode) code = Math.round(code);
|
|
24893
25102
|
var org = crs.org ? String(crs.org).toUpperCase() : null;
|
|
24894
|
-
if (!org && looksLikeEPSGCode(code)) {
|
|
25103
|
+
if (!org && hasCode && looksLikeEPSGCode(code)) {
|
|
24895
25104
|
org = 'EPSG';
|
|
24896
25105
|
}
|
|
24897
|
-
if (org != 'EPSG') return null;
|
|
25106
|
+
if (hasCode && org != 'EPSG') return null;
|
|
25107
|
+
if (!hasCode && !crs.wkt) return null;
|
|
24898
25108
|
return {
|
|
24899
|
-
org: 'EPSG',
|
|
24900
|
-
code: code,
|
|
25109
|
+
org: hasCode ? 'EPSG' : null,
|
|
25110
|
+
code: hasCode ? code : null,
|
|
24901
25111
|
name: crs.name || null,
|
|
24902
25112
|
description: crs.description || null,
|
|
24903
25113
|
wkt: crs.wkt || null,
|
|
24904
|
-
code_string: crs.code_string || ('EPSG:' + code)
|
|
25114
|
+
code_string: hasCode ? (crs.code_string || ('EPSG:' + code)) : null
|
|
24905
25115
|
};
|
|
24906
25116
|
}
|
|
24907
25117
|
|
|
25118
|
+
function addWktToCRS(meta, dataset, crsInfoArg) {
|
|
25119
|
+
if (!meta) return null;
|
|
25120
|
+
var info = dataset && dataset.info || {};
|
|
25121
|
+
if (meta.wkt && isWkt2(meta.wkt)) return meta;
|
|
25122
|
+
var crsInfo = crsInfoArg || getSafeDatasetCrsInfo(dataset);
|
|
25123
|
+
var crs = crsInfo && crsInfo.crs;
|
|
25124
|
+
var wkt = crs ? crsToWkt2(crs) : null;
|
|
25125
|
+
if (!wkt && meta.wkt) wkt = meta.wkt;
|
|
25126
|
+
if (!wkt && crs) wkt = crsToPrj(crs);
|
|
25127
|
+
if (!wkt && info.wkt1) wkt = info.wkt1;
|
|
25128
|
+
if (wkt) meta.wkt = wkt;
|
|
25129
|
+
return meta.code || meta.wkt ? meta : null;
|
|
25130
|
+
}
|
|
25131
|
+
|
|
25132
|
+
function getSafeDatasetCrsInfo(dataset) {
|
|
25133
|
+
try {
|
|
25134
|
+
return getDatasetCrsInfo(dataset);
|
|
25135
|
+
} catch (e) {
|
|
25136
|
+
return null;
|
|
25137
|
+
}
|
|
25138
|
+
}
|
|
25139
|
+
|
|
25140
|
+
function isWkt2(wkt) {
|
|
25141
|
+
return /^(GEODCRS|GEOGCRS|PROJCRS|VERTCRS|ENGCRS|BOUNDCRS|COMPOUNDCRS)\s*\[/i.test(String(wkt || '').trim());
|
|
25142
|
+
}
|
|
25143
|
+
|
|
24908
25144
|
function looksLikeEPSGCode(code) {
|
|
24909
25145
|
return code >= 2000 && code <= 1000000;
|
|
24910
25146
|
}
|
|
@@ -25034,7 +25270,7 @@ ${svg}
|
|
|
25034
25270
|
Object.keys(props).forEach(function(name) {
|
|
25035
25271
|
if (!isSupportedPropertyName(name)) return;
|
|
25036
25272
|
var value = props[name];
|
|
25037
|
-
var next = inferValueType(value);
|
|
25273
|
+
var next = inferValueType$1(value);
|
|
25038
25274
|
if (!next) return;
|
|
25039
25275
|
if (!(name in index)) {
|
|
25040
25276
|
index[name] = next;
|
|
@@ -25116,7 +25352,7 @@ ${svg}
|
|
|
25116
25352
|
fields.length == 1 && fields[0] == GeoJSON.ID_FIELD);
|
|
25117
25353
|
}
|
|
25118
25354
|
|
|
25119
|
-
function inferValueType(value) {
|
|
25355
|
+
function inferValueType$1(value) {
|
|
25120
25356
|
if (value === null || value === undefined) return null;
|
|
25121
25357
|
if (value instanceof Date) return 'DATETIME';
|
|
25122
25358
|
if (typeof value == 'boolean') return 'BOOLEAN';
|
|
@@ -25446,6 +25682,210 @@ ${svg}
|
|
|
25446
25682
|
return normalized;
|
|
25447
25683
|
}
|
|
25448
25684
|
|
|
25685
|
+
var writerPromise = null;
|
|
25686
|
+
var dynamicImportModule$1 = Function('id', 'return import(id)');
|
|
25687
|
+
|
|
25688
|
+
async function exportGeoParquet(dataset, opts, filenameOverride) {
|
|
25689
|
+
var writer = await loadGeoParquetWriter();
|
|
25690
|
+
var extension = opts.extension || 'parquet';
|
|
25691
|
+
if (opts.file) {
|
|
25692
|
+
extension = getFileExtension(opts.file) || extension;
|
|
25693
|
+
}
|
|
25694
|
+
return dataset.layers.map(function(lyr) {
|
|
25695
|
+
if (!lyr.geometry_type) {
|
|
25696
|
+
stop$1('GeoParquet export requires a geometry layer');
|
|
25697
|
+
}
|
|
25698
|
+
var features = exportLayerAsGeoJSON(lyr, dataset, opts, true, null);
|
|
25699
|
+
var output = buildGeoParquetColumns(features);
|
|
25700
|
+
var geoMetadata = buildGeoMetadata(features, dataset);
|
|
25701
|
+
var content = writer.parquetWriteBuffer({
|
|
25702
|
+
columnData: output.columnData,
|
|
25703
|
+
kvMetadata: [{
|
|
25704
|
+
key: 'geo',
|
|
25705
|
+
value: JSON.stringify(geoMetadata)
|
|
25706
|
+
}]
|
|
25707
|
+
});
|
|
25708
|
+
return {
|
|
25709
|
+
filename: filenameOverride || (lyr.name + '.' + extension),
|
|
25710
|
+
content: content
|
|
25711
|
+
};
|
|
25712
|
+
});
|
|
25713
|
+
}
|
|
25714
|
+
|
|
25715
|
+
function buildGeoParquetColumns(features, writer) {
|
|
25716
|
+
var geometryName = 'geometry';
|
|
25717
|
+
var names = getPropertyNames(features);
|
|
25718
|
+
var columnData = [];
|
|
25719
|
+
columnData.push({
|
|
25720
|
+
name: geometryName,
|
|
25721
|
+
data: features.map(function(feat) {
|
|
25722
|
+
return feat.geometry || null;
|
|
25723
|
+
}),
|
|
25724
|
+
type: 'GEOMETRY'
|
|
25725
|
+
});
|
|
25726
|
+
names.forEach(function(name) {
|
|
25727
|
+
var values = features.map(function(feat) {
|
|
25728
|
+
return feat.properties ? feat.properties[name] : null;
|
|
25729
|
+
});
|
|
25730
|
+
columnData.push(buildAttributeColumn(name, values));
|
|
25731
|
+
});
|
|
25732
|
+
return {columnData: columnData, geometryColumn: geometryName};
|
|
25733
|
+
}
|
|
25734
|
+
|
|
25735
|
+
function buildAttributeColumn(name, values) {
|
|
25736
|
+
var info = inferColumnType(values);
|
|
25737
|
+
return {
|
|
25738
|
+
name: name,
|
|
25739
|
+
data: values.map(function(value) {
|
|
25740
|
+
return normalizeFieldValue(value, info.type);
|
|
25741
|
+
}),
|
|
25742
|
+
type: info.type
|
|
25743
|
+
};
|
|
25744
|
+
}
|
|
25745
|
+
|
|
25746
|
+
function inferColumnType(values) {
|
|
25747
|
+
var type = null;
|
|
25748
|
+
for (var i = 0; i < values.length; i++) {
|
|
25749
|
+
var valueType = inferValueType(values[i]);
|
|
25750
|
+
if (!valueType) continue;
|
|
25751
|
+
if (!type) {
|
|
25752
|
+
type = valueType;
|
|
25753
|
+
} else if (type != valueType) {
|
|
25754
|
+
if ((type == 'INT32' || type == 'DOUBLE') &&
|
|
25755
|
+
(valueType == 'INT32' || valueType == 'DOUBLE')) {
|
|
25756
|
+
type = 'DOUBLE';
|
|
25757
|
+
} else {
|
|
25758
|
+
type = 'STRING';
|
|
25759
|
+
break;
|
|
25760
|
+
}
|
|
25761
|
+
}
|
|
25762
|
+
}
|
|
25763
|
+
return {type: type || 'STRING'};
|
|
25764
|
+
}
|
|
25765
|
+
|
|
25766
|
+
function inferValueType(value) {
|
|
25767
|
+
if (value === null || value === undefined) return null;
|
|
25768
|
+
if (typeof value == 'boolean') return 'BOOLEAN';
|
|
25769
|
+
if (typeof value == 'number') {
|
|
25770
|
+
if (!Number.isFinite(value)) return 'STRING';
|
|
25771
|
+
if (Math.floor(value) === value && value >= -2147483648 && value <= 2147483647) {
|
|
25772
|
+
return 'INT32';
|
|
25773
|
+
}
|
|
25774
|
+
return 'DOUBLE';
|
|
25775
|
+
}
|
|
25776
|
+
if (typeof value == 'bigint') return 'STRING';
|
|
25777
|
+
if (value instanceof Date) return 'TIMESTAMP';
|
|
25778
|
+
if (value instanceof Uint8Array) return 'BYTE_ARRAY';
|
|
25779
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) return 'BYTE_ARRAY';
|
|
25780
|
+
if (Array.isArray(value) || utils.isObject(value)) return 'JSON';
|
|
25781
|
+
return 'STRING';
|
|
25782
|
+
}
|
|
25783
|
+
|
|
25784
|
+
function normalizeFieldValue(value, type) {
|
|
25785
|
+
if (value === undefined) return null;
|
|
25786
|
+
if (value === null) return null;
|
|
25787
|
+
if (type == 'TIMESTAMP') return value instanceof Date ? value : new Date(value);
|
|
25788
|
+
if (type == 'BYTE_ARRAY') {
|
|
25789
|
+
if (value instanceof Uint8Array) return value;
|
|
25790
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) {
|
|
25791
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
25792
|
+
}
|
|
25793
|
+
return null;
|
|
25794
|
+
}
|
|
25795
|
+
if (type == 'JSON') return value;
|
|
25796
|
+
if (type == 'BOOLEAN') return !!value;
|
|
25797
|
+
if (type == 'INT32' || type == 'DOUBLE') {
|
|
25798
|
+
var num = Number(value);
|
|
25799
|
+
return Number.isFinite(num) ? num : null;
|
|
25800
|
+
}
|
|
25801
|
+
return String(value);
|
|
25802
|
+
}
|
|
25803
|
+
|
|
25804
|
+
function getPropertyNames(features) {
|
|
25805
|
+
var index = {};
|
|
25806
|
+
features.forEach(function(feat) {
|
|
25807
|
+
var props = feat.properties || {};
|
|
25808
|
+
Object.keys(props).forEach(function(name) {
|
|
25809
|
+
index[name] = true;
|
|
25810
|
+
});
|
|
25811
|
+
});
|
|
25812
|
+
return Object.keys(index);
|
|
25813
|
+
}
|
|
25814
|
+
|
|
25815
|
+
function buildGeoMetadata(features, dataset) {
|
|
25816
|
+
var geomTypes = utils.uniq(features.map(function(feat) {
|
|
25817
|
+
return feat.geometry && feat.geometry.type || null;
|
|
25818
|
+
}).filter(Boolean));
|
|
25819
|
+
var crs = getGeoMetadataCrs(dataset);
|
|
25820
|
+
var geomMeta = {
|
|
25821
|
+
encoding: 'WKB',
|
|
25822
|
+
geometry_types: geomTypes
|
|
25823
|
+
};
|
|
25824
|
+
if (crs) {
|
|
25825
|
+
geomMeta.crs = crs;
|
|
25826
|
+
}
|
|
25827
|
+
return {
|
|
25828
|
+
version: '1.1.0',
|
|
25829
|
+
primary_column: 'geometry',
|
|
25830
|
+
columns: {
|
|
25831
|
+
geometry: geomMeta
|
|
25832
|
+
}
|
|
25833
|
+
};
|
|
25834
|
+
}
|
|
25835
|
+
|
|
25836
|
+
function getGeoMetadataCrs(dataset) {
|
|
25837
|
+
var info = dataset && dataset.info || {};
|
|
25838
|
+
if (info.geoparquet_crs && utils.isObject(info.geoparquet_crs)) {
|
|
25839
|
+
return info.geoparquet_crs;
|
|
25840
|
+
}
|
|
25841
|
+
return convertCrsToProjjson(info.crs_string, info.wkt1);
|
|
25842
|
+
}
|
|
25843
|
+
|
|
25844
|
+
function convertCrsToProjjson(crsString, wkt1) {
|
|
25845
|
+
var mproj = require$1('mproj');
|
|
25846
|
+
var converter = getProjjsonFromProj4Converter(mproj);
|
|
25847
|
+
if (!converter) return null;
|
|
25848
|
+
try {
|
|
25849
|
+
var crsObj = crsString ? parseCrsString$1(crsString) : (wkt1 ? parsePrj(wkt1) : null);
|
|
25850
|
+
if (!crsObj) return null;
|
|
25851
|
+
var projjson = converter(crsObj);
|
|
25852
|
+
if (utils.isString(projjson)) {
|
|
25853
|
+
projjson = JSON.parse(projjson);
|
|
25854
|
+
}
|
|
25855
|
+
return utils.isObject(projjson) ? projjson : null;
|
|
25856
|
+
} catch (e) {
|
|
25857
|
+
return null;
|
|
25858
|
+
}
|
|
25859
|
+
}
|
|
25860
|
+
|
|
25861
|
+
function getProjjsonFromProj4Converter(mproj) {
|
|
25862
|
+
if (mproj && typeof mproj.projjson_from_proj4 == 'function') {
|
|
25863
|
+
return mproj.projjson_from_proj4;
|
|
25864
|
+
}
|
|
25865
|
+
if (mproj && mproj.internal && typeof mproj.internal.projjson_from_proj4 == 'function') {
|
|
25866
|
+
return mproj.internal.projjson_from_proj4;
|
|
25867
|
+
}
|
|
25868
|
+
return null;
|
|
25869
|
+
}
|
|
25870
|
+
|
|
25871
|
+
async function loadGeoParquetWriter() {
|
|
25872
|
+
if (runningInBrowser()) {
|
|
25873
|
+
var mod = require$1('hyparquet-writer');
|
|
25874
|
+
if (mod && mod.default && !mod.parquetWriteBuffer) {
|
|
25875
|
+
mod = mod.default;
|
|
25876
|
+
}
|
|
25877
|
+
if (!mod || !mod.parquetWriteBuffer) {
|
|
25878
|
+
stop$1('GeoParquet writer library is not loaded');
|
|
25879
|
+
}
|
|
25880
|
+
return mod;
|
|
25881
|
+
}
|
|
25882
|
+
if (!writerPromise) {
|
|
25883
|
+
writerPromise = dynamicImportModule$1('hyparquet-writer');
|
|
25884
|
+
}
|
|
25885
|
+
var nodeMod = await writerPromise;
|
|
25886
|
+
return nodeMod.default && !nodeMod.parquetWriteBuffer ? nodeMod.default : nodeMod;
|
|
25887
|
+
}
|
|
25888
|
+
|
|
25449
25889
|
function getOutputFormat(dataset, opts) {
|
|
25450
25890
|
var outFile = opts.file || null,
|
|
25451
25891
|
inFmt = dataset.info && dataset.info.input_formats && dataset.info.input_formats[0],
|
|
@@ -25489,6 +25929,8 @@ ${svg}
|
|
|
25489
25929
|
format = 'geopackage';
|
|
25490
25930
|
} else if (ext == 'fgb') {
|
|
25491
25931
|
format = 'flatgeobuf';
|
|
25932
|
+
} else if (ext == 'parquet' || ext == 'geoparquet') {
|
|
25933
|
+
format = 'geoparquet';
|
|
25492
25934
|
} else if (ext == 'svg') {
|
|
25493
25935
|
format = 'svg';
|
|
25494
25936
|
} else if (ext == 'kml' || ext == 'kmz') {
|
|
@@ -25579,6 +26021,16 @@ ${svg}
|
|
|
25579
26021
|
}
|
|
25580
26022
|
datasets.forEach(sortExportLayers);
|
|
25581
26023
|
files = await exportGeoPackage(datasets[0], opts);
|
|
26024
|
+
} else if (format == 'geoparquet') {
|
|
26025
|
+
var layerCount = datasets.reduce(function(sum, d) {
|
|
26026
|
+
return sum + d.layers.length;
|
|
26027
|
+
}, 0);
|
|
26028
|
+
var singleFileName = opts.file && layerCount == 1 ? opts.file : null;
|
|
26029
|
+
files = [];
|
|
26030
|
+
for (var i = 0; i < datasets.length; i++) {
|
|
26031
|
+
sortExportLayers(datasets[i]);
|
|
26032
|
+
files = files.concat(await exportGeoParquet(datasets[i], opts, singleFileName));
|
|
26033
|
+
}
|
|
25582
26034
|
} else {
|
|
25583
26035
|
files = datasets.reduce(function(memo, dataset) {
|
|
25584
26036
|
sortExportLayers(dataset);
|
|
@@ -26651,7 +27103,7 @@ ${svg}
|
|
|
26651
27103
|
});
|
|
26652
27104
|
|
|
26653
27105
|
function isSupportedOutputFormat(fmt) {
|
|
26654
|
-
var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg', 'kml', PACKAGE_EXT, 'flatgeobuf', 'geopackage'];
|
|
27106
|
+
var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg', 'kml', PACKAGE_EXT, 'flatgeobuf', 'geopackage', 'geoparquet'];
|
|
26655
27107
|
return types.indexOf(fmt) > -1;
|
|
26656
27108
|
}
|
|
26657
27109
|
|
|
@@ -26668,6 +27120,7 @@ ${svg}
|
|
|
26668
27120
|
shapefile: 'Shapefile',
|
|
26669
27121
|
flatgeobuf: 'Flatgeobuf',
|
|
26670
27122
|
geopackage: 'GeoPackage',
|
|
27123
|
+
geoparquet: 'GeoParquet',
|
|
26671
27124
|
svg: 'SVG'
|
|
26672
27125
|
}[fmt] || '';
|
|
26673
27126
|
}
|
|
@@ -26779,6 +27232,8 @@ ${svg}
|
|
|
26779
27232
|
} else if (o.format == 'tsv') {
|
|
26780
27233
|
o.format = 'dsv';
|
|
26781
27234
|
o.delimiter = o.delimiter || '\t';
|
|
27235
|
+
} else if (o.format == 'parquet') {
|
|
27236
|
+
o.format = 'geoparquet';
|
|
26782
27237
|
}
|
|
26783
27238
|
if (!isSupportedOutputFormat(o.format)) {
|
|
26784
27239
|
error('Unsupported output format:', o.format);
|
|
@@ -28017,6 +28472,10 @@ ${svg}
|
|
|
28017
28472
|
old_alias: 'json-subtree',
|
|
28018
28473
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
28019
28474
|
})
|
|
28475
|
+
.option('ndjson', {
|
|
28476
|
+
type: 'flag',
|
|
28477
|
+
describe: '[JSON/GeoJSON] input is newline-delimited JSON objects'
|
|
28478
|
+
})
|
|
28020
28479
|
.option('single-part', {
|
|
28021
28480
|
type: 'flag',
|
|
28022
28481
|
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
@@ -28033,7 +28492,7 @@ ${svg}
|
|
|
28033
28492
|
}
|
|
28034
28493
|
})
|
|
28035
28494
|
.option('format', {
|
|
28036
|
-
describe: 'options: shapefile,geojson,topojson,flatgeobuf,geopackage,json,dbf,csv,tsv,svg'
|
|
28495
|
+
describe: 'options: shapefile,geojson,topojson,flatgeobuf,geopackage,geoparquet,json,dbf,csv,tsv,svg'
|
|
28037
28496
|
})
|
|
28038
28497
|
.option('target', targetOpt)
|
|
28039
28498
|
.option('force', {
|
|
@@ -28109,10 +28568,6 @@ ${svg}
|
|
|
28109
28568
|
describe: '[TopoJSON] export coordinates without quantization',
|
|
28110
28569
|
type: 'flag'
|
|
28111
28570
|
})
|
|
28112
|
-
.option('metadata', {
|
|
28113
|
-
// describe: '[TopoJSON] Add a metadata object containing CRS information',
|
|
28114
|
-
type: 'flag'
|
|
28115
|
-
})
|
|
28116
28571
|
.option('no-point-quantization', {
|
|
28117
28572
|
// describe: '[TopoJSON] export point coordinates without quantization',
|
|
28118
28573
|
type: 'flag'
|
|
@@ -28155,6 +28610,10 @@ ${svg}
|
|
|
28155
28610
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
28156
28611
|
type: 'flag'
|
|
28157
28612
|
})
|
|
28613
|
+
.option('metadata', {
|
|
28614
|
+
describe: '[SVG/TopoJSON] include metadata in output',
|
|
28615
|
+
type: 'flag'
|
|
28616
|
+
})
|
|
28158
28617
|
.option('width', {
|
|
28159
28618
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
28160
28619
|
type: 'number'
|
|
@@ -28217,10 +28676,7 @@ ${svg}
|
|
|
28217
28676
|
.option('final', {
|
|
28218
28677
|
type: 'flag' // for testing
|
|
28219
28678
|
})
|
|
28220
|
-
|
|
28221
|
-
// describe: '[TopoJSON] add a metadata object',
|
|
28222
|
-
type: 'flag'
|
|
28223
|
-
});
|
|
28679
|
+
;
|
|
28224
28680
|
|
|
28225
28681
|
parser.section('Editing commands');
|
|
28226
28682
|
|
|
@@ -32479,7 +32935,13 @@ ${svg}
|
|
|
32479
32935
|
var str = readFirstChars(reader, 1000);
|
|
32480
32936
|
var type = identifyJSONString(str, opts);
|
|
32481
32937
|
var dataset, retn;
|
|
32482
|
-
if (
|
|
32938
|
+
if (opts.ndjson) {
|
|
32939
|
+
// NDJSON can represent either newline-delimited GeoJSON features/geometries
|
|
32940
|
+
// or plain JSON records. Defer type detection until after line parsing.
|
|
32941
|
+
retn = {
|
|
32942
|
+
content: reader.toString('utf8')
|
|
32943
|
+
};
|
|
32944
|
+
} else if (type == 'geojson') { // consider only for larger files
|
|
32483
32945
|
dataset = importGeoJSONFile(reader, opts);
|
|
32484
32946
|
retn = {
|
|
32485
32947
|
dataset: dataset,
|
|
@@ -32531,6 +32993,12 @@ ${svg}
|
|
|
32531
32993
|
}
|
|
32532
32994
|
|
|
32533
32995
|
if (content) {
|
|
32996
|
+
if (opts.ndjson) {
|
|
32997
|
+
var nd = importNDJSON(content, opts);
|
|
32998
|
+
retn.dataset = nd.dataset;
|
|
32999
|
+
retn.format = nd.format;
|
|
33000
|
+
return retn;
|
|
33001
|
+
}
|
|
32534
33002
|
if (utils.isString(content)) {
|
|
32535
33003
|
try {
|
|
32536
33004
|
content = JSON.parse(content); // ~3sec for 100MB string
|
|
@@ -32569,6 +33037,54 @@ ${svg}
|
|
|
32569
33037
|
});
|
|
32570
33038
|
}
|
|
32571
33039
|
|
|
33040
|
+
function importNDJSON(content, opts) {
|
|
33041
|
+
var lines = utils.isString(content) ? utils.splitLines(content) : [];
|
|
33042
|
+
var objects = [];
|
|
33043
|
+
var firstGeo = null;
|
|
33044
|
+
for (var i = 0; i < lines.length; i++) {
|
|
33045
|
+
var raw = lines[i].trim();
|
|
33046
|
+
if (!raw) continue;
|
|
33047
|
+
var obj;
|
|
33048
|
+
try {
|
|
33049
|
+
obj = JSON.parse(raw);
|
|
33050
|
+
} catch (e) {
|
|
33051
|
+
stop$1('NDJSON parsing error on line ' + (i + 1) + ': ' + e.message);
|
|
33052
|
+
}
|
|
33053
|
+
objects.push(obj);
|
|
33054
|
+
if (firstGeo === null) {
|
|
33055
|
+
firstGeo = isGeoJSONObject(obj);
|
|
33056
|
+
} else if (firstGeo !== isGeoJSONObject(obj)) {
|
|
33057
|
+
stop$1('NDJSON input mixes GeoJSON and non-GeoJSON objects');
|
|
33058
|
+
}
|
|
33059
|
+
}
|
|
33060
|
+
if (objects.length === 0) {
|
|
33061
|
+
stop$1('NDJSON input does not contain any JSON objects');
|
|
33062
|
+
}
|
|
33063
|
+
if (!firstGeo) {
|
|
33064
|
+
return {dataset: importJSONTable(objects), format: 'json'};
|
|
33065
|
+
}
|
|
33066
|
+
var parser = new GeoJSONParser(getGeoJSONImportOpts(opts));
|
|
33067
|
+
objects.forEach(function(obj) {
|
|
33068
|
+
if (obj && obj.type == 'FeatureCollection') {
|
|
33069
|
+
(obj.features || []).forEach(parser.parseObject);
|
|
33070
|
+
} else if (obj && obj.type == 'GeometryCollection') {
|
|
33071
|
+
(obj.geometries || []).forEach(parser.parseObject);
|
|
33072
|
+
} else {
|
|
33073
|
+
parser.parseObject(obj);
|
|
33074
|
+
}
|
|
33075
|
+
});
|
|
33076
|
+
return {dataset: parser.done(), format: 'geojson'};
|
|
33077
|
+
}
|
|
33078
|
+
|
|
33079
|
+
function isGeoJSONObject(obj) {
|
|
33080
|
+
if (!obj || typeof obj != 'object') return false;
|
|
33081
|
+
var type = obj.type;
|
|
33082
|
+
return type == 'Feature' || type == 'FeatureCollection' ||
|
|
33083
|
+
type == 'GeometryCollection' || type == 'Point' || type == 'MultiPoint' ||
|
|
33084
|
+
type == 'LineString' || type == 'MultiLineString' ||
|
|
33085
|
+
type == 'Polygon' || type == 'MultiPolygon';
|
|
33086
|
+
}
|
|
33087
|
+
|
|
32572
33088
|
// path: path from top-level to the target object
|
|
32573
33089
|
function selectFromObject(o, path) {
|
|
32574
33090
|
var arrayRxp = /(.*)\[([0-9]+)\]$/; // array bracket notation w/ index
|
|
@@ -32620,19 +33136,43 @@ ${svg}
|
|
|
32620
33136
|
dataset.info = dataset.info || {};
|
|
32621
33137
|
var crs = normalizeCRSMeta(headerMeta.crs || null);
|
|
32622
33138
|
dataset.info.flatgeobuf_crs = crs;
|
|
32623
|
-
if (crs
|
|
32624
|
-
dataset
|
|
32625
|
-
await initProjLibrary({crs: dataset.info.crs_string});
|
|
32626
|
-
} else if (crs && crs.wkt) {
|
|
32627
|
-
warnOnce('Unable to import WKT2 CRS from FlatGeobuf');
|
|
33139
|
+
if (crs) {
|
|
33140
|
+
await importFlatGeobufCRS(dataset, crs);
|
|
32628
33141
|
}
|
|
32629
33142
|
return dataset;
|
|
32630
33143
|
}
|
|
32631
33144
|
|
|
33145
|
+
async function importFlatGeobufCRS(dataset, crs) {
|
|
33146
|
+
var crsString = crs.org && crs.code ? crs.org.toLowerCase() + ':' + crs.code : null;
|
|
33147
|
+
if (crsString) {
|
|
33148
|
+
try {
|
|
33149
|
+
await initProjLibrary({crs: crsString});
|
|
33150
|
+
dataset.info.crs_string = crsString;
|
|
33151
|
+
return;
|
|
33152
|
+
} catch (e) {
|
|
33153
|
+
// Fall through and try WKT metadata if an authority lookup is unavailable.
|
|
33154
|
+
}
|
|
33155
|
+
}
|
|
33156
|
+
if (crs.wkt) {
|
|
33157
|
+
try {
|
|
33158
|
+
// Validate that mproj can parse the WKT, then keep the equivalent Proj4
|
|
33159
|
+
// string in crs_string so downstream projection handling works normally.
|
|
33160
|
+
parseWkt(crs.wkt);
|
|
33161
|
+
dataset.info.crs_string = wktToProj(crs.wkt);
|
|
33162
|
+
return;
|
|
33163
|
+
} catch (e) {
|
|
33164
|
+
warnOnce('Unable to import WKT CRS from FlatGeobuf');
|
|
33165
|
+
}
|
|
33166
|
+
}
|
|
33167
|
+
}
|
|
33168
|
+
|
|
32632
33169
|
function normalizeCRSMeta(crs) {
|
|
32633
33170
|
if (!crs) return null;
|
|
32634
33171
|
var code = +crs.code;
|
|
32635
|
-
if (
|
|
33172
|
+
if (!Number.isFinite(code) || code <= 0) {
|
|
33173
|
+
return Object.assign({}, crs, {code: null});
|
|
33174
|
+
}
|
|
33175
|
+
if (crs.org) return crs;
|
|
32636
33176
|
code = Math.round(code);
|
|
32637
33177
|
if (code >= 2000 && code <= 1000000) {
|
|
32638
33178
|
// Some encoders write code but omit authority org; default to EPSG.
|
|
@@ -33134,6 +33674,372 @@ ${svg}
|
|
|
33134
33674
|
return obj;
|
|
33135
33675
|
}
|
|
33136
33676
|
|
|
33677
|
+
var hyparquetPromise = null;
|
|
33678
|
+
var dynamicImportModule = Function('id', 'return import(id)');
|
|
33679
|
+
var mproj = null;
|
|
33680
|
+
|
|
33681
|
+
async function importGeoParquet(input, optsArg) {
|
|
33682
|
+
var opts = optsArg || {};
|
|
33683
|
+
var hyparquet = await loadHyparquetLib();
|
|
33684
|
+
var source = getGeoParquetSource(input);
|
|
33685
|
+
var file = await getHyparquetFile(source, hyparquet);
|
|
33686
|
+
var metadata = await hyparquet.parquetMetadataAsync(file);
|
|
33687
|
+
var geo = parseGeoParquetMetadata(metadata);
|
|
33688
|
+
var rows = await hyparquet.parquetReadObjects({
|
|
33689
|
+
file: file,
|
|
33690
|
+
rowFormat: 'object'
|
|
33691
|
+
});
|
|
33692
|
+
var geometryColumn = getGeoParquetGeometryColumn(rows, geo);
|
|
33693
|
+
if (!geometryColumn && hasUnsupportedGeometryEncoding(geo)) {
|
|
33694
|
+
warnOnce('Unable to import GeoParquet geometry: native encodings are not supported (expected WKB). Importing attribute data only.');
|
|
33695
|
+
}
|
|
33696
|
+
var dataset = convertGeoParquetRows(rows, geo, opts, geometryColumn);
|
|
33697
|
+
var crs = getGeoParquetCrs(geo, geometryColumn);
|
|
33698
|
+
dataset.info = dataset.info || {};
|
|
33699
|
+
dataset.info.geoparquet_geo = geo;
|
|
33700
|
+
dataset.info.geoparquet_crs = crs;
|
|
33701
|
+
if (crs) {
|
|
33702
|
+
var crsString = await resolveGeoParquetCrsString(crs);
|
|
33703
|
+
if (!crsString) {
|
|
33704
|
+
warnOnce('Unable to import CRS from GeoParquet metadata');
|
|
33705
|
+
}
|
|
33706
|
+
dataset.info.crs_string = crsString || null;
|
|
33707
|
+
}
|
|
33708
|
+
return dataset;
|
|
33709
|
+
}
|
|
33710
|
+
|
|
33711
|
+
async function loadHyparquetLib() {
|
|
33712
|
+
if (runningInBrowser()) {
|
|
33713
|
+
var mod = require$1('hyparquet');
|
|
33714
|
+
if (mod && mod.default && !mod.parquetReadObjects) {
|
|
33715
|
+
mod = mod.default;
|
|
33716
|
+
}
|
|
33717
|
+
if (!mod || !mod.parquetReadObjects || !mod.parquetMetadataAsync) {
|
|
33718
|
+
stop$1('GeoParquet library is not loaded');
|
|
33719
|
+
}
|
|
33720
|
+
return mod;
|
|
33721
|
+
}
|
|
33722
|
+
if (!hyparquetPromise) {
|
|
33723
|
+
hyparquetPromise = dynamicImportModule('hyparquet');
|
|
33724
|
+
}
|
|
33725
|
+
var nodeMod = await hyparquetPromise;
|
|
33726
|
+
return nodeMod.default && !nodeMod.parquetReadObjects ? nodeMod.default : nodeMod;
|
|
33727
|
+
}
|
|
33728
|
+
|
|
33729
|
+
function getGeoParquetSource(input) {
|
|
33730
|
+
if (!input) return null;
|
|
33731
|
+
if (Object.prototype.hasOwnProperty.call(input, 'content')) {
|
|
33732
|
+
return input.content || input.filename || null;
|
|
33733
|
+
}
|
|
33734
|
+
return input;
|
|
33735
|
+
}
|
|
33736
|
+
|
|
33737
|
+
async function getHyparquetFile(source, hyparquet) {
|
|
33738
|
+
if (!source) {
|
|
33739
|
+
stop$1('Missing GeoParquet data');
|
|
33740
|
+
}
|
|
33741
|
+
if (utils.isString(source)) {
|
|
33742
|
+
if (!hyparquet.asyncBufferFromFile) {
|
|
33743
|
+
stop$1('Unable to read GeoParquet file path');
|
|
33744
|
+
}
|
|
33745
|
+
return hyparquet.asyncBufferFromFile(source);
|
|
33746
|
+
}
|
|
33747
|
+
return toArrayBuffer(source);
|
|
33748
|
+
}
|
|
33749
|
+
|
|
33750
|
+
function toArrayBuffer(content) {
|
|
33751
|
+
if (content instanceof ArrayBuffer) {
|
|
33752
|
+
return content;
|
|
33753
|
+
}
|
|
33754
|
+
if (content instanceof Uint8Array) {
|
|
33755
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33756
|
+
}
|
|
33757
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(content)) {
|
|
33758
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33759
|
+
}
|
|
33760
|
+
if (ArrayBuffer.isView(content)) {
|
|
33761
|
+
return content.buffer.slice(content.byteOffset, content.byteOffset + content.byteLength);
|
|
33762
|
+
}
|
|
33763
|
+
if (utils.isArray(content)) {
|
|
33764
|
+
return new Uint8Array(content).buffer;
|
|
33765
|
+
}
|
|
33766
|
+
stop$1('Unsupported GeoParquet input type');
|
|
33767
|
+
}
|
|
33768
|
+
|
|
33769
|
+
function convertGeoParquetRows(rows, geo, opts, geometryColumnArg) {
|
|
33770
|
+
var importer = new GeoJSONParser(opts);
|
|
33771
|
+
var geometryColumn = geometryColumnArg === undefined ?
|
|
33772
|
+
getGeoParquetGeometryColumn(rows, geo) :
|
|
33773
|
+
geometryColumnArg;
|
|
33774
|
+
var geometryColumns = getGeoParquetGeometryColumns(geo);
|
|
33775
|
+
rows.forEach(function(row) {
|
|
33776
|
+
if (!utils.isObject(row)) return;
|
|
33777
|
+
var feature = convertGeoParquetRow(row, geometryColumn, geometryColumns);
|
|
33778
|
+
importer.parseObject(feature);
|
|
33779
|
+
});
|
|
33780
|
+
return importer.done();
|
|
33781
|
+
}
|
|
33782
|
+
|
|
33783
|
+
function convertGeoParquetRow(row, geometryColumn, geometryColumns) {
|
|
33784
|
+
var feature = {
|
|
33785
|
+
type: 'Feature',
|
|
33786
|
+
properties: {},
|
|
33787
|
+
geometry: null
|
|
33788
|
+
};
|
|
33789
|
+
if (geometryColumn && row[geometryColumn] !== undefined) {
|
|
33790
|
+
feature.geometry = row[geometryColumn] || null;
|
|
33791
|
+
}
|
|
33792
|
+
for (var key in row) {
|
|
33793
|
+
if (!Object.prototype.hasOwnProperty.call(row, key)) continue;
|
|
33794
|
+
if (key == geometryColumn || geometryColumns.indexOf(key) > -1) continue;
|
|
33795
|
+
feature.properties[key] = normalizeGeoParquetValue(row[key], key);
|
|
33796
|
+
}
|
|
33797
|
+
return feature;
|
|
33798
|
+
}
|
|
33799
|
+
|
|
33800
|
+
function normalizeGeoParquetValue(val, fieldName) {
|
|
33801
|
+
if (typeof val == 'bigint') {
|
|
33802
|
+
return normalizeBigIntValue(val, fieldName);
|
|
33803
|
+
}
|
|
33804
|
+
if (Array.isArray(val)) {
|
|
33805
|
+
return val.map(function(item) {
|
|
33806
|
+
return normalizeGeoParquetValue(item, fieldName);
|
|
33807
|
+
});
|
|
33808
|
+
}
|
|
33809
|
+
if (val && utils.isObject(val)) {
|
|
33810
|
+
var out = {};
|
|
33811
|
+
for (var key in val) {
|
|
33812
|
+
if (Object.prototype.hasOwnProperty.call(val, key)) {
|
|
33813
|
+
out[key] = normalizeGeoParquetValue(val[key], fieldName);
|
|
33814
|
+
}
|
|
33815
|
+
}
|
|
33816
|
+
return out;
|
|
33817
|
+
}
|
|
33818
|
+
return val;
|
|
33819
|
+
}
|
|
33820
|
+
|
|
33821
|
+
function normalizeBigIntValue(val, fieldName) {
|
|
33822
|
+
var num = Number(val);
|
|
33823
|
+
if (!Number.isFinite(num)) {
|
|
33824
|
+
warnOnce('GeoParquet field "' + fieldName + '" contains BigInt values outside JavaScript Number range; precision will be lost.');
|
|
33825
|
+
return num;
|
|
33826
|
+
}
|
|
33827
|
+
if (BigInt(Math.trunc(num)) !== val) {
|
|
33828
|
+
warnOnce('GeoParquet field "' + fieldName + '" contains BigInt values that exceed Number.MAX_SAFE_INTEGER; precision will be lost.');
|
|
33829
|
+
}
|
|
33830
|
+
return num;
|
|
33831
|
+
}
|
|
33832
|
+
|
|
33833
|
+
function getGeoParquetGeometryColumns(geo) {
|
|
33834
|
+
if (!geo || !utils.isObject(geo.columns)) return [];
|
|
33835
|
+
return Object.keys(geo.columns);
|
|
33836
|
+
}
|
|
33837
|
+
|
|
33838
|
+
function getGeoParquetGeometryColumn(rows, geo) {
|
|
33839
|
+
var row = rows && rows.length > 0 && utils.isObject(rows[0]) ? rows[0] : null;
|
|
33840
|
+
var keys = row ? Object.keys(row) : [];
|
|
33841
|
+
var candidate;
|
|
33842
|
+
if (geo && utils.isObject(geo.columns)) {
|
|
33843
|
+
var wkbColumns = getWkbGeometryColumns(geo);
|
|
33844
|
+
candidate = geo.primary_column;
|
|
33845
|
+
if (candidate && wkbColumns.indexOf(candidate) > -1 && keys.indexOf(candidate) > -1) {
|
|
33846
|
+
return candidate;
|
|
33847
|
+
}
|
|
33848
|
+
candidate = wkbColumns.find(function(name) {
|
|
33849
|
+
return keys.indexOf(name) > -1;
|
|
33850
|
+
});
|
|
33851
|
+
if (candidate) return candidate;
|
|
33852
|
+
return null;
|
|
33853
|
+
}
|
|
33854
|
+
if (keys.indexOf('geometry') > -1) {
|
|
33855
|
+
return 'geometry';
|
|
33856
|
+
}
|
|
33857
|
+
candidate = keys.find(function(key) {
|
|
33858
|
+
return looksLikeGeoJSONGeometry(row[key]);
|
|
33859
|
+
});
|
|
33860
|
+
return candidate || null;
|
|
33861
|
+
}
|
|
33862
|
+
|
|
33863
|
+
function getWkbGeometryColumns(geo) {
|
|
33864
|
+
if (!geo || !utils.isObject(geo.columns)) return [];
|
|
33865
|
+
return Object.keys(geo.columns).filter(function(name) {
|
|
33866
|
+
var encoding = geo.columns[name] && geo.columns[name].encoding;
|
|
33867
|
+
return utils.isString(encoding) && encoding.toUpperCase() == 'WKB';
|
|
33868
|
+
});
|
|
33869
|
+
}
|
|
33870
|
+
|
|
33871
|
+
function hasUnsupportedGeometryEncoding(geo) {
|
|
33872
|
+
if (!geo || !utils.isObject(geo.columns)) return false;
|
|
33873
|
+
var columnNames = Object.keys(geo.columns);
|
|
33874
|
+
if (columnNames.length === 0) return false;
|
|
33875
|
+
return getWkbGeometryColumns(geo).length === 0;
|
|
33876
|
+
}
|
|
33877
|
+
|
|
33878
|
+
function looksLikeGeoJSONGeometry(obj) {
|
|
33879
|
+
return !!(obj && utils.isObject(obj) && utils.isString(obj.type));
|
|
33880
|
+
}
|
|
33881
|
+
|
|
33882
|
+
function parseGeoParquetMetadata(metadata) {
|
|
33883
|
+
var kv = getParquetKeyValueMetadata(metadata);
|
|
33884
|
+
var entry = kv.find(function(item) {
|
|
33885
|
+
return getMetadataKey(item) == 'geo';
|
|
33886
|
+
});
|
|
33887
|
+
var value = entry ? getMetadataValue(entry) : null;
|
|
33888
|
+
if (!value) return null;
|
|
33889
|
+
if (utils.isObject(value)) return value;
|
|
33890
|
+
try {
|
|
33891
|
+
return JSON.parse(normalizeMetadataString(value));
|
|
33892
|
+
} catch (e) {
|
|
33893
|
+
warnOnce('Unable to parse GeoParquet metadata');
|
|
33894
|
+
return null;
|
|
33895
|
+
}
|
|
33896
|
+
}
|
|
33897
|
+
|
|
33898
|
+
function getParquetKeyValueMetadata(metadata) {
|
|
33899
|
+
if (!metadata) return [];
|
|
33900
|
+
if (Array.isArray(metadata.key_value_metadata)) {
|
|
33901
|
+
return metadata.key_value_metadata;
|
|
33902
|
+
}
|
|
33903
|
+
if (Array.isArray(metadata.keyValueMetadata)) {
|
|
33904
|
+
return metadata.keyValueMetadata;
|
|
33905
|
+
}
|
|
33906
|
+
if (utils.isObject(metadata.metadata)) {
|
|
33907
|
+
return Object.keys(metadata.metadata).map(function(key) {
|
|
33908
|
+
return {key: key, value: metadata.metadata[key]};
|
|
33909
|
+
});
|
|
33910
|
+
}
|
|
33911
|
+
return [];
|
|
33912
|
+
}
|
|
33913
|
+
|
|
33914
|
+
function getMetadataKey(entry) {
|
|
33915
|
+
if (!entry || !utils.isObject(entry)) return null;
|
|
33916
|
+
return entry.key || entry.name || null;
|
|
33917
|
+
}
|
|
33918
|
+
|
|
33919
|
+
function getMetadataValue(entry) {
|
|
33920
|
+
if (!entry || !utils.isObject(entry)) return null;
|
|
33921
|
+
return entry.value ?? entry.val ?? null;
|
|
33922
|
+
}
|
|
33923
|
+
|
|
33924
|
+
function normalizeMetadataString(value) {
|
|
33925
|
+
if (utils.isString(value)) return value;
|
|
33926
|
+
if (value instanceof Uint8Array) {
|
|
33927
|
+
return new TextDecoder('utf-8').decode(value);
|
|
33928
|
+
}
|
|
33929
|
+
if (typeof Buffer == 'function' && Buffer.isBuffer(value)) {
|
|
33930
|
+
return value.toString('utf-8');
|
|
33931
|
+
}
|
|
33932
|
+
return String(value);
|
|
33933
|
+
}
|
|
33934
|
+
|
|
33935
|
+
function getGeoParquetCrs(geo, geometryColumn) {
|
|
33936
|
+
if (!geo || !utils.isObject(geo.columns)) return null;
|
|
33937
|
+
if (geometryColumn && geo.columns[geometryColumn]) {
|
|
33938
|
+
return geo.columns[geometryColumn].crs ?? null;
|
|
33939
|
+
}
|
|
33940
|
+
var cols = Object.keys(geo.columns);
|
|
33941
|
+
for (var i = 0; i < cols.length; i++) {
|
|
33942
|
+
var crs = geo.columns[cols[i]].crs;
|
|
33943
|
+
if (crs) return crs;
|
|
33944
|
+
}
|
|
33945
|
+
return null;
|
|
33946
|
+
}
|
|
33947
|
+
|
|
33948
|
+
function getGeoParquetAuthority(crs) {
|
|
33949
|
+
var match = findPrimaryAuthorityId(crs);
|
|
33950
|
+
if (!match) return null;
|
|
33951
|
+
var org = String(match.authority || '').toUpperCase();
|
|
33952
|
+
var code = Number(match.code);
|
|
33953
|
+
if (!org || !Number.isFinite(code)) return null;
|
|
33954
|
+
if (org != 'EPSG' && org != 'ESRI') return null;
|
|
33955
|
+
return {
|
|
33956
|
+
org: org,
|
|
33957
|
+
code: Math.round(code)
|
|
33958
|
+
};
|
|
33959
|
+
}
|
|
33960
|
+
|
|
33961
|
+
async function resolveGeoParquetCrsString(crs) {
|
|
33962
|
+
var candidates = getGeoParquetCrsStrings(crs);
|
|
33963
|
+
for (var i = 0; i < candidates.length; i++) {
|
|
33964
|
+
try {
|
|
33965
|
+
parseCrsString$1(candidates[i]);
|
|
33966
|
+
await initProjLibrary({crs: candidates[i]});
|
|
33967
|
+
return candidates[i];
|
|
33968
|
+
} catch (e) {
|
|
33969
|
+
// Keep trying candidates; if none initialize, caller will warn.
|
|
33970
|
+
}
|
|
33971
|
+
}
|
|
33972
|
+
return null;
|
|
33973
|
+
}
|
|
33974
|
+
|
|
33975
|
+
function getGeoParquetCrsStrings(crs) {
|
|
33976
|
+
var strings = [];
|
|
33977
|
+
var authority = getGeoParquetAuthority(crs);
|
|
33978
|
+
if (authority) {
|
|
33979
|
+
strings.push(authority.org.toLowerCase() + ':' + authority.code);
|
|
33980
|
+
}
|
|
33981
|
+
var proj4 = convertProjjsonToProj4(crs);
|
|
33982
|
+
if (proj4 && strings.indexOf(proj4) == -1) {
|
|
33983
|
+
strings.push(proj4);
|
|
33984
|
+
}
|
|
33985
|
+
return strings;
|
|
33986
|
+
}
|
|
33987
|
+
|
|
33988
|
+
function convertProjjsonToProj4(crs) {
|
|
33989
|
+
var converter = getProjjsonToProj4Converter();
|
|
33990
|
+
if (!converter) return null;
|
|
33991
|
+
try {
|
|
33992
|
+
return converter(crs);
|
|
33993
|
+
} catch (e) {
|
|
33994
|
+
return null;
|
|
33995
|
+
}
|
|
33996
|
+
}
|
|
33997
|
+
|
|
33998
|
+
function getProjjsonToProj4Converter() {
|
|
33999
|
+
if (!mproj) {
|
|
34000
|
+
mproj = require$1('mproj');
|
|
34001
|
+
}
|
|
34002
|
+
if (mproj && typeof mproj.projjson_to_proj4 == 'function') {
|
|
34003
|
+
return mproj.projjson_to_proj4;
|
|
34004
|
+
}
|
|
34005
|
+
if (mproj && mproj.internal && typeof mproj.internal.projjson_to_proj4 == 'function') {
|
|
34006
|
+
return mproj.internal.projjson_to_proj4;
|
|
34007
|
+
}
|
|
34008
|
+
return null;
|
|
34009
|
+
}
|
|
34010
|
+
|
|
34011
|
+
function findPrimaryAuthorityId(crs) {
|
|
34012
|
+
if (!crs || !utils.isObject(crs)) return null;
|
|
34013
|
+
if (utils.isString(crs)) {
|
|
34014
|
+
return parseAuthorityString(crs);
|
|
34015
|
+
}
|
|
34016
|
+
var match = parseAuthorityObject(crs.id);
|
|
34017
|
+
if (match) return match;
|
|
34018
|
+
if (crs.base_crs && utils.isObject(crs.base_crs)) {
|
|
34019
|
+
match = parseAuthorityObject(crs.base_crs.id);
|
|
34020
|
+
if (match) return match;
|
|
34021
|
+
}
|
|
34022
|
+
return null;
|
|
34023
|
+
}
|
|
34024
|
+
|
|
34025
|
+
function parseAuthorityObject(id) {
|
|
34026
|
+
if (!id || !utils.isObject(id)) return null;
|
|
34027
|
+
if (id.authority === undefined || id.code === undefined) return null;
|
|
34028
|
+
return {
|
|
34029
|
+
authority: id.authority,
|
|
34030
|
+
code: id.code
|
|
34031
|
+
};
|
|
34032
|
+
}
|
|
34033
|
+
|
|
34034
|
+
function parseAuthorityString(str) {
|
|
34035
|
+
var match = /^([A-Za-z]+)\s*:\s*([0-9]+)$/.exec(str);
|
|
34036
|
+
if (!match) return null;
|
|
34037
|
+
return {
|
|
34038
|
+
authority: match[1],
|
|
34039
|
+
code: Number(match[2])
|
|
34040
|
+
};
|
|
34041
|
+
}
|
|
34042
|
+
|
|
33137
34043
|
var INHERITED_STYLE_KEYS = [
|
|
33138
34044
|
'fill', 'fill-opacity',
|
|
33139
34045
|
'stroke', 'stroke-width', 'stroke-opacity', 'stroke-dasharray',
|
|
@@ -33159,6 +34065,7 @@ ${svg}
|
|
|
33159
34065
|
var Parser = typeof DOMParser == 'undefined' ? require$1('@xmldom/xmldom').DOMParser : DOMParser;
|
|
33160
34066
|
var doc = new Parser().parseFromString(str, 'text/xml');
|
|
33161
34067
|
var root = doc && doc.documentElement;
|
|
34068
|
+
var geometadata = parseSVGGeometadata(root, str);
|
|
33162
34069
|
var groups = getTopLevelLayerGroups(root);
|
|
33163
34070
|
var layerData = [];
|
|
33164
34071
|
var datasets = [];
|
|
@@ -33175,7 +34082,11 @@ ${svg}
|
|
|
33175
34082
|
});
|
|
33176
34083
|
});
|
|
33177
34084
|
|
|
33178
|
-
|
|
34085
|
+
if (geometadata && geometadata.bbox && geometadata.viewBox) {
|
|
34086
|
+
remapCoordinatesFromSVGToMap(layerData, geometadata.viewBox, geometadata.bbox);
|
|
34087
|
+
} else {
|
|
34088
|
+
flipYCoordinates(layerData);
|
|
34089
|
+
}
|
|
33179
34090
|
|
|
33180
34091
|
layerData.forEach(function(layer) {
|
|
33181
34092
|
datasets.push(importLayerFeatures(layer.name, layer.features, opts));
|
|
@@ -33185,9 +34096,237 @@ ${svg}
|
|
|
33185
34096
|
return {layers: [], info: {}};
|
|
33186
34097
|
}
|
|
33187
34098
|
if (datasets.length === 1) {
|
|
33188
|
-
return datasets[0];
|
|
34099
|
+
return applySVGGeometadata(datasets[0], geometadata);
|
|
33189
34100
|
}
|
|
33190
|
-
return mergeDatasets(datasets);
|
|
34101
|
+
return applySVGGeometadata(mergeDatasets(datasets), geometadata);
|
|
34102
|
+
}
|
|
34103
|
+
|
|
34104
|
+
function applySVGGeometadata(dataset, geometadata) {
|
|
34105
|
+
if (geometadata && geometadata.crs) {
|
|
34106
|
+
setDatasetCrsInfo(dataset, getCrsInfo(geometadata.crs));
|
|
34107
|
+
}
|
|
34108
|
+
return dataset;
|
|
34109
|
+
}
|
|
34110
|
+
|
|
34111
|
+
function parseSVGGeometadata(root, svgText) {
|
|
34112
|
+
var json = findMetadataJSONString(root, svgText);
|
|
34113
|
+
var obj;
|
|
34114
|
+
var metadataViewport = getMetadataViewportRect(root);
|
|
34115
|
+
if (!json) return null;
|
|
34116
|
+
obj = parseMetadataJSONObject(json);
|
|
34117
|
+
if (!obj) return null;
|
|
34118
|
+
return {
|
|
34119
|
+
crs: normalizeMetadataCRS(obj.crs),
|
|
34120
|
+
bbox: normalizeMetadataBBox(obj.bbox),
|
|
34121
|
+
viewBox: metadataViewport || parseSVGViewBox(root && root.getAttribute && root.getAttribute('viewBox'))
|
|
34122
|
+
};
|
|
34123
|
+
}
|
|
34124
|
+
|
|
34125
|
+
function findMetadataJSONString(root, svgText) {
|
|
34126
|
+
var text = getMetadataTagText(root) || getHiddenMetadataText(root);
|
|
34127
|
+
if (!text && svgText) {
|
|
34128
|
+
text = extractHiddenMetadataFromSource(svgText);
|
|
34129
|
+
}
|
|
34130
|
+
return normalizeMetadataJSONText(text);
|
|
34131
|
+
}
|
|
34132
|
+
|
|
34133
|
+
function getMetadataTagText(root) {
|
|
34134
|
+
var nodes = getElementChildren(root);
|
|
34135
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
34136
|
+
if (getTagName(nodes[i]) == 'metadata') {
|
|
34137
|
+
return nodes[i].textContent || '';
|
|
34138
|
+
}
|
|
34139
|
+
}
|
|
34140
|
+
return null;
|
|
34141
|
+
}
|
|
34142
|
+
|
|
34143
|
+
function getHiddenMetadataText(root) {
|
|
34144
|
+
var node = getMetadataGroupNode(root);
|
|
34145
|
+
if (node) {
|
|
34146
|
+
return node.textContent || '';
|
|
34147
|
+
}
|
|
34148
|
+
return null;
|
|
34149
|
+
}
|
|
34150
|
+
|
|
34151
|
+
function getMetadataGroupNode(root) {
|
|
34152
|
+
var nodes = getElementChildren(root);
|
|
34153
|
+
var i, node;
|
|
34154
|
+
for (i = 0; i < nodes.length; i++) {
|
|
34155
|
+
node = nodes[i];
|
|
34156
|
+
if (getTagName(node) == 'g' && node.getAttribute && node.getAttribute('id') == 'mapshaper-metadata') {
|
|
34157
|
+
return node;
|
|
34158
|
+
}
|
|
34159
|
+
}
|
|
34160
|
+
return null;
|
|
34161
|
+
}
|
|
34162
|
+
|
|
34163
|
+
function getMetadataViewportRect(root) {
|
|
34164
|
+
var node = getMetadataGroupNode(root);
|
|
34165
|
+
var children, i, rect;
|
|
34166
|
+
if (!node) return null;
|
|
34167
|
+
children = getElementChildren(node);
|
|
34168
|
+
for (i = 0; i < children.length; i++) {
|
|
34169
|
+
if (getTagName(children[i]) == 'rect') {
|
|
34170
|
+
rect = parseMetadataRectNode(children[i]);
|
|
34171
|
+
if (rect) return rect;
|
|
34172
|
+
}
|
|
34173
|
+
}
|
|
34174
|
+
return null;
|
|
34175
|
+
}
|
|
34176
|
+
|
|
34177
|
+
function parseMetadataRectNode(node) {
|
|
34178
|
+
var x = parseNumber(node.getAttribute('x')) || 0;
|
|
34179
|
+
var y = parseNumber(node.getAttribute('y')) || 0;
|
|
34180
|
+
var width = parseNumber(node.getAttribute('width'));
|
|
34181
|
+
var height = parseNumber(node.getAttribute('height'));
|
|
34182
|
+
var pts, i, p;
|
|
34183
|
+
var xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity;
|
|
34184
|
+
if (!isFiniteNumber(width) || !isFiniteNumber(height) || width === 0 || height === 0) {
|
|
34185
|
+
return null;
|
|
34186
|
+
}
|
|
34187
|
+
pts = [
|
|
34188
|
+
[x, y],
|
|
34189
|
+
[x + width, y],
|
|
34190
|
+
[x, y + height],
|
|
34191
|
+
[x + width, y + height]
|
|
34192
|
+
];
|
|
34193
|
+
for (i = 0; i < pts.length; i++) {
|
|
34194
|
+
p = applyNodeTransformChain(node, pts[i]);
|
|
34195
|
+
xmin = Math.min(xmin, p[0]);
|
|
34196
|
+
ymin = Math.min(ymin, p[1]);
|
|
34197
|
+
xmax = Math.max(xmax, p[0]);
|
|
34198
|
+
ymax = Math.max(ymax, p[1]);
|
|
34199
|
+
}
|
|
34200
|
+
if (!isFiniteNumber(xmin) || !isFiniteNumber(ymin) || !isFiniteNumber(xmax) || !isFiniteNumber(ymax)) {
|
|
34201
|
+
return null;
|
|
34202
|
+
}
|
|
34203
|
+
return [xmin, ymin, xmax - xmin, ymax - ymin];
|
|
34204
|
+
}
|
|
34205
|
+
|
|
34206
|
+
function applyNodeTransformChain(node, point) {
|
|
34207
|
+
var chain = [];
|
|
34208
|
+
var p = [point[0], point[1]];
|
|
34209
|
+
var i;
|
|
34210
|
+
while (node && node.nodeType == 1) {
|
|
34211
|
+
chain.unshift(node);
|
|
34212
|
+
node = node.parentNode;
|
|
34213
|
+
}
|
|
34214
|
+
for (i = 0; i < chain.length; i++) {
|
|
34215
|
+
p = applyTransformString(chain[i].getAttribute && chain[i].getAttribute('transform'), p);
|
|
34216
|
+
}
|
|
34217
|
+
return p;
|
|
34218
|
+
}
|
|
34219
|
+
|
|
34220
|
+
function applyTransformString(str, point) {
|
|
34221
|
+
var re = /([a-z]+)\s*\(([^)]*)\)/ig;
|
|
34222
|
+
var m = null;
|
|
34223
|
+
var p = [point[0], point[1]];
|
|
34224
|
+
while ((m = re.exec(String(str || '')))) {
|
|
34225
|
+
p = applyTransformCommand(m[1].toLowerCase(), parseTransformNumbers(m[2]), p);
|
|
34226
|
+
}
|
|
34227
|
+
return p;
|
|
34228
|
+
}
|
|
34229
|
+
|
|
34230
|
+
function parseTransformNumbers(str) {
|
|
34231
|
+
return String(str || '')
|
|
34232
|
+
.trim()
|
|
34233
|
+
.split(/[\s,]+/)
|
|
34234
|
+
.filter(Boolean)
|
|
34235
|
+
.map(Number)
|
|
34236
|
+
.filter(function(v) { return isFiniteNumber(v); });
|
|
34237
|
+
}
|
|
34238
|
+
|
|
34239
|
+
function applyTransformCommand(cmd, nums, point) {
|
|
34240
|
+
var x = point[0], y = point[1];
|
|
34241
|
+
var sx, sy;
|
|
34242
|
+
if (cmd == 'translate') {
|
|
34243
|
+
return [x + (nums[0] || 0), y + (nums.length > 1 ? nums[1] : 0)];
|
|
34244
|
+
}
|
|
34245
|
+
if (cmd == 'scale') {
|
|
34246
|
+
sx = nums.length > 0 ? nums[0] : 1;
|
|
34247
|
+
sy = nums.length > 1 ? nums[1] : sx;
|
|
34248
|
+
return [x * sx, y * sy];
|
|
34249
|
+
}
|
|
34250
|
+
if (cmd == 'matrix' && nums.length >= 6) {
|
|
34251
|
+
return [
|
|
34252
|
+
nums[0] * x + nums[2] * y + nums[4],
|
|
34253
|
+
nums[1] * x + nums[3] * y + nums[5]
|
|
34254
|
+
];
|
|
34255
|
+
}
|
|
34256
|
+
return point;
|
|
34257
|
+
}
|
|
34258
|
+
|
|
34259
|
+
function extractHiddenMetadataFromSource(str) {
|
|
34260
|
+
var m = String(str || '').match(/<g[^>]*\bid\s*=\s*["']mapshaper-metadata["'][^>]*>([\s\S]*?)<\/g>/i);
|
|
34261
|
+
if (!m) return null;
|
|
34262
|
+
return stripMarkupTags(m[1]);
|
|
34263
|
+
}
|
|
34264
|
+
|
|
34265
|
+
function stripMarkupTags(str) {
|
|
34266
|
+
return String(str || '').replace(/<[^>]*>/g, '');
|
|
34267
|
+
}
|
|
34268
|
+
|
|
34269
|
+
function normalizeMetadataJSONText(str) {
|
|
34270
|
+
if (!str) return null;
|
|
34271
|
+
return decodeHTMLEntities(stripMarkupTags(String(str))).trim();
|
|
34272
|
+
}
|
|
34273
|
+
|
|
34274
|
+
function decodeHTMLEntities(str) {
|
|
34275
|
+
return String(str || '')
|
|
34276
|
+
.replace(/"|"/gi, '"')
|
|
34277
|
+
.replace(/'|'/gi, "'")
|
|
34278
|
+
.replace(/&|&/gi, '&')
|
|
34279
|
+
.replace(/<|</gi, '<')
|
|
34280
|
+
.replace(/>|>/gi, '>')
|
|
34281
|
+
.replace(/"/g, '"')
|
|
34282
|
+
.replace(/'/g, "'")
|
|
34283
|
+
.replace(/&/g, '&')
|
|
34284
|
+
.replace(/</g, '<')
|
|
34285
|
+
.replace(/>/g, '>');
|
|
34286
|
+
}
|
|
34287
|
+
|
|
34288
|
+
function parseMetadataJSONObject(text) {
|
|
34289
|
+
try {
|
|
34290
|
+
return JSON.parse(text);
|
|
34291
|
+
} catch (e) {
|
|
34292
|
+
return null;
|
|
34293
|
+
}
|
|
34294
|
+
}
|
|
34295
|
+
|
|
34296
|
+
function normalizeMetadataCRS(crs) {
|
|
34297
|
+
return typeof crs == 'string' && crs.trim() ? crs.trim() : null;
|
|
34298
|
+
}
|
|
34299
|
+
|
|
34300
|
+
function normalizeMetadataBBox(bbox) {
|
|
34301
|
+
if (!Array.isArray(bbox) || bbox.length != 4) return null;
|
|
34302
|
+
var out = bbox.map(function(v) { return Number(v); });
|
|
34303
|
+
return out.every(isFiniteNumber) ? out : null;
|
|
34304
|
+
}
|
|
34305
|
+
|
|
34306
|
+
function parseSVGViewBox(str) {
|
|
34307
|
+
var parts = String(str || '').trim().split(/[\s,]+/).map(Number);
|
|
34308
|
+
if (parts.length != 4 || !parts.every(isFiniteNumber) || parts[2] === 0 || parts[3] === 0) {
|
|
34309
|
+
return null;
|
|
34310
|
+
}
|
|
34311
|
+
return parts;
|
|
34312
|
+
}
|
|
34313
|
+
|
|
34314
|
+
function remapCoordinatesFromSVGToMap(layerData, viewBox, bbox) {
|
|
34315
|
+
var vx = viewBox[0], vy = viewBox[1], vw = viewBox[2], vh = viewBox[3];
|
|
34316
|
+
var minX = bbox[0], minY = bbox[1], maxX = bbox[2], maxY = bbox[3];
|
|
34317
|
+
var scaleX = (maxX - minX) / vw;
|
|
34318
|
+
var scaleY = (maxY - minY) / vh;
|
|
34319
|
+
|
|
34320
|
+
layerData.forEach(function(layer) {
|
|
34321
|
+
layer.features.forEach(function(feature) {
|
|
34322
|
+
forEachGeometryCoordinate(feature && feature.geometry, function(coord) {
|
|
34323
|
+
var sx = coord[0];
|
|
34324
|
+
var sy = coord[1];
|
|
34325
|
+
coord[0] = minX + (sx - vx) * scaleX;
|
|
34326
|
+
coord[1] = maxY - (sy - vy) * scaleY;
|
|
34327
|
+
});
|
|
34328
|
+
});
|
|
34329
|
+
});
|
|
33191
34330
|
}
|
|
33192
34331
|
|
|
33193
34332
|
function importLayerFeatures(layerName, features, opts) {
|
|
@@ -33215,6 +34354,7 @@ ${svg}
|
|
|
33215
34354
|
childNodes.forEach(function(node) {
|
|
33216
34355
|
var tag = getTagName(node);
|
|
33217
34356
|
if (tag == 'defs') return;
|
|
34357
|
+
if (tag == 'g' && node.getAttribute && node.getAttribute('id') == 'mapshaper-metadata') return;
|
|
33218
34358
|
if (tag == 'g') {
|
|
33219
34359
|
groups.push({
|
|
33220
34360
|
node: node,
|
|
@@ -33851,6 +34991,8 @@ ${svg}
|
|
|
33851
34991
|
stop$1("FlatGeobuf import requires async import path");
|
|
33852
34992
|
} else if (obj.gpkg) {
|
|
33853
34993
|
stop$1("GeoPackage import requires async import path");
|
|
34994
|
+
} else if (obj.parquet) {
|
|
34995
|
+
stop$1("GeoParquet import requires async import path");
|
|
33854
34996
|
}
|
|
33855
34997
|
|
|
33856
34998
|
return finalizeImportedDataset(dataset, dataFmt, data, opts);
|
|
@@ -33867,6 +35009,10 @@ ${svg}
|
|
|
33867
35009
|
dataFmt = 'geopackage';
|
|
33868
35010
|
data = obj.gpkg;
|
|
33869
35011
|
dataset = await importGeoPackage(data, opts);
|
|
35012
|
+
} else if (obj.parquet) {
|
|
35013
|
+
dataFmt = 'geoparquet';
|
|
35014
|
+
data = obj.parquet;
|
|
35015
|
+
dataset = await importGeoParquet(data, opts);
|
|
33870
35016
|
} else {
|
|
33871
35017
|
return importContent(obj, opts);
|
|
33872
35018
|
}
|
|
@@ -34358,7 +35504,7 @@ ${svg}
|
|
|
34358
35504
|
if (fileType == 'shp' && !input.dbf) {
|
|
34359
35505
|
message(utils.format("[%s] .dbf file is missing - shapes imported without attribute data.", path));
|
|
34360
35506
|
}
|
|
34361
|
-
return fileType == 'gpkg' || fileType == 'fgb' ? importContentAsync(input, opts) : importContent(input, opts);
|
|
35507
|
+
return fileType == 'gpkg' || fileType == 'fgb' || fileType == 'parquet' ? importContentAsync(input, opts) : importContent(input, opts);
|
|
34362
35508
|
}
|
|
34363
35509
|
|
|
34364
35510
|
// Import multiple files to a single dataset
|
|
@@ -41265,7 +42411,7 @@ ${svg}
|
|
|
41265
42411
|
// @type: 'clip' or 'erase'
|
|
41266
42412
|
function clipLayers(targetLayers, clipSrc, targetDataset, type, opts) {
|
|
41267
42413
|
profileStart('clipLayers');
|
|
41268
|
-
opts = opts || {
|
|
42414
|
+
opts = opts || {no_cleanup: true}; // TODO: update testing functions
|
|
41269
42415
|
var usingPathClip = utils.some(targetLayers, layerHasPaths);
|
|
41270
42416
|
var mergedDataset, clipLyr, nodes, result;
|
|
41271
42417
|
var clipDataset = normalizeOverlaySource(clipSrc, targetDataset, opts);
|
|
@@ -48147,17 +49293,62 @@ ${svg}
|
|
|
48147
49293
|
});
|
|
48148
49294
|
}
|
|
48149
49295
|
|
|
49296
|
+
function parseWKTPoint(val) {
|
|
49297
|
+
if (!utils.isString(val)) return null;
|
|
49298
|
+
// Support 2D POINT WKT, case-insensitive, with optional Z/M tokens.
|
|
49299
|
+
// Examples:
|
|
49300
|
+
// POINT (1 2)
|
|
49301
|
+
// point(1 2)
|
|
49302
|
+
// POINT Z (1 2 3)
|
|
49303
|
+
// POINT M (1 2 3)
|
|
49304
|
+
// POINT ZM (1 2 3 4)
|
|
49305
|
+
var m = /^\s*POINT(?:\s+Z(?:M)?|\s+M)?\s*\(\s*([^\s,]+)\s+([^\s,]+)(?:\s+[^)]*)?\)\s*$/i.exec(val);
|
|
49306
|
+
if (!m) return null;
|
|
49307
|
+
var x = coordinateFromValue(m[1]);
|
|
49308
|
+
var y = coordinateFromValue(m[2]);
|
|
49309
|
+
if (isNaN(x) || isNaN(y)) return null;
|
|
49310
|
+
return [x, y];
|
|
49311
|
+
}
|
|
49312
|
+
|
|
49313
|
+
function findWKTField(records, fields) {
|
|
49314
|
+
var sampleSize = Math.min(records.length, 50);
|
|
49315
|
+
return utils.find(fields, function(name) {
|
|
49316
|
+
var seen = 0;
|
|
49317
|
+
var matches = 0;
|
|
49318
|
+
for (var i = 0; i < sampleSize; i++) {
|
|
49319
|
+
var rec = records[i];
|
|
49320
|
+
if (!rec) continue;
|
|
49321
|
+
var val = rec[name];
|
|
49322
|
+
if (!utils.isString(val) || val.trim() === '') continue;
|
|
49323
|
+
seen++;
|
|
49324
|
+
if (parseWKTPoint(val)) matches++;
|
|
49325
|
+
}
|
|
49326
|
+
// Require at least one non-empty sample and majority parseable as POINT.
|
|
49327
|
+
return seen > 0 && matches / seen >= 0.6;
|
|
49328
|
+
});
|
|
49329
|
+
}
|
|
49330
|
+
|
|
48150
49331
|
function pointsFromDataTableAuto(data) {
|
|
48151
49332
|
var fields = data ? data.getFields() : [];
|
|
49333
|
+
var records = data ? data.getRecords() : [];
|
|
48152
49334
|
var opts = {
|
|
48153
49335
|
x: findXField(fields),
|
|
48154
49336
|
y: findYField(fields)
|
|
48155
49337
|
};
|
|
49338
|
+
if (!opts.x || !opts.y) {
|
|
49339
|
+
opts.wkt = findWKTField(records, fields);
|
|
49340
|
+
}
|
|
48156
49341
|
return pointsFromDataTable(data, opts);
|
|
48157
49342
|
}
|
|
48158
49343
|
|
|
48159
49344
|
function pointsFromDataTable(data, opts) {
|
|
48160
49345
|
if (!data) stop$1("Layer is missing a data table");
|
|
49346
|
+
if (opts.wkt && data.fieldExists(opts.wkt)) {
|
|
49347
|
+
return data.getRecords().map(function(rec) {
|
|
49348
|
+
var p = parseWKTPoint(rec[opts.wkt]);
|
|
49349
|
+
return p ? [p] : null;
|
|
49350
|
+
});
|
|
49351
|
+
}
|
|
48161
49352
|
if (!opts.x || !opts.y || !data.fieldExists(opts.x) || !data.fieldExists(opts.y)) {
|
|
48162
49353
|
stop$1("Missing x,y data fields");
|
|
48163
49354
|
}
|
|
@@ -48175,8 +49366,10 @@ ${svg}
|
|
|
48175
49366
|
var Points = /*#__PURE__*/Object.freeze({
|
|
48176
49367
|
__proto__: null,
|
|
48177
49368
|
coordinateFromValue: coordinateFromValue,
|
|
49369
|
+
findWKTField: findWKTField,
|
|
48178
49370
|
findXField: findXField,
|
|
48179
49371
|
findYField: findYField,
|
|
49372
|
+
parseWKTPoint: parseWKTPoint,
|
|
48180
49373
|
pointsFromPolygons: pointsFromPolygons
|
|
48181
49374
|
});
|
|
48182
49375
|
|
|
@@ -53074,7 +54267,7 @@ ${svg}
|
|
|
53074
54267
|
});
|
|
53075
54268
|
}
|
|
53076
54269
|
|
|
53077
|
-
var version = "0.7.
|
|
54270
|
+
var version = "0.7.8";
|
|
53078
54271
|
|
|
53079
54272
|
// Parse command line args into commands and run them
|
|
53080
54273
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|