mapshaper 0.5.118 → 0.6.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.5.118",
3
+ "version": "0.6.3",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -9,6 +9,7 @@
9
9
  "cartography",
10
10
  "simplification",
11
11
  "topology",
12
+ "csv",
12
13
  "gis"
13
14
  ],
14
15
  "author": "Matthew Bloch <masiyou@gmail.com>",
@@ -19,16 +20,15 @@
19
20
  "url": "https://github.com/mbloch/mapshaper"
20
21
  },
21
22
  "engines": {
22
- "node": ">=6.0.0"
23
+ "node": ">=12.0.0"
23
24
  },
24
25
  "scripts": {
25
- "test": "mocha -r esm --parallel --jobs 4 --check-leaks -R dot",
26
+ "test": "mocha test",
26
27
  "build": "rollup --config",
27
- "prepublishOnly": "npm test; ./pre-publish",
28
+ "lint": "eslint --ext mjs src/",
29
+ "prepublishOnly": "npm lint; npm test; ./pre-publish",
28
30
  "postpublish": "./release_web_ui; ./release_github_version",
29
- "browserify_old": "browserify -r sync-request -r mproj -r buffer -r iconv-lite -r fs -r flatbush -r rw -r path -r d3-scale-chromatic -r d3-color -r d3-interpolate -o www/modules.js",
30
- "browserify": "browserify -r sync-request -r mproj -r buffer -r iconv-lite -r fs -r flatbush -r rw -r path -r d3-scale-chromatic -r d3-color -r d3-interpolate -r kdbush -r @tmcw/togeojson -o www/modules.js",
31
- "watch": "rollup --config --watch",
31
+ "browserify": "browserify -r sync-request -r mproj -r buffer -r iconv-lite -r fs -r flatbush -r rw -r path -r kdbush -r @tmcw/togeojson -o www/modules.js",
32
32
  "dev": "rollup --config --watch"
33
33
  },
34
34
  "main": "./mapshaper.js",
@@ -36,7 +36,7 @@
36
36
  "/bin/**",
37
37
  "/www/**",
38
38
  "!/www/basemap.js",
39
- "!/www/nacis/",
39
+ "!/www/nacis/**",
40
40
  "/mapshaper.js",
41
41
  "!.DS_Store"
42
42
  ],
@@ -50,7 +50,7 @@
50
50
  "delaunator": "^5.0.0",
51
51
  "flatbush": "^3.2.1",
52
52
  "geokdbush": "^1.1.0",
53
- "iconv-lite": "0.4.24",
53
+ "iconv-lite": "^0.6.3",
54
54
  "kdbush": "^3.0.0",
55
55
  "mproj": "0.0.35",
56
56
  "opn": "^5.3.0",
@@ -59,16 +59,24 @@
59
59
  "tinyqueue": "^2.0.3"
60
60
  },
61
61
  "devDependencies": {
62
- "@rollup/plugin-node-resolve": "^13.0.6",
62
+ "@rollup/plugin-node-resolve": "^13.3.0",
63
63
  "browserify": "^17.0.0",
64
64
  "csv-spectrum": "^1.0.0",
65
- "deep-eql": ">=0.1.3",
66
- "esm": "^3.2.25",
67
- "mocha": "^8.4.0",
68
- "rollup": "^2.60.0",
65
+ "eslint": "^8.16.0",
66
+ "mocha": "^10.0.0",
67
+ "rollup": "^2.73.0",
69
68
  "shell-quote": "^1.6.1",
70
69
  "underscore": "^1.13.1"
71
70
  },
71
+ "mocha": {
72
+ "reporter": "dot",
73
+ "node-option": [
74
+ "experimental-specifier-resolution=node"
75
+ ],
76
+ "check-leaks": true,
77
+ "parallel": true,
78
+ "jobs": 4
79
+ },
72
80
  "bin": {
73
81
  "mapshaper": "./bin/mapshaper",
74
82
  "mapshaper-gui": "./bin/mapshaper-gui",
@@ -78,6 +78,7 @@
78
78
  get findValueByPct () { return findValueByPct; },
79
79
  get findValueByRank () { return findValueByRank; },
80
80
  get findMedian () { return findMedian; },
81
+ get findQuantile () { return findQuantile; },
81
82
  get mean () { return mean; },
82
83
  get format () { return format; },
83
84
  get formatter () { return formatter; },
@@ -1682,7 +1683,6 @@
1682
1683
  }
1683
1684
 
