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/www/mapshaper.js CHANGED
@@ -4879,7 +4879,7 @@
4879
4879
  this.ty -= cy * (sy - 1);
4880
4880
  };
4881
4881
 
4882
- var mproj$1 = require$1('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$1);
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$1.pj_init(params.proj)
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$1.pj_fwd_deg({lam: origin[0], phi: origin[1]}, P);
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$1.pj_fwd(lp, frame.crs);
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 inferGeometryType(t){let r;for(let f of t){if(r===GeometryType.Unknown)break;let t=f.getGeometry?toGeometryType(f.getGeometry().getType()):toGeometryType(f.geometry.type);void 0===r?r=t:r!==t&&(r=GeometryType.Unknown);}if(void 0===r)throw Error("Could not infer geometry type for collection of features.");return r}
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 content = serialize(geojson);
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 an EPSG code for this dataset). Downstream tools may misinterpret the coordinates or refuse to load the file.');
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
- // Try several strategies to derive an EPSG code for the dataset. Returns
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
- // EPSG code could be found. We don't write WKT-only CRSes -- mapshaper
24840
- // can't reliably round-trip them and many readers ignore the WKT field.
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 || !crs.code) return null;
25098
+ if (!crs) return null;
24890
25099
  var code = +crs.code;
24891
- if (!Number.isFinite(code) || code <= 0) return null;
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
- .option('metadata', {
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 (type == 'geojson') { // consider only for larger files
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 && crs.org && crs.code) {
32624
- dataset.info.crs_string = crs.org.toLowerCase() + ':' + crs.code;
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 (crs.org || !Number.isFinite(code)) return crs;
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
- flipYCoordinates(layerData);
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(/&#34;|&#x22;/gi, '"')
34277
+ .replace(/&#39;|&#x27;/gi, "'")
34278
+ .replace(/&#38;|&#x26;/gi, '&')
34279
+ .replace(/&#60;|&#x3c;/gi, '<')
34280
+ .replace(/&#62;|&#x3e;/gi, '>')
34281
+ .replace(/&quot;/g, '"')
34282
+ .replace(/&apos;/g, "'")
34283
+ .replace(/&amp;/g, '&')
34284
+ .replace(/&lt;/g, '<')
34285
+ .replace(/&gt;/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 || {no_fcleanup: true}; // TODO: update testing functions
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.6";
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.