mapshaper 0.6.33 → 0.6.35

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.33";
3
+ var VERSION = "0.6.35";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -12719,7 +12719,7 @@
12719
12719
  }
12720
12720
  var sliverControl = opts.sliver_control >= 0 ? opts.sliver_control : 0; // 0 is default
12721
12721
  var crs = getDatasetCRS(dataset);
12722
- var threshold = areaArg ?
12722
+ var threshold = areaArg && areaArg != 'auto' ?
12723
12723
  convertAreaParam(areaArg, crs) :
12724
12724
  getDefaultSliverThreshold(lyr, dataset.arcs);
12725
12725
  var filter = sliverControl > 0 ?
@@ -16653,7 +16653,8 @@
16653
16653
  overlap_rule: opts.overlap_rule
16654
16654
  };
16655
16655
  var mosaicIndex = new MosaicIndex(lyr, nodes, mosaicOpts);
16656
- var fillGaps = !opts.allow_overlaps; // gap fill doesn't work yet with overlapping shapes
16656
+ // gap fill doesn't work yet with overlapping shapes
16657
+ var fillGaps = !opts.allow_overlaps && (opts.sliver_control || opts.gap_fill_area);
16657
16658
  var cleanupData, filterData;
16658
16659
  if (fillGaps) {
16659
16660
  var sliverOpts = utils.extend({sliver_control: 1}, opts);
@@ -16935,6 +16936,7 @@
16935
16936
 
16936
16937
  function cleanPolygonLayerGeometry(lyr, dataset, opts) {
16937
16938
  // clean polygons by apply the 'dissolve2' function to each feature
16939
+ opts = Object.assign({gap_fill_area: 'auto'}, opts);
16938
16940
  var groups = lyr.shapes.map(function(shp, i) {
16939
16941
  return [i];
16940
16942
  });
@@ -18213,6 +18215,7 @@
18213
18215
  dy: 'measure',
18214
18216
  fill: 'color',
18215
18217
  'fill-pattern': 'pattern',
18218
+ 'fill-effect': null, // todo: validate effect names
18216
18219
  'font-family': null,
18217
18220
  'font-size': null,
18218
18221
  'font-style': null,
@@ -18261,7 +18264,7 @@
18261
18264
  var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity,vector-effect'.split(',');
18262
18265
 
18263
18266
  var propertiesBySymbolType = {
18264
- polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
18267
+ polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern', 'fill-effect')),
18265
18268
  polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit')),
18266
18269
  point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
18267
18270
  label: utils.arrayToIndex(commonProperties.concat(
@@ -19146,6 +19149,9 @@
19146
19149
  if (obj.tag == 'path' && obj.properties['fill-pattern']) {
19147
19150
  convertFillPattern(obj.properties, defs);
19148
19151
  }
19152
+ if (obj.tag == 'path' && obj.properties['fill-effect'] == 'sphere') {
19153
+ convertSphereEffect(obj.properties, defs);
19154
+ }
19149
19155
  if (obj.tag == 'image') {
19150
19156
  if (/\.svg/.test(obj.properties.href || '')) {
19151
19157
  convertSvgImage(obj, defs);
@@ -19156,6 +19162,25 @@
19156
19162
  }
19157
19163
  }
19158
19164
 
19165
+ function convertSphereEffect(obj, defs) {
19166
+ var id = 'mapshaper_sphere_effect';
19167
+ var href = `url(#${ id })`;
19168
+ var svg =
19169
+ `<radialGradient id="${id}" cx="0.5" cy="0.5" r=".56" fx="0.4" fy="0.35">
19170
+ <stop offset=".35" stop-opacity="0"/>
19171
+ <stop offset=".65" stop-opacity="0.1" />
19172
+ <stop offset=".85" stop-opacity="0.45" />
19173
+ <stop offset=".95" stop-opacity="1" />
19174
+ </radialGradient>` ;
19175
+ if (!utils.find(defs, function(o) { return o.id == id; })) {
19176
+ defs.push({svg, id, href});
19177
+ }
19178
+ obj.fill = href;
19179
+ if ('opacity' in obj === false && 'fill-opacity' in obj === false) {
19180
+ obj['fill-opacity'] = 0.35;
19181
+ }
19182
+ }
19183
+
19159
19184
  function convertSvgImage(obj, defs) {
19160
19185
  // Same-origin policy prevents embedding images in the web UI
19161
19186
  var href = obj.properties.href;
@@ -23675,7 +23700,10 @@ ${svg}
23675
23700
  .option('calc', calcOpt)
23676
23701
  .option('sum-fields', sumFieldsOpt)
23677
23702
  .option('copy-fields', copyFieldsOpt)
23678
- .option('gap-fill-area', minGapAreaOpt)
23703
+ .option('gap-fill-area', {
23704
+ describe: 'threshold for filling gaps, e.g. 1.5km2',
23705
+ type: 'area'
23706
+ })
23679
23707
  .option('sliver-control', sliverControlOpt)
23680
23708
  .option('allow-overlaps', {
23681
23709
  describe: 'allow dissolved polygons to overlap (disables gap fill)',
@@ -23917,7 +23945,9 @@ ${svg}
23917
23945
  .option('polygon', {
23918
23946
  describe: 'create a polygon to match the outline of the graticule',
23919
23947
  type: 'flag'
23920
- });
23948
+ })
23949
+ .option('name', nameOpt);
23950
+
23921
23951
 
23922
23952
  parser.command('grid')
23923
23953
  .describe('create a grid of square or hexagonal polygons')
@@ -24447,6 +24477,9 @@ ${svg}
24447
24477
  .option('fill-pattern', {
24448
24478
  describe: 'pattern fill, ex: "hatches 2px grey 2px blue"'
24449
24479
  })
24480
+ .option('fill-effect', {
24481
+ describe: 'use "sphere" on a circle for a 3d globe effect'
24482
+ })
24450
24483
  .option('fill-opacity', {
24451
24484
  describe: 'fill opacity'
24452
24485
  })
@@ -37929,7 +37962,8 @@ ${svg}
37929
37962
  return {
37930
37963
  gnom: 60,
37931
37964
  laea: 179,
37932
- ortho: 89.9, // TODO: investigate projection errors closer to 90
37965
+ //ortho: 89.9, // projection errors betwen lat +/-35 to 55
37966
+ ortho: 89.85, // TODO: investigate
37933
37967
  stere: 142,
37934
37968
  sterea: 142,
37935
37969
  ups: 10.5 // TODO: should be 6.5 deg at north pole
@@ -38308,7 +38342,7 @@ ${svg}
38308
38342
  });
38309
38343
 
38310
38344
  cmd.graticule = function(dataset, opts) {
38311
- var name = opts.polygon ? 'polygon' : 'graticule';
38345
+ var name = opts.name || opts.polygon && 'polygon' || 'graticule';
38312
38346
  var graticule, destInfo;
38313
38347
  if (dataset && !isLatLngDataset(dataset)) {
38314
38348
  // project graticule to match dataset
@@ -38374,7 +38408,7 @@ ${svg}
38374
38408
  //
38375
38409
  function createGraticule(P, outlined, opts) {
38376
38410
  var interval = opts.interval || 10;
38377
- if (![5,10,15,30,45].includes(interval)) stop('Invalid interval:', interval);
38411
+ if (![5,10,15,20,30,45].includes(interval)) stop('Invalid interval:', interval);
38378
38412
  P.lam0 * 180 / Math.PI;
38379
38413
  var precision = interval > 10 ? 1 : 0.5; // degrees between each vertex
38380
38414
  var xstep = interval;
@@ -40104,6 +40138,7 @@ ${svg}
40104
40138
  };
40105
40139
 
40106
40140
  if (opts.calc) {
40141
+ if (!lyr.data) initDataTable(lyr);
40107
40142
  records2 = recombineDataRecords(lyr.data.getRecords(), mosaicIndex.getSourceIdsByTileId, mosaicShapes.length, opts);
40108
40143
  lyr2.data = new DataTable(records2);
40109
40144
  }
@@ -40962,6 +40997,7 @@ ${svg}
40962
40997
  }
40963
40998
  commandStr = runGlobalExpression(opts.expression, targets);
40964
40999
  if (commandStr) {
41000
+ message(`command: [${commandStr}]`);
40965
41001
  commands = parseCommands(commandStr);
40966
41002
  runParsedCommands(commands, job, cb);
40967
41003
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.33",
3
+ "version": "0.6.35",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.33";
3
+ var VERSION = "0.6.35";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -12719,7 +12719,7 @@
12719
12719
  }
12720
12720
  var sliverControl = opts.sliver_control >= 0 ? opts.sliver_control : 0; // 0 is default
12721
12721
  var crs = getDatasetCRS(dataset);
12722
- var threshold = areaArg ?
12722
+ var threshold = areaArg && areaArg != 'auto' ?
12723
12723
  convertAreaParam(areaArg, crs) :
12724
12724
  getDefaultSliverThreshold(lyr, dataset.arcs);
12725
12725
  var filter = sliverControl > 0 ?
@@ -16653,7 +16653,8 @@
16653
16653
  overlap_rule: opts.overlap_rule
16654
16654
  };
16655
16655
  var mosaicIndex = new MosaicIndex(lyr, nodes, mosaicOpts);
16656
- var fillGaps = !opts.allow_overlaps; // gap fill doesn't work yet with overlapping shapes
16656
+ // gap fill doesn't work yet with overlapping shapes
16657
+ var fillGaps = !opts.allow_overlaps && (opts.sliver_control || opts.gap_fill_area);
16657
16658
  var cleanupData, filterData;
16658
16659
  if (fillGaps) {
16659
16660
  var sliverOpts = utils.extend({sliver_control: 1}, opts);
@@ -16935,6 +16936,7 @@
16935
16936
 
16936
16937
  function cleanPolygonLayerGeometry(lyr, dataset, opts) {
16937
16938
  // clean polygons by apply the 'dissolve2' function to each feature
16939
+ opts = Object.assign({gap_fill_area: 'auto'}, opts);
16938
16940
  var groups = lyr.shapes.map(function(shp, i) {
16939
16941
  return [i];
16940
16942
  });
@@ -18213,6 +18215,7 @@
18213
18215
  dy: 'measure',
18214
18216
  fill: 'color',
18215
18217
  'fill-pattern': 'pattern',
18218
+ 'fill-effect': null, // todo: validate effect names
18216
18219
  'font-family': null,
18217
18220
  'font-size': null,
18218
18221
  'font-style': null,
@@ -18261,7 +18264,7 @@
18261
18264
  var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity,vector-effect'.split(',');
18262
18265
 
18263
18266
  var propertiesBySymbolType = {
18264
- polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
18267
+ polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern', 'fill-effect')),
18265
18268
  polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit')),
18266
18269
  point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
18267
18270
  label: utils.arrayToIndex(commonProperties.concat(
@@ -19146,6 +19149,9 @@
19146
19149
  if (obj.tag == 'path' && obj.properties['fill-pattern']) {
19147
19150
  convertFillPattern(obj.properties, defs);
19148
19151
  }
19152
+ if (obj.tag == 'path' && obj.properties['fill-effect'] == 'sphere') {
19153
+ convertSphereEffect(obj.properties, defs);
19154
+ }
19149
19155
  if (obj.tag == 'image') {
19150
19156
  if (/\.svg/.test(obj.properties.href || '')) {
19151
19157
  convertSvgImage(obj, defs);
@@ -19156,6 +19162,25 @@
19156
19162
  }
19157
19163
  }
19158
19164
 
19165
+ function convertSphereEffect(obj, defs) {
19166
+ var id = 'mapshaper_sphere_effect';
19167
+ var href = `url(#${ id })`;
19168
+ var svg =
19169
+ `<radialGradient id="${id}" cx="0.5" cy="0.5" r=".56" fx="0.4" fy="0.35">
19170
+ <stop offset=".35" stop-opacity="0"/>
19171
+ <stop offset=".65" stop-opacity="0.1" />
19172
+ <stop offset=".85" stop-opacity="0.45" />
19173
+ <stop offset=".95" stop-opacity="1" />
19174
+ </radialGradient>` ;
19175
+ if (!utils.find(defs, function(o) { return o.id == id; })) {
19176
+ defs.push({svg, id, href});
19177
+ }
19178
+ obj.fill = href;
19179
+ if ('opacity' in obj === false && 'fill-opacity' in obj === false) {
19180
+ obj['fill-opacity'] = 0.35;
19181
+ }
19182
+ }
19183
+
19159
19184
  function convertSvgImage(obj, defs) {
19160
19185
  // Same-origin policy prevents embedding images in the web UI
19161
19186
  var href = obj.properties.href;
@@ -23675,7 +23700,10 @@ ${svg}
23675
23700
  .option('calc', calcOpt)
23676
23701
  .option('sum-fields', sumFieldsOpt)
23677
23702
  .option('copy-fields', copyFieldsOpt)
23678
- .option('gap-fill-area', minGapAreaOpt)
23703
+ .option('gap-fill-area', {
23704
+ describe: 'threshold for filling gaps, e.g. 1.5km2',
23705
+ type: 'area'
23706
+ })
23679
23707
  .option('sliver-control', sliverControlOpt)
23680
23708
  .option('allow-overlaps', {
23681
23709
  describe: 'allow dissolved polygons to overlap (disables gap fill)',
@@ -23917,7 +23945,9 @@ ${svg}
23917
23945
  .option('polygon', {
23918
23946
  describe: 'create a polygon to match the outline of the graticule',
23919
23947
  type: 'flag'
23920
- });
23948
+ })
23949
+ .option('name', nameOpt);
23950
+
23921
23951
 
23922
23952
  parser.command('grid')
23923
23953
  .describe('create a grid of square or hexagonal polygons')
@@ -24447,6 +24477,9 @@ ${svg}
24447
24477
  .option('fill-pattern', {
24448
24478
  describe: 'pattern fill, ex: "hatches 2px grey 2px blue"'
24449
24479
  })
24480
+ .option('fill-effect', {
24481
+ describe: 'use "sphere" on a circle for a 3d globe effect'
24482
+ })
24450
24483
  .option('fill-opacity', {
24451
24484
  describe: 'fill opacity'
24452
24485
  })
@@ -37929,7 +37962,8 @@ ${svg}
37929
37962
  return {
37930
37963
  gnom: 60,
37931
37964
  laea: 179,
37932
- ortho: 89.9, // TODO: investigate projection errors closer to 90
37965
+ //ortho: 89.9, // projection errors betwen lat +/-35 to 55
37966
+ ortho: 89.85, // TODO: investigate
37933
37967
  stere: 142,
37934
37968
  sterea: 142,
37935
37969
  ups: 10.5 // TODO: should be 6.5 deg at north pole
@@ -38308,7 +38342,7 @@ ${svg}
38308
38342
  });
38309
38343
 
38310
38344
  cmd.graticule = function(dataset, opts) {
38311
- var name = opts.polygon ? 'polygon' : 'graticule';
38345
+ var name = opts.name || opts.polygon && 'polygon' || 'graticule';
38312
38346
  var graticule, destInfo;
38313
38347
  if (dataset && !isLatLngDataset(dataset)) {
38314
38348
  // project graticule to match dataset
@@ -38374,7 +38408,7 @@ ${svg}
38374
38408
  //
38375
38409
  function createGraticule(P, outlined, opts) {
38376
38410
  var interval = opts.interval || 10;
38377
- if (![5,10,15,30,45].includes(interval)) stop('Invalid interval:', interval);
38411
+ if (![5,10,15,20,30,45].includes(interval)) stop('Invalid interval:', interval);
38378
38412
  P.lam0 * 180 / Math.PI;
38379
38413
  var precision = interval > 10 ? 1 : 0.5; // degrees between each vertex
38380
38414
  var xstep = interval;
@@ -40104,6 +40138,7 @@ ${svg}
40104
40138
  };
40105
40139
 
40106
40140
  if (opts.calc) {
40141
+ if (!lyr.data) initDataTable(lyr);
40107
40142
  records2 = recombineDataRecords(lyr.data.getRecords(), mosaicIndex.getSourceIdsByTileId, mosaicShapes.length, opts);
40108
40143
  lyr2.data = new DataTable(records2);
40109
40144
  }
@@ -40962,6 +40997,7 @@ ${svg}
40962
40997
  }
40963
40998
  commandStr = runGlobalExpression(opts.expression, targets);
40964
40999
  if (commandStr) {
41000
+ message(`command: [${commandStr}]`);
40965
41001
  commands = parseCommands(commandStr);
40966
41002
  runParsedCommands(commands, job, cb);
40967
41003
  } else {