1684
1685
  function Slider(ref, opts) {
1685
- var _el = El(ref);
1686
1686
  var _self = this;
1687
1687
  var defaults = {
1688
1688
  space: 7
@@ -1713,7 +1713,7 @@
1713
1713
  _handle = El(ref);
1714
1714
  draggable(_handle)
1715
1715
  .on('drag', function(e) {
1716
- setHandlePos(startX + e.dx, true);
1716
+ setHandlePos(startX + e.dx);
1717
1717
  })
1718
1718
  .on('dragstart', function(e) {
1719
1719
  startX = position();
@@ -1739,7 +1739,7 @@
1739
1739
  return _pct;
1740
1740
  };
1741
1741
 
1742
- function setHandlePos(x, fire) {
1742
+ function setHandlePos(x) {
1743
1743
  x = utils$1.clamp(x, 0, size());
1744
1744
  var pct = x / size();
1745
1745
  if (pct != _pct) {
@@ -2261,7 +2261,7 @@
2261
2261
  menu.hide();
2262
2262
  setTimeout(function() {
2263
2263
  var opts = getSimplifyOptions();
2264
- mapshaper.simplify(dataset, opts);
2264
+ mapshaper.cmd.simplify(dataset, opts);
2265
2265
  gui.session.simplificationApplied(getSimplifyOptionsAsString());
2266
2266
  updateZ(gui.map.getActiveLayer()); // question: does this update all display layers?
2267
2267
  model.updated({
@@ -3122,7 +3122,7 @@
3122
3122
 
3123
3123
  function cleanLayerName(raw) {
3124
3124
  return raw.replace(/[\n\t/\\]/g, '')
3125
- .replace(/^[\.\s]+/, '').replace(/[\.\s]+$/, '');
3125
+ .replace(/^[.\s]+/, '').replace(/[.\s]+$/, '');
3126
3126
  }
3127
3127
 
3128
3128
  function updateLayerStackOrder(layers) {
@@ -3856,8 +3856,6 @@
3856
3856
  }
3857
3857
  }
3858
3858
 
3859
- var snapVerticesToPoint = internal.snapVerticesToPoint;
3860
- var cloneShape = internal.cloneShape;
3861
3859
  var copyRecord = internal.copyRecord;
3862
3860
 
3863
3861
  function Undo(gui) {
@@ -4412,7 +4410,8 @@
4412
4410
  return self;
4413
4411
  }
4414
4412
 
4415
- var Buffer = require('buffer').Buffer; // works with browserify
4413
+ // Fall back to browserify's Buffer polyfill
4414
+ var B = typeof Buffer != 'undefined' ? Buffer : require('buffer').Buffer;
4416
4415
 
4417
4416
  // This module provides a way for multiple jobs to run together asynchronously
4418
4417
  // while keeping job-level context variables (like "defs") separate.
@@ -4740,7 +4739,7 @@
4740
4739
  '/': '&#x2F;'
4741
4740
  };
4742
4741
  function htmlEscape(s) {
4743
- return String(s).replace(/[&<>"'\/]/g, function(s) {
4742
+ return String(s).replace(/[&<>"'/]/g, function(s) {
4744
4743
  return entityMap[s];
4745
4744
  });
4746
4745
  }
@@ -5314,18 +5313,24 @@
5314
5313
  return arr[k];
5315
5314
  }
5316
5315
 
5317
- //
5318
- //
5319
5316
  function findMedian(arr) {
5320
- var n = arr.length,
5321
- rank = Math.floor(n / 2) + 1,
5322
- median = findValueByRank(arr, rank);
5323
- if ((n & 1) == 0) {
5324
- median = (median + findValueByRank(arr, rank - 1)) / 2;
5325
- }
5326
- return median;
5317
+ return findQuantile(arr, 0.5);
5327
5318
  }
5328
5319
 
5320
+ function findQuantile(arr, k) {
5321
+ var n = arr.length,
5322
+ i1 = Math.floor((n - 1) * k),
5323
+ i2 = Math.ceil((n - 1) * k);
5324
+ if (i1 < 0 || i2 >= n) return NaN;
5325
+ var v1 = findValueByRank(arr, i1 + 1);
5326
+ if (i1 == i2) return v1;
5327
+ var v2 = findValueByRank(arr, i2 + 1);
5328
+ // use linear interpolation
5329
+ var w1 = i2 / (n - 1) - k;
5330
+ var w2 = k - i1 / (n - 1);
5331
+ var v = (v1 * w1 + v2 * w2) * (n - 1);
5332
+ return v;
5333
+ }
5329
5334
 
5330
5335
  function mean(arr) {
5331
5336
  var count = 0,
@@ -5383,8 +5388,8 @@
5383
5388
  var type = matches[4];
5384
5389
  var isString = type == 's',
5385
5390
  isHex = type == 'x' || type == 'X',
5386
- isInt = type == 'd' || type == 'i',
5387
- isFloat = type == 'f',
5391
+ // isInt = type == 'd' || type == 'i',
5392
+ // isFloat = type == 'f',
5388
5393
  isNumber = !isString;
5389
5394
 
5390
5395
  var sign = "",
@@ -5443,7 +5448,7 @@
5443
5448
 
5444
5449
  // Get a function for interpolating formatted values into a string.
5445
5450
  function formatter(fmt) {
5446
- var codeRxp = /%([\',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
5451
+ var codeRxp = /%([',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g;
5447
5452
  var literals = [],
5448
5453
  formatCodes = [],
5449
5454
  startIdx = 0,
@@ -5487,10 +5492,10 @@
5487
5492
 
5488
5493
  function createBuffer(arg, arg2) {
5489
5494
  if (isInteger(arg)) {
5490
- return Buffer.allocUnsafe ? Buffer.allocUnsafe(arg) : new Buffer(arg);
5495
+ return B.allocUnsafe ? B.allocUnsafe(arg) : new B(arg);
5491
5496
  } else {
5492
5497
  // check allocUnsafe to make sure Buffer.from() will accept strings (it didn't before Node v5.10)
5493
- return Buffer.from && Buffer.allocUnsafe ? Buffer.from(arg, arg2) : new Buffer(arg, arg2);
5498
+ return B.from && B.allocUnsafe ? B.from(arg, arg2) : new B(arg, arg2);
5494
5499
  }
5495
5500
  }
5496
5501
 
@@ -5843,27 +5848,21 @@
5843
5848
 
5844
5849
  function pointTest(x, y) {
5845
5850
  var bullseyeDist = 2, // hit all points w/in 2 px
5846
- tinyDist = 0.5,
5847
- toPx = ext.getTransform().mx,
5848
- hits = [],
5849
5851
  hitThreshold = 25,
5850
- newThreshold = Infinity;
5852
+ toPx = ext.getTransform().mx,
5853
+ hits = [];
5851
5854
 
5855
+ // inlining forEachPoint() does not not appreciably speed this up
5852
5856
  internal.forEachPoint(displayLayer.layer.shapes, function(p, id) {
5853
5857
  var dist = geom.distance2D(x, y, p[0], p[1]) * toPx;
5854
5858
  if (dist > hitThreshold) return;
5855
- // got a hit
5856
- if (dist < newThreshold) {
5857
- // start a collection of hits
5858
- hits = [id];
5859
- hitThreshold = Math.max(bullseyeDist, dist + tinyDist);
5860
- newThreshold = dist < bullseyeDist ? -1 : dist - tinyDist;
5861
- } else {
5862
- // add to hits if inside bullseye or is same dist as previous hit
5863
- hits.push(id);
5859
+ if (dist < hitThreshold && hitThreshold > bullseyeDist) {
5860
+ hits = [];
5861
+ hitThreshold = Math.max(bullseyeDist, dist);
5864
5862
  }
5863
+ hits.push(id);
5865
5864
  });
5866
- // TODO: add info on what part of a shape gets hit
5865
+ // TODO: add info on what part of a shape gets hit?
5867
5866
  return {
5868
5867
  ids: utils$1.uniq(hits) // multipoint features can register multiple hits
5869
5868
  };
@@ -8272,20 +8271,25 @@
8272
8271
  _frame;
8273
8272
 
8274
8273
  _position.on('resize', function(e) {
8275
- if (_contentBounds) {
8274
+ if (ready()) {
8276
8275
  onChange({resize: true});
8277
8276
  }
8278
8277
  });
8279
8278
 
8279
+ function ready() { return !!_contentBounds; }
8280
+
8280
8281
  this.reset = function() {
8282
+ if (!ready()) return;
8281
8283
  recenter(_contentBounds.centerX(), _contentBounds.centerY(), 1, {reset: true});
8282
8284
  };
8283
8285
 
8284
8286
  this.home = function() {
8287
+ if (!ready()) return;
8285
8288
  recenter(_contentBounds.centerX(), _contentBounds.centerY(), 1);
8286
8289
  };
8287
8290
 
8288
8291
  this.pan = function(xpix, ypix) {
8292
+ if (!ready()) return;
8289
8293
  var t = this.getTransform();
8290
8294
  recenter(_cx - xpix / t.mx, _cy - ypix / t.my);
8291
8295
  };
@@ -8293,6 +8297,7 @@
8293
8297
  // Zoom to @w (width of the map viewport in coordinates)
8294
8298
  // @xpct, @ypct: optional focus, [0-1]...
8295
8299
  this.zoomToExtent = function(w, xpct, ypct) {
8300
+ if (!ready()) return;
8296
8301
  if (arguments.length < 3) {
8297
8302
  xpct = 0.5;
8298
8303
  ypct = 0.5;
@@ -8312,6 +8317,7 @@
8312
8317
  };
8313
8318
 
8314
8319
  this.zoomByPct = function(pct, xpct, ypct) {
8320
+ if (!ready()) return;
8315
8321
  this.zoomToExtent(this.getBounds().width() / pct, xpct, ypct);
8316
8322
  };
8317
8323
 
@@ -8753,7 +8759,7 @@
8753
8759
  bx = t.bx,
8754
8760
  by = t.by;
8755
8761
  if (size === 0) return;
8756
- if (size <= 4 && !styler) {
8762
+ if (size <= 6 && !styler) {
8757
8763
  // optimized drawing of many small same-colored dots
8758
8764
  _self.drawSquareDotsFaster(shapes, color, size, t);
8759
8765
  return;
@@ -8810,14 +8816,12 @@
8810
8816
  // pixels: Uint32Array of pixel colors
8811
8817
  // w, h: Size of canvas
8812
8818
  function drawSquareFaster(x, y, rgba, size, pixels, w, h) {
8813
- var xmin = (x - size * 0.5) | 0;
8814
- var ymin = (y - size * 0.5) | 0;
8815
- var xmax = xmin + size - 1;
8816
- var ymax = ymin + size - 1;
8817
- var c, r;
8818
- for (c = xmin; c <= xmax; c++) {
8819
- if (c < 0 || c >= w) continue;
8820
- for (r = ymin; r <= ymax && r >= 0 && r < h; r++) {
8819
+ var xmin = x < 0 ? 0 : (x - size * 0.5) | 0;
8820
+ var ymin = y < 0 ? 0 : (y - size * 0.5) | 0;
8821
+ var xmax = x >= w-1 ? w-1 : xmin + size - 1;
8822
+ var ymax = y >= h-1 ? h-1 : ymin + size - 1;
8823
+ for (var r = ymin; r <= ymax; r++) {
8824
+ for (var c = xmin; c <= xmax; c++) {
8821
8825
  pixels[r * w + c] = rgba;
8822
8826
  }
8823
8827
  }
@@ -8904,24 +8908,25 @@
8904
8908
  return s;
8905
8909
  }
8906
8910
 
8907
-
8908
8911
  function getDotScale(ext) {
8909
8912
  var smallSide = Math.min(ext.width(), ext.height());
8913
+ var mapScale = ext.scale();
8910
8914
  // reduce size on smaller screens
8911
8915
  var j = smallSide < 200 && 0.5 || smallSide < 400 && 0.75 || 1;
8916
+ // grow dots as map zooms in
8912
8917
  var k = 1;
8913
- var mapScale = ext.scale();
8914
8918
  if (mapScale < 0.5) {
8915
8919
  k = Math.pow(mapScale + 0.5, 0.35);
8916
- }
8917
- if (mapScale > 1) {
8920
+ } else if (mapScale > 1) {
8918
8921
  // scale faster at first, so small dots in large datasets
8919
8922
  // become easily visible and clickable after zooming in a bit
8920
8923
  k *= Math.pow(Math.min(mapScale, 10), 0.3);
8921
8924
  k *= Math.pow(mapScale, 0.1);
8922
8925
  }
8923
-
8924
- return k * j * GUI.getPixelRatio();
8926
+ // grow pixels more slowly on retina displays (to reduce number of pixels to
8927
+ // draw for large point datasets when slightly zoomed in)
8928
+ var l = Math.pow(GUI.getPixelRatio(), 0.8);
8929
+ return j * k * l;
8925
8930
  }
8926
8931
 
8927
8932
  function getScaledTransform(ext) {
@@ -9494,7 +9499,7 @@
9494
9499
 
9495
9500
  // Only generate low-detail arcs for larger datasets
9496
9501
  if (size > 5e5) {
9497
- if (!!unfilteredArcs.getVertexData().zz) {
9502
+ if (unfilteredArcs.getVertexData().zz) {
9498
9503
  // Use precalculated simplification data for vertex filtering, if available
9499
9504
  filteredArcs = initFilteredArcs(unfilteredArcs);
9500
9505
  filteredSegLen = internal.getAvgSegment(filteredArcs);
@@ -9860,7 +9865,13 @@
9860
9865
  var warning;
9861
9866
 
9862
9867
  if (!dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS)) {
9863
- warning = 'The current layer is not compatible with the projection used by the basemaps.';
9868
+ warning = 'This data is incompatible with the basemaps.';
9869
+ if (!internal.layerHasGeometry(activeLyr.layer)) {
9870
+ warning += ' Reason: layer is missing geographic data';
9871
+ } else if (!dataCRS) {
9872
+ warning += ' Reason: unknown projection.';
9873
+ }
9874
+
9864
9875
  basemapWarning.html(warning).show();
9865
9876
  basemapNote.hide();
9866
9877
  } else {