mapshaper 0.7.11 → 0.7.13
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 +364 -114
- package/package.json +3 -3
- package/www/index.html +27 -29
- package/www/mapshaper-gui.js +367 -106
- package/www/mapshaper.js +364 -114
- package/www/page.css +247 -110
package/mapshaper.js
CHANGED
|
@@ -17490,7 +17490,7 @@
|
|
|
17490
17490
|
// higher-level mapshaper-svg.mjs (which would otherwise form a cycle).
|
|
17491
17491
|
|
|
17492
17492
|
function featureHasSvgSymbol(d) {
|
|
17493
|
-
return !!(d && (d['svg-symbol'] || d.r));
|
|
17493
|
+
return !!(d && (d['svg-symbol'] || d.r || d.icon || d['icon-size']));
|
|
17494
17494
|
}
|
|
17495
17495
|
|
|
17496
17496
|
function featureHasLabel(d) {
|
|
@@ -17763,6 +17763,9 @@
|
|
|
17763
17763
|
'font-style': null,
|
|
17764
17764
|
'font-stretch': null,
|
|
17765
17765
|
'font-weight': null,
|
|
17766
|
+
icon: null,
|
|
17767
|
+
'icon-color': 'color',
|
|
17768
|
+
'icon-size': 'number',
|
|
17766
17769
|
'label-text': null, // leaving this null
|
|
17767
17770
|
'letter-spacing': 'measure',
|
|
17768
17771
|
'line-height': 'measure',
|
|
@@ -18110,12 +18113,44 @@
|
|
|
18110
18113
|
if (d['svg-symbol']) {
|
|
18111
18114
|
return renderComplexSymbol(d['svg-symbol']);
|
|
18112
18115
|
}
|
|
18116
|
+
if (featureHasIcon(d)) {
|
|
18117
|
+
return renderIcon(d);
|
|
18118
|
+
}
|
|
18113
18119
|
if (d.r > 0) {
|
|
18114
18120
|
return circle(d);
|
|
18115
18121
|
}
|
|
18116
18122
|
return empty();
|
|
18117
18123
|
}
|
|
18118
18124
|
|
|
18125
|
+
function featureHasIcon(d) {
|
|
18126
|
+
return !!(d && (d.icon || d['icon-size'] || (d['icon-color'] && d.r > 0)));
|
|
18127
|
+
}
|
|
18128
|
+
|
|
18129
|
+
function renderIcon(d) {
|
|
18130
|
+
var type = d.icon || 'circle';
|
|
18131
|
+
var r = getIconRadius(d);
|
|
18132
|
+
if (r > 0 === false) return empty();
|
|
18133
|
+
if (type == 'circle') return circle(getIconStyleData(d, r));
|
|
18134
|
+
if (type == 'square') return square(getIconStyleData(d, r), 0, 0);
|
|
18135
|
+
if (type == 'ring') return ring(getIconStyleData(d, r), 0, 0);
|
|
18136
|
+
if (type == 'star') return star(getIconStyleData(d, r));
|
|
18137
|
+
message('Unknown icon type: ' + type);
|
|
18138
|
+
return empty();
|
|
18139
|
+
}
|
|
18140
|
+
|
|
18141
|
+
function getIconRadius(d) {
|
|
18142
|
+
if (d['icon-size'] > 0) return d['icon-size'] / 2;
|
|
18143
|
+
if (d.r > 0) return d.r;
|
|
18144
|
+
return 5;
|
|
18145
|
+
}
|
|
18146
|
+
|
|
18147
|
+
function getIconStyleData(d, r) {
|
|
18148
|
+
var o = utils.extend({}, d);
|
|
18149
|
+
o.r = r;
|
|
18150
|
+
o.fill = d['icon-color'] || d.fill || 'black';
|
|
18151
|
+
return o;
|
|
18152
|
+
}
|
|
18153
|
+
|
|
18119
18154
|
function renderComplexSymbol(sym, x, y) {
|
|
18120
18155
|
if (utils.isString(sym)) {
|
|
18121
18156
|
sym = JSON.parse(sym);
|
|
@@ -18190,10 +18225,44 @@
|
|
|
18190
18225
|
height: r * 2
|
|
18191
18226
|
}
|
|
18192
18227
|
};
|
|
18193
|
-
applyStyleAttributes(o, 'point', d);
|
|
18228
|
+
applyStyleAttributes(o, 'point', d, nonCirclePointFilter);
|
|
18229
|
+
return o;
|
|
18230
|
+
}
|
|
18231
|
+
|
|
18232
|
+
function ring(d, x, y) {
|
|
18233
|
+
var o = circle(d, x, y);
|
|
18234
|
+
o.properties.fill = 'none';
|
|
18235
|
+
o.properties.stroke = d.fill;
|
|
18236
|
+
if (!o.properties['stroke-width']) {
|
|
18237
|
+
o.properties['stroke-width'] = 1;
|
|
18238
|
+
}
|
|
18239
|
+
return o;
|
|
18240
|
+
}
|
|
18241
|
+
|
|
18242
|
+
function star(d) {
|
|
18243
|
+
var coords = getStarCoords$1(d.r);
|
|
18244
|
+
var o = importPolygon([coords]);
|
|
18245
|
+
applyStyleAttributes(o, 'point', d, nonCirclePointFilter);
|
|
18194
18246
|
return o;
|
|
18195
18247
|
}
|
|
18196
18248
|
|
|
18249
|
+
function nonCirclePointFilter(k) {
|
|
18250
|
+
return k != 'r';
|
|
18251
|
+
}
|
|
18252
|
+
|
|
18253
|
+
function getStarCoords$1(r) {
|
|
18254
|
+
var coords = [];
|
|
18255
|
+
var innerR = r * 0.42;
|
|
18256
|
+
var angle, len;
|
|
18257
|
+
for (var i=0; i<10; i++) {
|
|
18258
|
+
len = i % 2 === 0 ? r : innerR;
|
|
18259
|
+
angle = -Math.PI / 2 + i * Math.PI / 5;
|
|
18260
|
+
coords.push([roundToTenths(Math.cos(angle) * len), roundToTenths(Math.sin(angle) * len)]);
|
|
18261
|
+
}
|
|
18262
|
+
coords.push(coords[0].concat());
|
|
18263
|
+
return coords;
|
|
18264
|
+
}
|
|
18265
|
+
|
|
18197
18266
|
function line(d, x, y) {
|
|
18198
18267
|
var coords, o;
|
|
18199
18268
|
coords = [[x, y], [x + (d.dx || 0), y + (d.dy || 0)]];
|
|
@@ -18899,7 +18968,7 @@
|
|
|
18899
18968
|
|
|
18900
18969
|
// just a dot, no label or icon
|
|
18901
18970
|
function isSimpleCircle(rec) {
|
|
18902
|
-
return rec && (rec.r > 0 && !rec['svg-symbol'] && !rec['label-text']);
|
|
18971
|
+
return rec && (rec.r > 0 && !rec['svg-symbol'] && !rec['label-text'] && !rec.icon && !rec['icon-size'] && !rec['icon-color']);
|
|
18903
18972
|
}
|
|
18904
18973
|
|
|
18905
18974
|
function importMultiPoint(coords, rec) {
|
|
@@ -18927,6 +18996,8 @@
|
|
|
18927
18996
|
importPolygon: importPolygon
|
|
18928
18997
|
});
|
|
18929
18998
|
|
|
18999
|
+
var ILLUSTRATOR_PATH_VERTEX_LIMIT = 32000;
|
|
19000
|
+
|
|
18930
19001
|
//
|
|
18931
19002
|
function exportSVG(dataset, opts) {
|
|
18932
19003
|
var namespace = 'xmlns="http://www.w3.org/2000/svg"';
|
|
@@ -19091,6 +19162,7 @@ ${svg}
|
|
|
19091
19162
|
var d = utils.defaults({layers: [lyr]}, dataset);
|
|
19092
19163
|
var geojson = exportDatasetAsGeoJSON(d, opts);
|
|
19093
19164
|
var features = geojson.features || geojson.geometries || (geojson.type ? [geojson] : []);
|
|
19165
|
+
warnIfIllustratorPathLimitExceeded(lyr, features);
|
|
19094
19166
|
var children = importGeoJSONFeatures(features, opts);
|
|
19095
19167
|
// Drop empty placeholder <g/> elements (features whose geometry was null in the
|
|
19096
19168
|
// source data, collapsed during simplification, or otherwise produced no
|
|
@@ -19109,6 +19181,53 @@ ${svg}
|
|
|
19109
19181
|
return children;
|
|
19110
19182
|
}
|
|
19111
19183
|
|
|
19184
|
+
function warnIfIllustratorPathLimitExceeded(lyr, features) {
|
|
19185
|
+
var count = 0;
|
|
19186
|
+
var max = 0;
|
|
19187
|
+
if (lyr.geometry_type != 'polygon' && lyr.geometry_type != 'polyline') return;
|
|
19188
|
+
features.forEach(function(feature) {
|
|
19189
|
+
var geom = feature.geometry || feature;
|
|
19190
|
+
var n = countSvgPathVertices(geom);
|
|
19191
|
+
if (n > ILLUSTRATOR_PATH_VERTEX_LIMIT) {
|
|
19192
|
+
count++;
|
|
19193
|
+
max = Math.max(max, n);
|
|
19194
|
+
}
|
|
19195
|
+
});
|
|
19196
|
+
if (count > 0) {
|
|
19197
|
+
warn(utils.format(
|
|
19198
|
+
'%,d SVG path%s in layer "%s" contain%s more than %,d vertices; Adobe Illustrator may not import %s. The largest path has %,d vertices.',
|
|
19199
|
+
count,
|
|
19200
|
+
utils.pluralSuffix(count),
|
|
19201
|
+
lyr.name || '[unnamed]',
|
|
19202
|
+
count == 1 ? 's' : '',
|
|
19203
|
+
ILLUSTRATOR_PATH_VERTEX_LIMIT,
|
|
19204
|
+
count == 1 ? 'it' : 'them',
|
|
19205
|
+
max
|
|
19206
|
+
));
|
|
19207
|
+
}
|
|
19208
|
+
}
|
|
19209
|
+
|
|
19210
|
+
function countSvgPathVertices(geom) {
|
|
19211
|
+
var coords = geom && geom.coordinates;
|
|
19212
|
+
if (!coords) return 0;
|
|
19213
|
+
if (geom.type == 'LineString') return coords.length;
|
|
19214
|
+
if (geom.type == 'MultiLineString' || geom.type == 'Polygon') {
|
|
19215
|
+
return sumPathLengths(coords);
|
|
19216
|
+
}
|
|
19217
|
+
if (geom.type == 'MultiPolygon') {
|
|
19218
|
+
return coords.reduce(function(sum, polygon) {
|
|
19219
|
+
return sum + sumPathLengths(polygon);
|
|
19220
|
+
}, 0);
|
|
19221
|
+
}
|
|
19222
|
+
return 0;
|
|
19223
|
+
}
|
|
19224
|
+
|
|
19225
|
+
function sumPathLengths(paths) {
|
|
19226
|
+
return paths.reduce(function(sum, path) {
|
|
19227
|
+
return sum + path.length;
|
|
19228
|
+
}, 0);
|
|
19229
|
+
}
|
|
19230
|
+
|
|
19112
19231
|
function isEmptyPlaceholder(o) {
|
|
19113
19232
|
return o.tag == 'g' && (!o.children || o.children.length === 0);
|
|
19114
19233
|
}
|
|
@@ -19206,7 +19325,7 @@ ${svg}
|
|
|
19206
19325
|
// TODO: set fill="none" in SVG symbols, not on the container
|
|
19207
19326
|
// (setting fill=none on the container overrides the default black fill
|
|
19208
19327
|
// on paths, which may alter the appearance of SVG icons loaded from external URLs).
|
|
19209
|
-
if (lyr.geometry_type == 'polyline' ||
|
|
19328
|
+
if (lyr.geometry_type == 'polyline' || layerHasSvgSymbolField(lyr)) {
|
|
19210
19329
|
layerObj.properties.fill = 'none';
|
|
19211
19330
|
}
|
|
19212
19331
|
|
|
@@ -19229,6 +19348,15 @@ ${svg}
|
|
|
19229
19348
|
}
|
|
19230
19349
|
|
|
19231
19350
|
function layerHasSvgSymbols(lyr) {
|
|
19351
|
+
return lyr.geometry_type == 'point' && lyr.data && (
|
|
19352
|
+
lyr.data.fieldExists('svg-symbol') ||
|
|
19353
|
+
lyr.data.fieldExists('icon') ||
|
|
19354
|
+
lyr.data.fieldExists('icon-size') ||
|
|
19355
|
+
(lyr.data.fieldExists('icon-color') && lyr.data.fieldExists('r'))
|
|
19356
|
+
);
|
|
19357
|
+
}
|
|
19358
|
+
|
|
19359
|
+
function layerHasSvgSymbolField(lyr) {
|
|
19232
19360
|
return lyr.geometry_type == 'point' && lyr.data && lyr.data.fieldExists('svg-symbol');
|
|
19233
19361
|
}
|
|
19234
19362
|
|
|
@@ -28250,7 +28378,7 @@ ${svg}
|
|
|
28250
28378
|
|
|
28251
28379
|
};
|
|
28252
28380
|
|
|
28253
|
-
this.
|
|
28381
|
+
this.getHelpLines = function(cmdName) {
|
|
28254
28382
|
var helpCommands, singleCommand, lines;
|
|
28255
28383
|
if (cmdName) {
|
|
28256
28384
|
singleCommand = findCommandDefn(cmdName, getCommands());
|
|
@@ -28262,113 +28390,115 @@ ${svg}
|
|
|
28262
28390
|
helpCommands = getCommands().filter(function(cmd) {return cmd.name && cmd.describe || cmd.title;});
|
|
28263
28391
|
lines = getMultiCommandLines(helpCommands);
|
|
28264
28392
|
}
|
|
28393
|
+
return lines;
|
|
28394
|
+
};
|
|
28265
28395
|
|
|
28266
|
-
|
|
28267
|
-
|
|
28268
|
-
|
|
28269
|
-
var colWidth = calcColWidth(lines);
|
|
28270
|
-
var gutter = ' ';
|
|
28271
|
-
var indent = runningInBrowser() ? '' : ' ';
|
|
28272
|
-
var helpStr = lines.map(function(line) {
|
|
28273
|
-
if (Array.isArray(line)) {
|
|
28274
|
-
line = indent + utils.rpad(line[0], colWidth, ' ') + gutter + line[1];
|
|
28275
|
-
}
|
|
28276
|
-
return line;
|
|
28277
|
-
}).join('\n');
|
|
28278
|
-
return helpStr;
|
|
28279
|
-
}
|
|
28280
|
-
|
|
28281
|
-
function getSingleCommandLines(cmd) {
|
|
28282
|
-
var lines = [];
|
|
28283
|
-
var options = [];
|
|
28284
|
-
cmd.options.forEach(function(opt) {
|
|
28285
|
-
options = options.concat(getOptionLines(opt));
|
|
28286
|
-
});
|
|
28396
|
+
this.getHelpMessage = function(cmdName) {
|
|
28397
|
+
return formatLines(this.getHelpLines(cmdName));
|
|
28398
|
+
};
|
|
28287
28399
|
|
|
28288
|
-
|
|
28289
|
-
|
|
28290
|
-
|
|
28291
|
-
|
|
28400
|
+
function formatLines(lines) {
|
|
28401
|
+
var colWidth = calcColWidth(lines);
|
|
28402
|
+
var gutter = ' ';
|
|
28403
|
+
var indent = runningInBrowser() ? '' : ' ';
|
|
28404
|
+
var helpStr = lines.map(function(line) {
|
|
28405
|
+
if (Array.isArray(line)) {
|
|
28406
|
+
line = indent + utils.rpad(line[0], colWidth, ' ') + gutter + line[1];
|
|
28292
28407
|
}
|
|
28408
|
+
return line;
|
|
28409
|
+
}).join('\n');
|
|
28410
|
+
return helpStr;
|
|
28411
|
+
}
|
|
28293
28412
|
|
|
28294
|
-
|
|
28295
|
-
|
|
28296
|
-
|
|
28297
|
-
|
|
28298
|
-
|
|
28299
|
-
|
|
28300
|
-
|
|
28301
|
-
|
|
28302
|
-
|
|
28303
|
-
|
|
28304
|
-
|
|
28413
|
+
function getSingleCommandLines(cmd) {
|
|
28414
|
+
var lines = [];
|
|
28415
|
+
var options = [];
|
|
28416
|
+
cmd.options.forEach(function(opt) {
|
|
28417
|
+
options = options.concat(getOptionLines(opt));
|
|
28418
|
+
});
|
|
28419
|
+
|
|
28420
|
+
lines.push('COMMAND', getCommandLine(cmd));
|
|
28421
|
+
if (options.length > 0) {
|
|
28422
|
+
lines.push('', 'OPTIONS');
|
|
28423
|
+
lines = lines.concat(options);
|
|
28305
28424
|
}
|
|
28306
28425
|
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
lines.push([label, description]);
|
|
28317
|
-
} else {
|
|
28318
|
-
label = opt.name;
|
|
28319
|
-
if (opt.alias) label += ', ' + opt.alias;
|
|
28320
|
-
if (opt.type != 'flag' && !opt.assign_to) label += '=';
|
|
28321
|
-
lines.push([label, description]);
|
|
28322
|
-
}
|
|
28323
|
-
return lines;
|
|
28426
|
+
// examples
|
|
28427
|
+
if (cmd.examples) {
|
|
28428
|
+
lines.push('', 'EXAMPLE' + (cmd.examples.length > 1 ? 'S' : ''));
|
|
28429
|
+
cmd.examples.forEach(function(ex, i) {
|
|
28430
|
+
if (i > 0) lines.push('');
|
|
28431
|
+
ex.split('\n').forEach(function(line, i) {
|
|
28432
|
+
lines.push(' ' + line);
|
|
28433
|
+
});
|
|
28434
|
+
});
|
|
28324
28435
|
}
|
|
28436
|
+
return lines;
|
|
28437
|
+
}
|
|
28325
28438
|
|
|
28326
|
-
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
|
|
28439
|
+
function getOptionLines(opt, cmd) {
|
|
28440
|
+
var lines = [];
|
|
28441
|
+
var description = opt.describe;
|
|
28442
|
+
var label;
|
|
28443
|
+
if (!description) ; else if (opt.label) {
|
|
28444
|
+
lines.push([opt.label, description]);
|
|
28445
|
+
} else if (opt.DEFAULT) {
|
|
28446
|
+
label = opt.name + '=';
|
|
28447
|
+
lines.push(['<' + opt.name + '>', 'shortcut for ' + label]);
|
|
28448
|
+
lines.push([label, description]);
|
|
28449
|
+
} else {
|
|
28450
|
+
label = opt.name;
|
|
28451
|
+
if (opt.alias) label += ', ' + opt.alias;
|
|
28452
|
+
if (opt.type != 'flag' && !opt.assign_to) label += '=';
|
|
28453
|
+
lines.push([label, description]);
|
|
28330
28454
|
}
|
|
28455
|
+
return lines;
|
|
28456
|
+
}
|
|
28331
28457
|
|
|
28332
|
-
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28458
|
+
function getCommandLine(cmd) {
|
|
28459
|
+
var name = cmd.name ? "-" + cmd.name : '';
|
|
28460
|
+
if (cmd.alias) name += ', -' + cmd.alias;
|
|
28461
|
+
return [name, cmd.describe || '(undocumented command)'];
|
|
28462
|
+
}
|
|
28336
28463
|
|
|
28337
|
-
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28341
|
-
} else {
|
|
28342
|
-
lines.push(getCommandLine(cmd));
|
|
28343
|
-
}
|
|
28344
|
-
});
|
|
28464
|
+
function getMultiCommandLines(commands) {
|
|
28465
|
+
var lines = [];
|
|
28466
|
+
// usage
|
|
28467
|
+
if (_usage) lines.push(_usage);
|
|
28345
28468
|
|
|
28346
|
-
|
|
28347
|
-
|
|
28348
|
-
|
|
28349
|
-
|
|
28350
|
-
|
|
28351
|
-
|
|
28469
|
+
// list of commands
|
|
28470
|
+
commands.forEach(function(cmd) {
|
|
28471
|
+
if (cmd.title) {
|
|
28472
|
+
lines.push('', cmd.title);
|
|
28473
|
+
} else {
|
|
28474
|
+
lines.push(getCommandLine(cmd));
|
|
28352
28475
|
}
|
|
28476
|
+
});
|
|
28353
28477
|
|
|
28354
|
-
|
|
28355
|
-
|
|
28356
|
-
|
|
28357
|
-
|
|
28358
|
-
|
|
28478
|
+
// examples
|
|
28479
|
+
if (_examples.length > 0) {
|
|
28480
|
+
lines.push('', 'Examples');
|
|
28481
|
+
_examples.forEach(function(str) {
|
|
28482
|
+
lines.push('', str);
|
|
28483
|
+
});
|
|
28359
28484
|
}
|
|
28360
28485
|
|
|
28361
|
-
|
|
28362
|
-
|
|
28363
|
-
|
|
28364
|
-
lines.forEach(function(line) {
|
|
28365
|
-
if (Array.isArray(line)) {
|
|
28366
|
-
w = Math.max(w, line[0].length);
|
|
28367
|
-
}
|
|
28368
|
-
});
|
|
28369
|
-
return w;
|
|
28486
|
+
// note
|
|
28487
|
+
if (_note) {
|
|
28488
|
+
lines.push('', _note);
|
|
28370
28489
|
}
|
|
28371
|
-
|
|
28490
|
+
return lines;
|
|
28491
|
+
}
|
|
28492
|
+
|
|
28493
|
+
function calcColWidth(lines) {
|
|
28494
|
+
var w = 0;
|
|
28495
|
+
lines.forEach(function(line) {
|
|
28496
|
+
if (Array.isArray(line)) {
|
|
28497
|
+
w = Math.max(w, line[0].length);
|
|
28498
|
+
}
|
|
28499
|
+
});
|
|
28500
|
+
return w;
|
|
28501
|
+
}
|
|
28372
28502
|
|
|
28373
28503
|
function getCommands() {
|
|
28374
28504
|
return _commands.map(function(cmd) {
|
|
@@ -30488,6 +30618,15 @@ ${svg}
|
|
|
30488
30618
|
.option('r', {
|
|
30489
30619
|
describe: 'symbol radius (set this to export points as circles)',
|
|
30490
30620
|
})
|
|
30621
|
+
.option('icon', {
|
|
30622
|
+
describe: 'point icon shape; one of: circle, square, ring, star'
|
|
30623
|
+
})
|
|
30624
|
+
.option('icon-size', {
|
|
30625
|
+
describe: 'point icon size in pixels'
|
|
30626
|
+
})
|
|
30627
|
+
.option('icon-color', {
|
|
30628
|
+
describe: 'point icon color (defaults to fill color, then black)'
|
|
30629
|
+
})
|
|
30491
30630
|
.option('label-text', {
|
|
30492
30631
|
describe: 'label text (set this to export points as labels)'
|
|
30493
30632
|
})
|
|
@@ -44055,7 +44194,14 @@ ${svg}
|
|
|
44055
44194
|
}]
|
|
44056
44195
|
};
|
|
44057
44196
|
}
|
|
44058
|
-
|
|
44197
|
+
if (runningInBrowser()) {
|
|
44198
|
+
message({
|
|
44199
|
+
type: 'mapshaper-console-info',
|
|
44200
|
+
layers: arr
|
|
44201
|
+
});
|
|
44202
|
+
} else {
|
|
44203
|
+
message(formatInfo(arr));
|
|
44204
|
+
}
|
|
44059
44205
|
};
|
|
44060
44206
|
|
|
44061
44207
|
cmd.printInfo = cmd.info; // old name
|
|
@@ -48764,7 +48910,7 @@ ${svg}
|
|
|
48764
48910
|
return layerHasGeometry(lyr) && !layerIsFullyEnclosed(lyr, dataset, clipData);
|
|
48765
48911
|
});
|
|
48766
48912
|
if (layers.length > 0) {
|
|
48767
|
-
clipLayersInPlace(layers, clipData, dataset, 'clip');
|
|
48913
|
+
clipLayersInPlace(layers, clipData, dataset, 'clip', getInternalClipOpts());
|
|
48768
48914
|
return true;
|
|
48769
48915
|
}
|
|
48770
48916
|
return false;
|
|
@@ -48803,13 +48949,21 @@ ${svg}
|
|
|
48803
48949
|
}
|
|
48804
48950
|
|
|
48805
48951
|
function datasetCrossesLon(dataset, lon) {
|
|
48806
|
-
var crosses =
|
|
48807
|
-
dataset.
|
|
48808
|
-
|
|
48809
|
-
|
|
48810
|
-
|
|
48952
|
+
var crosses = false;
|
|
48953
|
+
dataset.layers.filter(layerHasPaths).forEach(function(lyr) {
|
|
48954
|
+
if (crosses) return;
|
|
48955
|
+
lyr.shapes.forEach(function(shp) {
|
|
48956
|
+
if (crosses || !shp) return;
|
|
48957
|
+
forEachSegmentInShape(shp, dataset.arcs, function(i, j, xx, yy) {
|
|
48958
|
+
var ax = xx[i],
|
|
48959
|
+
bx = xx[j];
|
|
48960
|
+
if (ax <= lon && bx >= lon || ax >= lon && bx <= lon) {
|
|
48961
|
+
crosses = true;
|
|
48962
|
+
}
|
|
48963
|
+
});
|
|
48964
|
+
});
|
|
48811
48965
|
});
|
|
48812
|
-
return crosses
|
|
48966
|
+
return crosses;
|
|
48813
48967
|
}
|
|
48814
48968
|
|
|
48815
48969
|
function insertVerticalCut(dataset, lon) {
|
|
@@ -48820,29 +48974,38 @@ ${svg}
|
|
|
48820
48974
|
// densify (so cut line can curve, e.g. Cupola projection)
|
|
48821
48975
|
var geojson = bboxToPolygon(bbox, {interval: 0.5});
|
|
48822
48976
|
var clip = importGeoJSON(geojson);
|
|
48823
|
-
clipLayersInPlace(pathLayers, clip, dataset, 'erase');
|
|
48977
|
+
clipLayersInPlace(pathLayers, clip, dataset, 'erase', getInternalClipOpts());
|
|
48824
48978
|
}
|
|
48825
48979
|
|
|
48826
|
-
|
|
48980
|
+
function getInternalClipOpts() {
|
|
48981
|
+
return {no_cleanup: true, no_warn: true};
|
|
48982
|
+
}
|
|
48983
|
+
|
|
48984
|
+
// Converts a Proj.4 projection name (e.g. lcc, tmerc, utm) to a Proj.4 string
|
|
48827
48985
|
// by picking parameters that are appropriate to the extent of the dataset
|
|
48828
48986
|
// being projected (e.g. standard parallels, longitude of origin)
|
|
48829
|
-
// Works for lcc, aea, tmerc, etc.
|
|
48987
|
+
// Works for lcc, aea, tmerc, utm, etc.
|
|
48830
48988
|
// TODO: add more projections
|
|
48831
48989
|
//
|
|
48832
48990
|
function expandProjDefn(str, dataset, targetLayers) {
|
|
48833
48991
|
var mproj = require$1('mproj');
|
|
48834
|
-
var proj4, params, bbox, isConic2SP, isCentered, decimals;
|
|
48992
|
+
var proj4, params, bbox, isConic2SP, isCentered, isUtm, decimals;
|
|
48835
48993
|
if (str in mproj.internal.pj_list === false) {
|
|
48836
48994
|
// not a bare projection code -- assume valid projection string in other format
|
|
48837
48995
|
return str;
|
|
48838
48996
|
}
|
|
48839
48997
|
isConic2SP = ['lcc', 'aea'].includes(str);
|
|
48840
48998
|
isCentered = ['tmerc', 'etmerc'].includes(str);
|
|
48999
|
+
isUtm = str == 'utm';
|
|
48841
49000
|
proj4 = '+proj=' + str;
|
|
48842
|
-
if (isConic2SP || isCentered) {
|
|
49001
|
+
if (isConic2SP || isCentered || isUtm) {
|
|
48843
49002
|
bbox = getBBox(dataset, targetLayers); // TODO: support projected datasets
|
|
48844
49003
|
decimals = getBoundsPrecisionForDisplay(bbox);
|
|
48845
|
-
|
|
49004
|
+
if (isUtm) {
|
|
49005
|
+
params = getUtmParams(bbox);
|
|
49006
|
+
} else {
|
|
49007
|
+
params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
|
|
49008
|
+
}
|
|
48846
49009
|
proj4 += ' ' + params;
|
|
48847
49010
|
message(`Converted "${str}" to "${proj4}"`);
|
|
48848
49011
|
}
|
|
@@ -48858,7 +49021,77 @@ ${svg}
|
|
|
48858
49021
|
if (!isLatLngCRS(getDatasetCRS(dataset))) {
|
|
48859
49022
|
stop$1('Expected unprojected data');
|
|
48860
49023
|
}
|
|
48861
|
-
return
|
|
49024
|
+
return getAutoFitBBox(source);
|
|
49025
|
+
}
|
|
49026
|
+
|
|
49027
|
+
function getAutoFitBBox(dataset) {
|
|
49028
|
+
var bbox = getDatasetBounds(dataset).toArray();
|
|
49029
|
+
if (bbox[2] - bbox[0] > 180) {
|
|
49030
|
+
bbox = getWrappedBBox(dataset, bbox) || bbox;
|
|
49031
|
+
}
|
|
49032
|
+
return bbox;
|
|
49033
|
+
}
|
|
49034
|
+
|
|
49035
|
+
function getWrappedBBox(dataset, bbox) {
|
|
49036
|
+
var xmaxW = -Infinity,
|
|
49037
|
+
xminE = Infinity, xmaxE = -Infinity,
|
|
49038
|
+
ymin = bbox[1], ymax = bbox[3],
|
|
49039
|
+
gap;
|
|
49040
|
+
|
|
49041
|
+
// Detect dateline clustering with a streaming east/west split. The gap
|
|
49042
|
+
// between the two boxes can only shrink as more coordinates are scanned.
|
|
49043
|
+
forEachDatasetCoord(dataset, function(x) {
|
|
49044
|
+
if (x < 0) {
|
|
49045
|
+
if (x > xmaxW) xmaxW = x;
|
|
49046
|
+
} else {
|
|
49047
|
+
if (x < xminE) xminE = x;
|
|
49048
|
+
if (x > xmaxE) xmaxE = x;
|
|
49049
|
+
}
|
|
49050
|
+
if (xmaxW > -Infinity && xmaxE > -Infinity) {
|
|
49051
|
+
gap = xminE - xmaxW;
|
|
49052
|
+
return gap > 180;
|
|
49053
|
+
}
|
|
49054
|
+
});
|
|
49055
|
+
|
|
49056
|
+
if (xmaxW == -Infinity || xmaxE == -Infinity) return null;
|
|
49057
|
+
if (xminE - xmaxW <= 180) return null;
|
|
49058
|
+
return [xminE, ymin, xmaxW + 360, ymax];
|
|
49059
|
+
}
|
|
49060
|
+
|
|
49061
|
+
function forEachDatasetCoord(dataset, cb) {
|
|
49062
|
+
var arcs = dataset.arcs;
|
|
49063
|
+
var usedArcs = arcs ? new Uint8Array(arcs.size()) : null;
|
|
49064
|
+
var keepGoing = true;
|
|
49065
|
+
dataset.layers.forEach(function(lyr) {
|
|
49066
|
+
if (!keepGoing) return;
|
|
49067
|
+
if (lyr.geometry_type == 'point') {
|
|
49068
|
+
keepGoing = scanPointCoords(lyr.shapes, cb);
|
|
49069
|
+
} else if (arcs && (lyr.geometry_type == 'polygon' || lyr.geometry_type == 'polyline')) {
|
|
49070
|
+
forEachArcId(lyr.shapes, function(id) {
|
|
49071
|
+
var absId, iter;
|
|
49072
|
+
if (!keepGoing) return;
|
|
49073
|
+
absId = id < 0 ? ~id : id;
|
|
49074
|
+
if (usedArcs[absId]) return;
|
|
49075
|
+
usedArcs[absId] = 1;
|
|
49076
|
+
iter = arcs.getArcIter(absId);
|
|
49077
|
+
while (keepGoing && iter.hasNext()) {
|
|
49078
|
+
keepGoing = cb(iter.x, iter.y) !== false;
|
|
49079
|
+
}
|
|
49080
|
+
});
|
|
49081
|
+
}
|
|
49082
|
+
});
|
|
49083
|
+
}
|
|
49084
|
+
|
|
49085
|
+
function scanPointCoords(shapes, cb) {
|
|
49086
|
+
var shp, p;
|
|
49087
|
+
for (var i=0, n=shapes.length; i<n; i++) {
|
|
49088
|
+
shp = shapes[i];
|
|
49089
|
+
for (var j=0, m=shp ? shp.length : 0; j<m; j++) {
|
|
49090
|
+
p = shp[j];
|
|
49091
|
+
if (cb(p[0], p[1]) === false) return false;
|
|
49092
|
+
}
|
|
49093
|
+
}
|
|
49094
|
+
return true;
|
|
48862
49095
|
}
|
|
48863
49096
|
|
|
48864
49097
|
// See: Savric & Jenny, "Automating the selection of standard parallels for conic map projections"
|
|
@@ -48877,11 +49110,21 @@ ${svg}
|
|
|
48877
49110
|
return `+lon_0=${ cx.toFixed(decimals) } +lat_0=${ cy.toFixed(decimals) }`;
|
|
48878
49111
|
}
|
|
48879
49112
|
|
|
49113
|
+
function getUtmParams(bbox) {
|
|
49114
|
+
var cx = (bbox[0] + bbox[2]) / 2;
|
|
49115
|
+
var cy = (bbox[1] + bbox[3]) / 2;
|
|
49116
|
+
var zone = Math.floor((cx + 180) / 6) + 1;
|
|
49117
|
+
zone = Math.max(1, Math.min(60, zone));
|
|
49118
|
+
return `+zone=${ zone }` + (cy < 0 ? ' +south' : '');
|
|
49119
|
+
}
|
|
49120
|
+
|
|
48880
49121
|
var ProjectionParams = /*#__PURE__*/Object.freeze({
|
|
48881
49122
|
__proto__: null,
|
|
48882
49123
|
expandProjDefn: expandProjDefn,
|
|
49124
|
+
getAutoFitBBox: getAutoFitBBox,
|
|
48883
49125
|
getCenterParams: getCenterParams,
|
|
48884
|
-
getConicParams: getConicParams
|
|
49126
|
+
getConicParams: getConicParams,
|
|
49127
|
+
getUtmParams: getUtmParams
|
|
48885
49128
|
});
|
|
48886
49129
|
|
|
48887
49130
|
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
@@ -49280,8 +49523,15 @@ ${svg}
|
|
|
49280
49523
|
}
|
|
49281
49524
|
|
|
49282
49525
|
cmd.printHelp = function(opts) {
|
|
49283
|
-
var
|
|
49284
|
-
|
|
49526
|
+
var parser = getOptionParser();
|
|
49527
|
+
if (runningInBrowser()) {
|
|
49528
|
+
message({
|
|
49529
|
+
type: 'mapshaper-console-help',
|
|
49530
|
+
lines: parser.getHelpLines(opts.command)
|
|
49531
|
+
});
|
|
49532
|
+
} else {
|
|
49533
|
+
print(parser.getHelpMessage(opts.command));
|
|
49534
|
+
}
|
|
49285
49535
|
};
|
|
49286
49536
|
|
|
49287
49537
|
function stopJob(job) {
|
|
@@ -55431,7 +55681,7 @@ ${svg}
|
|
|
55431
55681
|
});
|
|
55432
55682
|
}
|
|
55433
55683
|
|
|
55434
|
-
var version = "0.7.
|
|
55684
|
+
var version = "0.7.13";
|
|
55435
55685
|
|
|
55436
55686
|
// Parse command line args into commands and run them
|
|
55437
55687
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mapshaper",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.13",
|
|
4
4
|
"description": "A tool for editing vector datasets for mapping and GIS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shapefile",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"docs": "node build-docs.mjs",
|
|
29
29
|
"roadmap": "node build-roadmap.mjs",
|
|
30
30
|
"lint": "eslint --ext mjs src/",
|
|
31
|
-
"prepublishOnly": "npm test
|
|
31
|
+
"prepublishOnly": "npm test && npm run test:browser && ./pre-publish",
|
|
32
32
|
"postpublish": "./release_web_ui; ./release_github_version",
|
|
33
33
|
"dev": "rollup --config --watch",
|
|
34
|
-
"test:browser": "playwright test"
|
|
34
|
+
"test:browser": "playwright test --fully-parallel --workers=6"
|
|
35
35
|
},
|
|
36
36
|
"main": "./mapshaper.js",
|
|
37
37
|
"files": [
|