mapshaper 0.5.97 → 0.5.100
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/CHANGELOG.md +9 -0
- package/mapshaper.js +104 -36
- package/package.json +2 -1
- package/www/images/thumb-map.jpg +0 -0
- package/www/images/thumb-satellite.jpg +0 -0
- package/www/index.html +15 -1
- package/www/mapshaper-gui.js +780 -385
- package/www/mapshaper.js +104 -36
- package/www/page.css +89 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
v0.5.100
|
|
2
|
+
* Added support for using the basemap feature with datasets in a wide variety of projections.
|
|
3
|
+
|
|
4
|
+
v0.5.99
|
|
5
|
+
* Added support for viewing data against a Mapbox basemap (enabled on the mapshaper.org site).
|
|
6
|
+
|
|
7
|
+
v0.5.98
|
|
8
|
+
* Better handling of null data by the -classify command.
|
|
9
|
+
|
|
1
10
|
v0.5.97
|
|
2
11
|
* Better warnings and error messages.
|
|
3
12
|
|
package/mapshaper.js
CHANGED
|
@@ -1771,6 +1771,8 @@
|
|
|
1771
1771
|
// avoid re-allocating memory
|
|
1772
1772
|
var xx2 = new Float64Array(data.xx.buffer, 0, n-1);
|
|
1773
1773
|
var yy2 = new Float64Array(data.yy.buffer, 0, n-1);
|
|
1774
|
+
var zz2 = arcs.isFlat() ? null : new Float64Array(data.zz.buffer, 0, n-1);
|
|
1775
|
+
var z = arcs.getRetainedInterval();
|
|
1774
1776
|
var count = 0;
|
|
1775
1777
|
var found = false;
|
|
1776
1778
|
for (var j=0; j<nn.length; j++) {
|
|
@@ -1784,24 +1786,31 @@
|
|
|
1784
1786
|
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
1785
1787
|
utils.copyElements(data.xx, i+1, xx2, i, n-i-1);
|
|
1786
1788
|
utils.copyElements(data.yy, i+1, yy2, i, n-i-1);
|
|
1787
|
-
|
|
1789
|
+
if (zz2) {
|
|
1790
|
+
utils.copyElements(data.zz, 0, zz2, 0, i);
|
|
1791
|
+
utils.copyElements(data.zz, i+1, zz2, i, n-i-1);
|
|
1792
|
+
}
|
|
1793
|
+
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1794
|
+
arcs.setRetainedInterval(z);
|
|
1788
1795
|
}
|
|
1789
1796
|
|
|
1790
1797
|
function insertVertex(arcs, i, p) {
|
|
1791
|
-
// TODO: add extra bytes to the buffers, to reduce new memory allocation
|
|
1792
1798
|
var data = arcs.getVertexData();
|
|
1793
1799
|
var nn = data.nn;
|
|
1794
1800
|
var n = data.xx.length;
|
|
1795
1801
|
var count = 0;
|
|
1796
1802
|
var found = false;
|
|
1797
|
-
var xx2, yy2;
|
|
1803
|
+
var xx2, yy2, zz2;
|
|
1798
1804
|
// avoid re-allocating memory on each insertion
|
|
1799
1805
|
if (data.xx.buffer.byteLength >= data.xx.length * 8 + 8) {
|
|
1800
1806
|
xx2 = new Float64Array(data.xx.buffer, 0, n+1);
|
|
1801
1807
|
yy2 = new Float64Array(data.yy.buffer, 0, n+1);
|
|
1802
1808
|
} else {
|
|
1803
|
-
xx2 = new Float64Array(new ArrayBuffer((n +
|
|
1804
|
-
yy2 = new Float64Array(new ArrayBuffer((n +
|
|
1809
|
+
xx2 = new Float64Array(new ArrayBuffer((n + 50) * 8), 0, n+1);
|
|
1810
|
+
yy2 = new Float64Array(new ArrayBuffer((n + 50) * 8), 0, n+1);
|
|
1811
|
+
}
|
|
1812
|
+
if (!arcs.isFlat()) {
|
|
1813
|
+
zz2 = new Float64Array(new ArrayBuffer((n + 1) * 8), 0, n+1);
|
|
1805
1814
|
}
|
|
1806
1815
|
for (var j=0; j<nn.length; j++) {
|
|
1807
1816
|
count += nn[j];
|
|
@@ -1816,7 +1825,12 @@
|
|
|
1816
1825
|
utils.copyElements(data.yy, i, yy2, i+1, n-i);
|
|
1817
1826
|
xx2[i] = p[0];
|
|
1818
1827
|
yy2[i] = p[1];
|
|
1819
|
-
|
|
1828
|
+
if (zz2) {
|
|
1829
|
+
zz2[i] = Infinity;
|
|
1830
|
+
utils.copyElements(data.zz, 0, zz2, 0, i);
|
|
1831
|
+
utils.copyElements(data.zz, i, zz2, i+1, n-i);
|
|
1832
|
+
}
|
|
1833
|
+
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
1820
1834
|
}
|
|
1821
1835
|
|
|
1822
1836
|
var ArcUtils = /*#__PURE__*/Object.freeze({
|
|
@@ -4663,8 +4677,8 @@
|
|
|
4663
4677
|
if (isLatLngCRS(P)) {
|
|
4664
4678
|
return xy.concat();
|
|
4665
4679
|
}
|
|
4666
|
-
proj =
|
|
4667
|
-
return proj(xy);
|
|
4680
|
+
proj = getProjTransform(P, getCRS('wgs84'));
|
|
4681
|
+
return proj(xy[0], xy[1]);
|
|
4668
4682
|
}
|
|
4669
4683
|
|
|
4670
4684
|
function getProjInfo(dataset) {
|
|
@@ -4806,10 +4820,30 @@
|
|
|
4806
4820
|
return !isLatLngCRS(P);
|
|
4807
4821
|
}
|
|
4808
4822
|
|
|
4823
|
+
function isInvertibleCRS(P) {
|
|
4824
|
+
if (!P || !P.inv) return false;
|
|
4825
|
+
return true;
|
|
4826
|
+
}
|
|
4827
|
+
|
|
4809
4828
|
function isLatLngCRS(P) {
|
|
4810
4829
|
return P && P.is_latlong || false;
|
|
4811
4830
|
}
|
|
4812
4831
|
|
|
4832
|
+
function isWGS84(P) {
|
|
4833
|
+
if (!isLatLngCRS(P)) return false;
|
|
4834
|
+
var proj4 = crsToProj4(P);
|
|
4835
|
+
return proj4.toLowerCase().includes('84');
|
|
4836
|
+
}
|
|
4837
|
+
|
|
4838
|
+
function isWebMercator(P) {
|
|
4839
|
+
if (!P) return false;
|
|
4840
|
+
var str = crsToProj4(P);
|
|
4841
|
+
// e.g. +proj=merc +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +wktext +a=6378137 +b=6378137 +nadgrids=@null
|
|
4842
|
+
// e.g. +proj=merc +a=6378137 +b=6378137
|
|
4843
|
+
// TODO: support https://proj.org/operations/projections/webmerc.html
|
|
4844
|
+
return str.includes('+proj=merc') && str.includes('+a=6378137') && str.includes('+b=6378137');
|
|
4845
|
+
}
|
|
4846
|
+
|
|
4813
4847
|
function isLatLngDataset(dataset) {
|
|
4814
4848
|
return isLatLngCRS(getDatasetCRS(dataset));
|
|
4815
4849
|
}
|
|
@@ -4863,7 +4897,10 @@
|
|
|
4863
4897
|
requireDatasetsHaveCompatibleCRS: requireDatasetsHaveCompatibleCRS,
|
|
4864
4898
|
getScaleFactorAtXY: getScaleFactorAtXY,
|
|
4865
4899
|
isProjectedCRS: isProjectedCRS,
|
|
4900
|
+
isInvertibleCRS: isInvertibleCRS,
|
|
4866
4901
|
isLatLngCRS: isLatLngCRS,
|
|
4902
|
+
isWGS84: isWGS84,
|
|
4903
|
+
isWebMercator: isWebMercator,
|
|
4867
4904
|
isLatLngDataset: isLatLngDataset,
|
|
4868
4905
|
printProjections: printProjections,
|
|
4869
4906
|
translatePrj: translatePrj,
|
|
@@ -8357,8 +8394,8 @@
|
|
|
8357
8394
|
}
|
|
8358
8395
|
|
|
8359
8396
|
function getBoundsPrecisionForDisplay(bbox) {
|
|
8360
|
-
var w = bbox[2] - bbox[0],
|
|
8361
|
-
h = bbox[3] - bbox[1],
|
|
8397
|
+
var w = Math.abs(bbox[2] - bbox[0]),
|
|
8398
|
+
h = Math.abs(bbox[3] - bbox[1]),
|
|
8362
8399
|
range = Math.min(w, h) + 1e-8,
|
|
8363
8400
|
digits = 0;
|
|
8364
8401
|
while (range < 2000) {
|
|
@@ -29059,6 +29096,31 @@ ${svg}
|
|
|
29059
29096
|
return ramp;
|
|
29060
29097
|
}
|
|
29061
29098
|
|
|
29099
|
+
function getNullValue(opts) {
|
|
29100
|
+
var nullValue;
|
|
29101
|
+
if ('null_value' in opts) {
|
|
29102
|
+
nullValue = parseNullValue(opts.null_value);
|
|
29103
|
+
} else if (opts.colors) {
|
|
29104
|
+
nullValue = '#eee';
|
|
29105
|
+
} else if (opts.values) {
|
|
29106
|
+
nullValue = null;
|
|
29107
|
+
} else {
|
|
29108
|
+
nullValue = -1; // kludge, to match behavior of getClassValues()
|
|
29109
|
+
}
|
|
29110
|
+
return nullValue;
|
|
29111
|
+
}
|
|
29112
|
+
|
|
29113
|
+
// Parse command line string arguments to the correct data type
|
|
29114
|
+
function parseNullValue(val) {
|
|
29115
|
+
if (utils.isString(val) && !isNaN(+val)) {
|
|
29116
|
+
val = +val;
|
|
29117
|
+
}
|
|
29118
|
+
if (val === 'null') {
|
|
29119
|
+
val = null;
|
|
29120
|
+
}
|
|
29121
|
+
return val;
|
|
29122
|
+
}
|
|
29123
|
+
|
|
29062
29124
|
function getClassValues(method, n, opts) {
|
|
29063
29125
|
var categorical = method == 'categorical' || method == 'non-adjacent';
|
|
29064
29126
|
var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
|
|
@@ -29132,27 +29194,36 @@ ${svg}
|
|
|
29132
29194
|
return values;
|
|
29133
29195
|
}
|
|
29134
29196
|
|
|
29135
|
-
var sequential = ['quantile', 'nice', 'equal-interval', 'hybrid'];
|
|
29197
|
+
var sequential = ['quantile', 'nice', 'equal-interval', 'hybrid', 'breaks'];
|
|
29136
29198
|
var all = ['non-adjacent', 'indexed', 'categorical'].concat(sequential);
|
|
29137
29199
|
|
|
29138
|
-
function getClassifyMethod(opts,
|
|
29200
|
+
function getClassifyMethod(opts, dataType) {
|
|
29139
29201
|
var method;
|
|
29140
29202
|
if (opts.method) {
|
|
29141
29203
|
method = opts.method;
|
|
29204
|
+
} else if (opts.breaks) {
|
|
29205
|
+
method = 'breaks';
|
|
29142
29206
|
} else if (opts.index_field) {
|
|
29143
29207
|
method = 'indexed';
|
|
29144
|
-
} else if (opts.categories ||
|
|
29208
|
+
} else if (opts.categories || dataType == 'string') {
|
|
29145
29209
|
method = 'categorical';
|
|
29146
|
-
} else if (
|
|
29210
|
+
} else if (dataType == 'number') {
|
|
29147
29211
|
method = 'quantile'; // TODO: validate data field
|
|
29212
|
+
} else if (dataType == 'date' || dataType == 'object') {
|
|
29213
|
+
stop('Data type does not support classification:', dataType);
|
|
29214
|
+
} else if (dataType === null) {
|
|
29215
|
+
// data field is empty
|
|
29216
|
+
return null; // kludge
|
|
29217
|
+
} else if (dataType === undefined) {
|
|
29218
|
+
// no data field was given
|
|
29219
|
+
stop('Expected a data field to classify or the non-adjacent option');
|
|
29148
29220
|
} else {
|
|
29149
|
-
|
|
29150
|
-
stop('Missing a data field and/or classification method');
|
|
29221
|
+
stop('Unable to determine which classification method to use.');
|
|
29151
29222
|
}
|
|
29152
29223
|
if (!all.includes(method)) {
|
|
29153
29224
|
stop('Not a recognized classification method:', method);
|
|
29154
29225
|
}
|
|
29155
|
-
if (sequential.includes(method) &&
|
|
29226
|
+
if (sequential.includes(method) && dataType != 'number' && dataType !== null) {
|
|
29156
29227
|
stop('The', method, 'method requires a numerical data field');
|
|
29157
29228
|
}
|
|
29158
29229
|
return method;
|
|
@@ -29165,7 +29236,7 @@ ${svg}
|
|
|
29165
29236
|
var opts = optsArg || {};
|
|
29166
29237
|
var records = lyr.data && lyr.data.getRecords();
|
|
29167
29238
|
var valuesAreColors = !!opts.colors;
|
|
29168
|
-
var dataField,
|
|
29239
|
+
var dataField, fieldType, outputField;
|
|
29169
29240
|
var values, nullValue;
|
|
29170
29241
|
var classifyByValue, classifyByRecordId;
|
|
29171
29242
|
var numClasses, numValues;
|
|
@@ -29179,9 +29250,10 @@ ${svg}
|
|
|
29179
29250
|
//
|
|
29180
29251
|
if (opts.index_field) {
|
|
29181
29252
|
dataField = opts.index_field;
|
|
29182
|
-
|
|
29253
|
+
fieldType = getColumnType(opts.field, records);
|
|
29254
|
+
} else if (opts.field) {
|
|
29183
29255
|
dataField = opts.field;
|
|
29184
|
-
|
|
29256
|
+
fieldType = getColumnType(opts.field, records);
|
|
29185
29257
|
}
|
|
29186
29258
|
if (dataField) {
|
|
29187
29259
|
requireDataField(lyr.data, dataField);
|
|
@@ -29189,7 +29261,7 @@ ${svg}
|
|
|
29189
29261
|
|
|
29190
29262
|
// get classification method
|
|
29191
29263
|
//
|
|
29192
|
-
method = getClassifyMethod(opts,
|
|
29264
|
+
method = getClassifyMethod(opts, fieldType);
|
|
29193
29265
|
|
|
29194
29266
|
// validate classification method
|
|
29195
29267
|
if (method == 'non-adjacent') {
|
|
@@ -29207,6 +29279,7 @@ ${svg}
|
|
|
29207
29279
|
// get the number of classes and the number of values
|
|
29208
29280
|
//
|
|
29209
29281
|
// expand categories if value is '*'
|
|
29282
|
+
// use all unique values if categories option is missing
|
|
29210
29283
|
if (method == 'categorical') {
|
|
29211
29284
|
if ((!opts.categories || opts.categories.includes('*')) && dataField) {
|
|
29212
29285
|
opts.categories = getUniqFieldValues(records, dataField);
|
|
@@ -29248,24 +29321,16 @@ ${svg}
|
|
|
29248
29321
|
message('Colors:', formatValuesForLogging(values));
|
|
29249
29322
|
}
|
|
29250
29323
|
|
|
29251
|
-
|
|
29252
|
-
//
|
|
29253
|
-
if ('null_value' in opts) {
|
|
29254
|
-
nullValue = opts.null_value;
|
|
29255
|
-
} else if (valuesAreColors) {
|
|
29256
|
-
nullValue = '#eee';
|
|
29257
|
-
} else if (opts.values) {
|
|
29258
|
-
nullValue = null;
|
|
29259
|
-
} else {
|
|
29260
|
-
nullValue = -1; // kludge, to match behavior of getClassValues()
|
|
29261
|
-
}
|
|
29262
|
-
|
|
29324
|
+
nullValue = getNullValue(opts);
|
|
29263
29325
|
|
|
29264
29326
|
// get a function to convert input data to class indexes
|
|
29265
29327
|
//
|
|
29266
|
-
if (
|
|
29328
|
+
if (fieldType === null) {
|
|
29329
|
+
// no valid data -- always return null value
|
|
29330
|
+
classifyByRecordId = function() {return nullValue;};
|
|
29331
|
+
} else if (method == 'non-adjacent') {
|
|
29267
29332
|
classifyByRecordId = getNonAdjacentClassifier(lyr, dataset, values);
|
|
29268
|
-
} else if (
|
|
29333
|
+
} else if (method == 'indexed') {
|
|
29269
29334
|
// data is pre-classified... just read the index from a field
|
|
29270
29335
|
classifyByValue = getIndexedClassifier(values, nullValue, opts);
|
|
29271
29336
|
} else if (method == 'categorical') {
|
|
@@ -34082,7 +34147,7 @@ ${svg}
|
|
|
34082
34147
|
isCentered = ['tmerc', 'etmerc'].includes(str);
|
|
34083
34148
|
proj4 = '+proj=' + str;
|
|
34084
34149
|
if (isConic2SP || isCentered) {
|
|
34085
|
-
bbox = getBBox(dataset);
|
|
34150
|
+
bbox = getBBox(dataset); // TODO: support projected datasets
|
|
34086
34151
|
decimals = getBoundsPrecisionForDisplay(bbox);
|
|
34087
34152
|
params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
|
|
34088
34153
|
proj4 += ' ' + params;
|
|
@@ -34287,14 +34352,17 @@ ${svg}
|
|
|
34287
34352
|
// old simplification data will not be optimal after reprojection;
|
|
34288
34353
|
// re-using for now to avoid error in web ui
|
|
34289
34354
|
zz = data.zz,
|
|
34355
|
+
z = arcs.getRetainedInterval(),
|
|
34290
34356
|
p;
|
|
34291
34357
|
|
|
34292
34358
|
for (var i=0, n=xx.length; i<n; i++) {
|
|
34293
34359
|
p = proj(xx[i], yy[i]);
|
|
34360
|
+
if (!p) error('Unprojectable point:', xx[i], yy[i]);
|
|
34294
34361
|
xx[i] = p[0];
|
|
34295
34362
|
yy[i] = p[1];
|
|
34296
34363
|
}
|
|
34297
34364
|
arcs.updateVertexData(data.nn, xx, yy, zz);
|
|
34365
|
+
arcs.setRetainedInterval(z);
|
|
34298
34366
|
}
|
|
34299
34367
|
|
|
34300
34368
|
function projectArcs2(arcs, proj) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mapshaper",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.100",
|
|
4
4
|
"description": "A tool for editing vector datasets for mapping and GIS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shapefile",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"files": [
|
|
36
36
|
"/bin/**",
|
|
37
37
|
"/www/**",
|
|
38
|
+
"!/www/basemap.js",
|
|
38
39
|
"!/www/nacis/",
|
|
39
40
|
"/mapshaper.js",
|
|
40
41
|
"!.DS_Store"
|
|
Binary file
|
|
Binary file
|
package/www/index.html
CHANGED
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<input type="text" value="label" class="clicktext" />
|
|
74
74
|
</div></div>
|
|
75
75
|
<div id="mode-buttons" class="page-header-buttons">
|
|
76
|
-
<span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="console-btn header-btn btn">Console</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
|
|
76
|
+
<span class="basemap-btn header-btn btn">Basemap</span><span class="separator"></span><span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="console-btn header-btn btn">Console</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
|
|
77
77
|
</div>
|
|
78
78
|
<div id="splash-buttons" class="page-header-buttons">
|
|
79
79
|
<a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a>
|
|
@@ -148,6 +148,18 @@
|
|
|
148
148
|
</div>
|
|
149
149
|
</div>
|
|
150
150
|
|
|
151
|
+
<div class="basemap-options main-area popup-dialog">
|
|
152
|
+
<div class="info-box">
|
|
153
|
+
<h3>Basemap options</h3>
|
|
154
|
+
<p class="basemap-note">Your data will be displayed using the Mercator projection.</p>
|
|
155
|
+
<p class="basemap-warning"></p>
|
|
156
|
+
<div class="basemap-styles"></div>
|
|
157
|
+
<div>
|
|
158
|
+
<div class="close-btn btn dialog-btn">Close</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
151
163
|
<div class="simplify-options main-area popup-dialog">
|
|
152
164
|
<div class="info-box">
|
|
153
165
|
<h3>Simplification menu</h3>
|
|
@@ -280,6 +292,7 @@ interface. Examples: "no-topology"
|
|
|
280
292
|
<div class="repair-btn text-btn colored-text">Repair</div>
|
|
281
293
|
</div>
|
|
282
294
|
<div class="map-layers"></div>
|
|
295
|
+
<div class="basemap-container"><div class="basemap"></div></div>
|
|
283
296
|
</div>
|
|
284
297
|
</div>
|
|
285
298
|
|
|
@@ -287,6 +300,7 @@ interface. Examples: "no-topology"
|
|
|
287
300
|
<div class="drop-area"></div>
|
|
288
301
|
</div>
|
|
289
302
|
|
|
303
|
+
<script src="basemap.js" type="text/javascript"></script>
|
|
290
304
|
<script src="zip.js" type="text/javascript"></script>
|
|
291
305
|
<script src="modules.js" type="text/javascript"></script>
|
|
292
306
|
<script src="mapshaper.js" type="text/javascript"></script>
|