mapshaper 0.6.63 → 0.6.66
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 +601 -385
- package/package.json +1 -1
- package/www/index.html +4 -3
- package/www/mapshaper-gui.js +495 -245
- package/www/mapshaper.js +601 -385
- package/www/page.css +16 -1
package/mapshaper.js
CHANGED
|
@@ -4010,6 +4010,59 @@
|
|
|
4010
4010
|
return applyFieldOrder(names, order);
|
|
4011
4011
|
}
|
|
4012
4012
|
|
|
4013
|
+
|
|
4014
|
+
function parseUnknownType(str) {
|
|
4015
|
+
var val = getInputParser('number')(str);
|
|
4016
|
+
if (val !== null) return val;
|
|
4017
|
+
val = getInputParser('object')(str);
|
|
4018
|
+
if (val !== null) return val;
|
|
4019
|
+
return str;
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
// used by GUI data editing
|
|
4023
|
+
function getInputParser(type) {
|
|
4024
|
+
return inputParsers[type || 'multiple'];
|
|
4025
|
+
}
|
|
4026
|
+
|
|
4027
|
+
var inputParsers = {
|
|
4028
|
+
date: function(raw) {
|
|
4029
|
+
var d = new Date(raw);
|
|
4030
|
+
return isNaN(+d) ? null : d;
|
|
4031
|
+
},
|
|
4032
|
+
string: function(raw) {
|
|
4033
|
+
return raw;
|
|
4034
|
+
},
|
|
4035
|
+
number: function(raw) {
|
|
4036
|
+
var val = Number(raw);
|
|
4037
|
+
if (raw == 'NaN') {
|
|
4038
|
+
val = NaN;
|
|
4039
|
+
} else if (isNaN(val)) {
|
|
4040
|
+
val = null;
|
|
4041
|
+
}
|
|
4042
|
+
return val;
|
|
4043
|
+
},
|
|
4044
|
+
object: function(raw) {
|
|
4045
|
+
var val = null;
|
|
4046
|
+
try {
|
|
4047
|
+
val = JSON.parse(raw);
|
|
4048
|
+
} catch(e) {}
|
|
4049
|
+
return val;
|
|
4050
|
+
},
|
|
4051
|
+
boolean: function(raw) {
|
|
4052
|
+
var val = null;
|
|
4053
|
+
if (raw == 'true') {
|
|
4054
|
+
val = true;
|
|
4055
|
+
} else if (raw == 'false') {
|
|
4056
|
+
val = false;
|
|
4057
|
+
}
|
|
4058
|
+
return val;
|
|
4059
|
+
},
|
|
4060
|
+
multiple: function(raw) {
|
|
4061
|
+
var val = Number(raw);
|
|
4062
|
+
return isNaN(val) ? raw : val;
|
|
4063
|
+
}
|
|
4064
|
+
};
|
|
4065
|
+
|
|
4013
4066
|
var DataUtils = /*#__PURE__*/Object.freeze({
|
|
4014
4067
|
__proto__: null,
|
|
4015
4068
|
copyRecord: copyRecord,
|
|
@@ -4024,7 +4077,9 @@
|
|
|
4024
4077
|
getUniqFieldValues: getUniqFieldValues,
|
|
4025
4078
|
applyFieldOrder: applyFieldOrder,
|
|
4026
4079
|
getFirstNonEmptyRecord: getFirstNonEmptyRecord,
|
|
4027
|
-
findFieldNames: findFieldNames
|
|
4080
|
+
findFieldNames: findFieldNames,
|
|
4081
|
+
parseUnknownType: parseUnknownType,
|
|
4082
|
+
getInputParser: getInputParser
|
|
4028
4083
|
});
|
|
4029
4084
|
|
|
4030
4085
|
function DataTable(obj) {
|
|
@@ -4122,6 +4177,30 @@
|
|
|
4122
4177
|
}
|
|
4123
4178
|
};
|
|
4124
4179
|
|
|
4180
|
+
// TODO: make this stricter (could give false positive on some degenerate paths)
|
|
4181
|
+
function pathIsRectangle(ids, arcs) {
|
|
4182
|
+
var bbox = arcs.getSimpleShapeBounds(ids).toArray();
|
|
4183
|
+
var iter = arcs.getShapeIter(ids);
|
|
4184
|
+
while (iter.hasNext()) {
|
|
4185
|
+
if (iter.x != bbox[0] && iter.x != bbox[2] ||
|
|
4186
|
+
iter.y != bbox[1] && iter.y != bbox[3]) {
|
|
4187
|
+
return false;
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
return true;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
function bboxToCoords(bbox) {
|
|
4194
|
+
return [[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]],
|
|
4195
|
+
[bbox[2], bbox[1]], [bbox[0], bbox[1]]];
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
var RectangleUtils = /*#__PURE__*/Object.freeze({
|
|
4199
|
+
__proto__: null,
|
|
4200
|
+
pathIsRectangle: pathIsRectangle,
|
|
4201
|
+
bboxToCoords: bboxToCoords
|
|
4202
|
+
});
|
|
4203
|
+
|
|
4125
4204
|
// Insert a column of values into a (new or existing) data field
|
|
4126
4205
|
function insertFieldValues(lyr, fieldName, values) {
|
|
4127
4206
|
var size = getFeatureCount(lyr) || values.length,
|
|
@@ -4162,6 +4241,19 @@
|
|
|
4162
4241
|
return lyr.geometry_type == 'point' && layerHasNonNullShapes(lyr);
|
|
4163
4242
|
}
|
|
4164
4243
|
|
|
4244
|
+
function layerIsRectangle(lyr, arcs) {
|
|
4245
|
+
return layerOnlyHasRectangles(lyr, arcs) && lyr.shapes.length == 1;
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
function layerOnlyHasRectangles(lyr, arcs) {
|
|
4249
|
+
if (!layerHasPaths(lyr)) return false;
|
|
4250
|
+
if (countMultiPartFeatures(lyr) > 0) return false;
|
|
4251
|
+
return lyr.shapes.every(function(shp) {
|
|
4252
|
+
if (!shp) return true;
|
|
4253
|
+
return pathIsRectangle(shp[0], arcs);
|
|
4254
|
+
});
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4165
4257
|
function layerHasNonNullShapes(lyr) {
|
|
4166
4258
|
return utils.some(lyr.shapes || [], function(shp) {
|
|
4167
4259
|
return !!shp;
|
|
@@ -4405,6 +4497,8 @@
|
|
|
4405
4497
|
layerHasGeometry: layerHasGeometry,
|
|
4406
4498
|
layerHasPaths: layerHasPaths,
|
|
4407
4499
|
layerHasPoints: layerHasPoints,
|
|
4500
|
+
layerIsRectangle: layerIsRectangle,
|
|
4501
|
+
layerOnlyHasRectangles: layerOnlyHasRectangles,
|
|
4408
4502
|
layerHasNonNullShapes: layerHasNonNullShapes,
|
|
4409
4503
|
deleteFeatureById: deleteFeatureById,
|
|
4410
4504
|
transformPointsInLayer: transformPointsInLayer,
|
|
@@ -5002,10 +5096,10 @@
|
|
|
5002
5096
|
// x, y: a point location in projected coordinates
|
|
5003
5097
|
// Returns k, the ratio of coordinate distance to distance on the ground
|
|
5004
5098
|
function getScaleFactorAtXY(x, y, crs) {
|
|
5005
|
-
var dist = 1;
|
|
5099
|
+
var dist = 1 / crs.to_meter;
|
|
5006
5100
|
var lp = mproj.pj_inv_deg({x: x, y: y}, crs);
|
|
5007
5101
|
var lp2 = mproj.pj_inv_deg({x: x + dist, y: y}, crs);
|
|
5008
|
-
var k =
|
|
5102
|
+
var k = 1 / geom.greatCircleDistance(lp.lam, lp.phi, lp2.lam, lp2.phi);
|
|
5009
5103
|
return k;
|
|
5010
5104
|
}
|
|
5011
5105
|
|
|
@@ -11058,7 +11152,7 @@
|
|
|
11058
11152
|
// File looks like an importable file type
|
|
11059
11153
|
// name: filename or path
|
|
11060
11154
|
function looksLikeImportableFile(name) {
|
|
11061
|
-
return !!guessInputFileType(name);
|
|
11155
|
+
return !!guessInputFileType(name) || isImportableAsBinary(name);
|
|
11062
11156
|
}
|
|
11063
11157
|
|
|
11064
11158
|
// File looks like a directly readable data file type
|
|
@@ -13301,6 +13395,18 @@
|
|
|
13301
13395
|
miles: 1609.344 // International Statute Mile
|
|
13302
13396
|
};
|
|
13303
13397
|
|
|
13398
|
+
// str: display size in px, pt or in
|
|
13399
|
+
// using: 72pt per inch, 1pt per pixel.
|
|
13400
|
+
function parseSizeParam(str) {
|
|
13401
|
+
var num = parseFloat(str),
|
|
13402
|
+
units = /px$/.test(str) && 'px' || /pt$/.test(str) && 'pt' ||
|
|
13403
|
+
/in$/.test(str) && 'in' || !isNaN(+str) && 'px' || null;
|
|
13404
|
+
if (isNaN(num) || !units) {
|
|
13405
|
+
stop('Invalid size:', str);
|
|
13406
|
+
}
|
|
13407
|
+
return units == 'in' && num * 72 || num;
|
|
13408
|
+
}
|
|
13409
|
+
|
|
13304
13410
|
// Return coeff. for converting a distance measure to dataset coordinates
|
|
13305
13411
|
// @paramUnits: units code of distance param, or null if units are not specified
|
|
13306
13412
|
// @crs: Proj.4 CRS object, or null (unknown latlong CRS);
|
|
@@ -13444,6 +13550,7 @@
|
|
|
13444
13550
|
|
|
13445
13551
|
var Units = /*#__PURE__*/Object.freeze({
|
|
13446
13552
|
__proto__: null,
|
|
13553
|
+
parseSizeParam: parseSizeParam,
|
|
13447
13554
|
getIntervalConversionFactor: getIntervalConversionFactor,
|
|
13448
13555
|
parseMeasure: parseMeasure,
|
|
13449
13556
|
parseMeasure2: parseMeasure2,
|
|
@@ -18121,7 +18228,7 @@
|
|
|
18121
18228
|
var frameLyr = findFrameLayerInDataset(dataset);
|
|
18122
18229
|
var frameData;
|
|
18123
18230
|
if (frameLyr) {
|
|
18124
|
-
frameData =
|
|
18231
|
+
frameData = getFrameLayerData(frameLyr, dataset);
|
|
18125
18232
|
} else {
|
|
18126
18233
|
frameData = calcFrameData(dataset, exportOpts);
|
|
18127
18234
|
}
|
|
@@ -18129,6 +18236,25 @@
|
|
|
18129
18236
|
return frameData;
|
|
18130
18237
|
}
|
|
18131
18238
|
|
|
18239
|
+
|
|
18240
|
+
function getFrameLayerData(lyr, dataset) {
|
|
18241
|
+
var bounds = getLayerBounds(lyr, dataset.arcs);
|
|
18242
|
+
var d = lyr.data.getReadOnlyRecordAt(0);
|
|
18243
|
+
var w = d.width || 800;
|
|
18244
|
+
var h = w * bounds.height() / bounds.width();
|
|
18245
|
+
return {
|
|
18246
|
+
type: 'frame',
|
|
18247
|
+
width: w,
|
|
18248
|
+
height: h,
|
|
18249
|
+
bbox: bounds.toArray()
|
|
18250
|
+
};
|
|
18251
|
+
}
|
|
18252
|
+
|
|
18253
|
+
// export function getFrameLayerData(lyr) {
|
|
18254
|
+
// return lyr.data && lyr.data.getReadOnlyRecordAt(0);
|
|
18255
|
+
// }
|
|
18256
|
+
|
|
18257
|
+
|
|
18132
18258
|
function calcFrameData(dataset, opts) {
|
|
18133
18259
|
var bounds;
|
|
18134
18260
|
if (opts.svg_bbox) {
|
|
@@ -18146,10 +18272,6 @@
|
|
|
18146
18272
|
};
|
|
18147
18273
|
}
|
|
18148
18274
|
|
|
18149
|
-
function getFrameLayerData(lyr) {
|
|
18150
|
-
return lyr.data && lyr.data.getReadOnlyRecordAt(0);
|
|
18151
|
-
}
|
|
18152
|
-
|
|
18153
18275
|
// Used by mapshaper-frame and mapshaper-pixel-transform. TODO: refactor
|
|
18154
18276
|
function getFrameSize(bounds, opts) {
|
|
18155
18277
|
var aspectRatio = bounds.width() / bounds.height();
|
|
@@ -18165,26 +18287,27 @@
|
|
|
18165
18287
|
|
|
18166
18288
|
|
|
18167
18289
|
// @lyr dataset layer
|
|
18168
|
-
function isFrameLayer(lyr) {
|
|
18169
|
-
return getFurnitureLayerType(lyr) == 'frame'
|
|
18290
|
+
function isFrameLayer(lyr, dataset) {
|
|
18291
|
+
return getFurnitureLayerType(lyr) == 'frame' &&
|
|
18292
|
+
layerIsRectangle(lyr, dataset.arcs);
|
|
18170
18293
|
}
|
|
18171
18294
|
|
|
18172
18295
|
function findFrameLayerInDataset(dataset) {
|
|
18173
18296
|
return utils.find(dataset.layers, function(lyr) {
|
|
18174
|
-
return isFrameLayer(lyr);
|
|
18297
|
+
return isFrameLayer(lyr, dataset);
|
|
18175
18298
|
});
|
|
18176
18299
|
}
|
|
18177
18300
|
|
|
18178
18301
|
function findFrameDataset(catalog) {
|
|
18179
18302
|
var target = utils.find(catalog.getLayers(), function(o) {
|
|
18180
|
-
return isFrameLayer(o.layer);
|
|
18303
|
+
return isFrameLayer(o.layer, o.dataset);
|
|
18181
18304
|
});
|
|
18182
18305
|
return target ? target.dataset : null;
|
|
18183
18306
|
}
|
|
18184
18307
|
|
|
18185
18308
|
function findFrameLayer(catalog) {
|
|
18186
18309
|
var target = utils.find(catalog.getLayers(), function(o) {
|
|
18187
|
-
return isFrameLayer(o.layer);
|
|
18310
|
+
return isFrameLayer(o.layer, o.dataset);
|
|
18188
18311
|
});
|
|
18189
18312
|
return target && target.layer || null;
|
|
18190
18313
|
}
|
|
@@ -18322,7 +18445,6 @@
|
|
|
18322
18445
|
var FrameData = /*#__PURE__*/Object.freeze({
|
|
18323
18446
|
__proto__: null,
|
|
18324
18447
|
getFrameData: getFrameData,
|
|
18325
|
-
getFrameLayerData: getFrameLayerData,
|
|
18326
18448
|
getFrameSize: getFrameSize,
|
|
18327
18449
|
findFrameLayerInDataset: findFrameLayerInDataset,
|
|
18328
18450
|
findFrameDataset: findFrameDataset,
|
|
@@ -18825,6 +18947,10 @@
|
|
|
18825
18947
|
if (filter && !filter(fields[i])) continue;
|
|
18826
18948
|
setAttribute(svgObj, fields[i], rec[fields[i]]);
|
|
18827
18949
|
}
|
|
18950
|
+
// kludge to prevent default black fill on polygons with stroke styles
|
|
18951
|
+
if ((symType == 'polygon' || symType == 'circle') && rec.stroke && !rec.fill) {
|
|
18952
|
+
setAttribute(svgObj, 'fill', 'none');
|
|
18953
|
+
}
|
|
18828
18954
|
}
|
|
18829
18955
|
|
|
18830
18956
|
function setAttribute(obj, k, v) {
|
|
@@ -19407,99 +19533,136 @@
|
|
|
19407
19533
|
}
|
|
19408
19534
|
|
|
19409
19535
|
// TODO: generalize to other kinds of furniture as they are developed
|
|
19410
|
-
function getScalebarPosition(
|
|
19411
|
-
var
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
hoffs: 10
|
|
19536
|
+
function getScalebarPosition(opts) {
|
|
19537
|
+
var pos = opts.position || 'top-left';
|
|
19538
|
+
return {
|
|
19539
|
+
valign: pos.includes('top') ? 'top' : 'bottom',
|
|
19540
|
+
halign: pos.includes('left') ? 'left' : 'right'
|
|
19416
19541
|
};
|
|
19417
|
-
|
|
19418
|
-
|
|
19542
|
+
}
|
|
19543
|
+
|
|
19544
|
+
var styleOpts = {
|
|
19545
|
+
a: {
|
|
19546
|
+
bar_width: 3,
|
|
19547
|
+
tic_length: 0
|
|
19548
|
+
},
|
|
19549
|
+
b: {
|
|
19550
|
+
bar_width: 1,
|
|
19551
|
+
tic_length: 5
|
|
19419
19552
|
}
|
|
19420
|
-
|
|
19421
|
-
|
|
19553
|
+
};
|
|
19554
|
+
|
|
19555
|
+
var defaultOpts = {
|
|
19556
|
+
position: 'top-left',
|
|
19557
|
+
label_position: 'top',
|
|
19558
|
+
label_offset: 4,
|
|
19559
|
+
font_size: 12,
|
|
19560
|
+
margin: 12
|
|
19561
|
+
};
|
|
19562
|
+
|
|
19563
|
+
function getScalebarOpts(d) {
|
|
19564
|
+
var style = d.style == 'b' || d.style == 'B' ? 'b' : 'a';
|
|
19565
|
+
return Object.assign({}, defaultOpts, styleOpts[style], d, {style: style});
|
|
19566
|
+
}
|
|
19567
|
+
|
|
19568
|
+
// approximate pixel height of the scalebar
|
|
19569
|
+
function getScalebarHeight(opts) {
|
|
19570
|
+
return Math.round(opts.bar_width + opts.label_offset +
|
|
19571
|
+
opts.tic_length + opts.font_size * 0.8);
|
|
19572
|
+
}
|
|
19573
|
+
|
|
19574
|
+
function renderAsSvg(length, text, opts) {
|
|
19575
|
+
// label part
|
|
19576
|
+
var xOff = opts.style == 'b' ? Math.round(opts.font_size / 4) : 0;
|
|
19577
|
+
var alignLeft = opts.style == 'a' && opts.position.includes('left');
|
|
19578
|
+
var anchorX = alignLeft ? -xOff : length + xOff;
|
|
19579
|
+
var anchorY = opts.bar_width + + opts.tic_length + opts.label_offset;
|
|
19580
|
+
if (opts.label_position == 'top') {
|
|
19581
|
+
anchorY = -opts.label_offset - opts.tic_length;
|
|
19422
19582
|
}
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19583
|
+
var labelOpts = {
|
|
19584
|
+
'label-text': text,
|
|
19585
|
+
'font-size': opts.font_size,
|
|
19586
|
+
'text-anchor': alignLeft ? 'start': 'end',
|
|
19587
|
+
'dominant-baseline': opts.label_position == 'top' ? 'auto' : 'hanging'
|
|
19588
|
+
//// 'dominant-baseline': labelPos == 'top' ? 'text-after-edge' : 'text-before-edge'
|
|
19589
|
+
// 'text-after-edge' is buggy in Safari and unsupported by Illustrator,
|
|
19590
|
+
// so I'm using 'hanging' and 'auto', which seem to be well supported.
|
|
19591
|
+
// downside: requires a kludgy multiplier to calculate scalebar height (see above)
|
|
19592
|
+
};
|
|
19593
|
+
var labelPart = symbolRenderers.label(labelOpts, anchorX, anchorY);
|
|
19594
|
+
var zeroOpts = Object.assign({}, labelOpts, {'label-text': '0', 'text-anchor': 'start'});
|
|
19595
|
+
var zeroLabel = symbolRenderers.label(zeroOpts, -xOff, anchorY);
|
|
19596
|
+
|
|
19597
|
+
// bar part
|
|
19598
|
+
var y = 0;
|
|
19599
|
+
var y2 = opts.tic_length + opts.bar_width / 2;
|
|
19600
|
+
var coords;
|
|
19601
|
+
if (opts.label_position == "top") {
|
|
19602
|
+
y2 = -y2;
|
|
19426
19603
|
}
|
|
19427
|
-
if (
|
|
19428
|
-
|
|
19429
|
-
|
|
19604
|
+
if (opts.tic_length > 0) {
|
|
19605
|
+
coords = [[0, y2], [0, y], [length, y], [length, y2]];
|
|
19606
|
+
} else {
|
|
19607
|
+
coords = [[0, y], [length, y]];
|
|
19430
19608
|
}
|
|
19431
|
-
|
|
19609
|
+
var barPart = importLineString(coords);
|
|
19610
|
+
Object.assign(barPart.properties, {
|
|
19611
|
+
stroke: 'black',
|
|
19612
|
+
fill: 'none',
|
|
19613
|
+
'stroke-width': opts.bar_width,
|
|
19614
|
+
'stroke-linecap': 'butt',
|
|
19615
|
+
'stroke-linejoin': 'miter'
|
|
19616
|
+
});
|
|
19617
|
+
var parts = opts.style == 'b' ? [zeroLabel, labelPart, barPart] : [labelPart, barPart];
|
|
19618
|
+
return {
|
|
19619
|
+
tag: 'g',
|
|
19620
|
+
children: parts
|
|
19621
|
+
};
|
|
19432
19622
|
}
|
|
19433
19623
|
|
|
19434
19624
|
function renderScalebar(d, frame) {
|
|
19435
|
-
|
|
19625
|
+
if (!frame.crs) {
|
|
19626
|
+
message('Unable to render scalebar: unknown CRS.');
|
|
19627
|
+
return [];
|
|
19628
|
+
}
|
|
19629
|
+
if (frame.width > 0 === false) {
|
|
19630
|
+
return [];
|
|
19631
|
+
}
|
|
19632
|
+
|
|
19633
|
+
var opts = getScalebarOpts(d);
|
|
19436
19634
|
var metersPerPx = getMapFrameMetersPerPixel(frame);
|
|
19437
19635
|
var frameWidthPx = frame.width;
|
|
19438
19636
|
var unit = d.label ? parseScalebarUnits(d.label) : 'mile';
|
|
19439
19637
|
var number = d.label ? parseScalebarNumber(d.label) : null;
|
|
19440
19638
|
var label = number && unit ? d.label : getAutoScalebarLabel(frameWidthPx, metersPerPx, unit);
|
|
19441
|
-
var scalebarKm = parseScalebarLabelToKm(label);
|
|
19442
|
-
var barHeight = 3;
|
|
19443
|
-
var labelOffs = 4;
|
|
19444
|
-
var fontSize = +d.font_size || 12;
|
|
19445
|
-
var width = Math.round(scalebarKm / metersPerPx * 1000);
|
|
19446
|
-
var height = Math.round(barHeight + labelOffs + fontSize * 0.8);
|
|
19447
|
-
var labelPos = d.label_position == 'top' ? 'top' : 'bottom';
|
|
19448
|
-
var anchorX = pos.halign == 'left' ? 0 : width;
|
|
19449
|
-
var anchorY = barHeight + labelOffs;
|
|
19450
|
-
var dx = pos.halign == 'right' ? frameWidthPx - width - pos.hoffs : pos.hoffs;
|
|
19451
|
-
var dy = pos.valign == 'bottom' ? frame.height - height - pos.voffs : pos.voffs;
|
|
19452
19639
|
|
|
19640
|
+
var scalebarKm = parseScalebarLabelToKm(label);
|
|
19453
19641
|
if (scalebarKm > 0 === false) {
|
|
19454
19642
|
message('Unusable scalebar label:', label);
|
|
19455
19643
|
return [];
|
|
19456
19644
|
}
|
|
19457
19645
|
|
|
19458
|
-
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19462
|
-
if (!frame.crs) {
|
|
19463
|
-
message('Unable to render scalebar: unknown CRS.');
|
|
19464
|
-
return [];
|
|
19646
|
+
var width = Math.round(scalebarKm / metersPerPx * 1000);
|
|
19647
|
+
if (width > 0 === false) {
|
|
19648
|
+
stop("Null scalebar length");
|
|
19465
19649
|
}
|
|
19466
19650
|
|
|
19467
|
-
|
|
19468
|
-
|
|
19469
|
-
|
|
19651
|
+
var pos = getScalebarPosition(opts);
|
|
19652
|
+
var height = getScalebarHeight(opts);
|
|
19653
|
+
var dx = pos.halign == 'right' ? frameWidthPx - width - opts.margin : opts.margin;
|
|
19654
|
+
var dy = pos.valign == 'bottom' ? frame.height - height - opts.margin : opts.margin;
|
|
19655
|
+
if (opts.label_position == 'top') {
|
|
19656
|
+
dy += Math.round(opts.label_offset + opts.tic_length + opts.font_size * 0.8 + opts.bar_width / 2);
|
|
19657
|
+
} else {
|
|
19658
|
+
dy += Math.round(opts.bar_width / 2);
|
|
19470
19659
|
}
|
|
19471
19660
|
|
|
19472
|
-
|
|
19473
|
-
|
|
19474
|
-
|
|
19475
|
-
var barObj = {
|
|
19476
|
-
tag: 'rect',
|
|
19477
|
-
properties: {
|
|
19478
|
-
fill: 'black',
|
|
19479
|
-
x: 0,
|
|
19480
|
-
y: 0,
|
|
19481
|
-
width: width,
|
|
19482
|
-
height: barHeight
|
|
19483
|
-
}
|
|
19484
|
-
};
|
|
19485
|
-
var labelOpts = {
|
|
19486
|
-
'label-text': label,
|
|
19487
|
-
'font-size': fontSize,
|
|
19488
|
-
'text-anchor': pos.halign == 'left' ? 'start': 'end',
|
|
19489
|
-
'dominant-baseline': labelPos == 'top' ? 'auto' : 'hanging'
|
|
19490
|
-
//// 'dominant-baseline': labelPos == 'top' ? 'text-after-edge' : 'text-before-edge'
|
|
19491
|
-
// 'text-after-edge' is buggy in Safari and unsupported by Illustrator,
|
|
19492
|
-
// so I'm using 'hanging' and 'auto', which seem to be well supported.
|
|
19493
|
-
// downside: requires a kludgy multiplier to calculate scalebar height (see above)
|
|
19494
|
-
};
|
|
19495
|
-
var labelObj = symbolRenderers.label(labelOpts, anchorX, anchorY);
|
|
19496
|
-
var g = {
|
|
19497
|
-
tag: 'g',
|
|
19498
|
-
children: [barObj, labelObj],
|
|
19499
|
-
properties: {
|
|
19500
|
-
transform: 'translate(' + dx + ' ' + dy + ')'
|
|
19501
|
-
}
|
|
19661
|
+
var g = renderAsSvg(width, label, opts);
|
|
19662
|
+
g.properties = {
|
|
19663
|
+
transform: 'translate(' + dx + ' ' + dy + ')'
|
|
19502
19664
|
};
|
|
19665
|
+
|
|
19503
19666
|
return [g];
|
|
19504
19667
|
}
|
|
19505
19668
|
|
|
@@ -19615,6 +19778,7 @@
|
|
|
19615
19778
|
}).reverse().join(',');
|
|
19616
19779
|
}
|
|
19617
19780
|
|
|
19781
|
+
|
|
19618
19782
|
function renderFrame(d) {
|
|
19619
19783
|
var lineWidth = 1,
|
|
19620
19784
|
// inset stroke by half of line width
|
|
@@ -21986,7 +22150,13 @@ ${svg}
|
|
|
21986
22150
|
|
|
21987
22151
|
// @targets - non-empty output from Catalog#findCommandTargets()
|
|
21988
22152
|
//
|
|
21989
|
-
async function exportTargetLayers(targets, opts) {
|
|
22153
|
+
async function exportTargetLayers(catalog, targets, opts) {
|
|
22154
|
+
// kludge: get extent of 'fit-extent' layer (if given)
|
|
22155
|
+
if (opts.fit_extent) {
|
|
22156
|
+
var target = catalog.findSingleLayer(opts.fit_extent);
|
|
22157
|
+
var bounds = getLayerBounds(target.layer, target.dataset.arcs);
|
|
22158
|
+
opts = Object.assign({svg_bbox: bounds.toArray()}, opts);
|
|
22159
|
+
}
|
|
21990
22160
|
// convert target fmt to dataset fmt
|
|
21991
22161
|
var datasets = targets.map(function(target) {
|
|
21992
22162
|
return utils.defaults({layers: target.layers}, target.dataset);
|
|
@@ -24068,6 +24238,9 @@ ${svg}
|
|
|
24068
24238
|
describe: '[SVG] bounding box of SVG map in projected map units',
|
|
24069
24239
|
type: 'bbox'
|
|
24070
24240
|
})
|
|
24241
|
+
.option('fit-extent', {
|
|
24242
|
+
describe: '[SVG] layer to use for the map extent'
|
|
24243
|
+
})
|
|
24071
24244
|
.option('point-symbol', {
|
|
24072
24245
|
describe: '[SVG] circle or square (default is circle)'
|
|
24073
24246
|
})
|
|
@@ -25018,6 +25191,10 @@ ${svg}
|
|
|
25018
25191
|
type: 'bbox'
|
|
25019
25192
|
})
|
|
25020
25193
|
.option('offset', offsetOpt)
|
|
25194
|
+
.option('width', {
|
|
25195
|
+
// describe: 'set viewport width in pixels',
|
|
25196
|
+
type: 'number'
|
|
25197
|
+
})
|
|
25021
25198
|
.option('aspect-ratio', aspectRatioOpt)
|
|
25022
25199
|
.option('source', {
|
|
25023
25200
|
describe: 'name of layer to enclose'
|
|
@@ -25691,13 +25868,33 @@ ${svg}
|
|
|
25691
25868
|
DEFAULT: true,
|
|
25692
25869
|
describe: 'distance label, e.g. "35 miles"'
|
|
25693
25870
|
})
|
|
25694
|
-
.option('
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
.option('
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
.option('
|
|
25871
|
+
.option('style', {
|
|
25872
|
+
describe: 'two options: a or b'
|
|
25873
|
+
})
|
|
25874
|
+
.option('font-size', {
|
|
25875
|
+
type: 'number'
|
|
25876
|
+
})
|
|
25877
|
+
.option('tic-length', {
|
|
25878
|
+
describe: 'length of tic marks (style b)',
|
|
25879
|
+
type: 'number'
|
|
25880
|
+
})
|
|
25881
|
+
.option('bar-width', {
|
|
25882
|
+
describe: 'line width of bar',
|
|
25883
|
+
type: 'number'
|
|
25884
|
+
})
|
|
25885
|
+
.option('label-offset', {
|
|
25886
|
+
type: 'number'
|
|
25887
|
+
})
|
|
25888
|
+
.option('position', {
|
|
25889
|
+
describe: 'e.g. bottom-right (default is top-left)'
|
|
25890
|
+
})
|
|
25891
|
+
.option('label-position', {
|
|
25892
|
+
describe: 'top or bottom'
|
|
25893
|
+
})
|
|
25894
|
+
.option('margin', {
|
|
25895
|
+
describe: 'offset in pixels from edge of map',
|
|
25896
|
+
type: 'number'
|
|
25897
|
+
});
|
|
25701
25898
|
|
|
25702
25899
|
parser.command('shape')
|
|
25703
25900
|
.describe('create a polyline or polygon from coordinates')
|
|
@@ -35673,11 +35870,285 @@ ${svg}
|
|
|
35673
35870
|
};
|
|
35674
35871
|
}
|
|
35675
35872
|
|
|
35873
|
+
var MAX_RULE_LEN = 50;
|
|
35874
|
+
|
|
35875
|
+
cmd.info = function(targets, opts) {
|
|
35876
|
+
var layers = expandCommandTargets(targets);
|
|
35877
|
+
var arr = layers.map(function(o) {
|
|
35878
|
+
return getLayerInfo(o.layer, o.dataset);
|
|
35879
|
+
});
|
|
35880
|
+
|
|
35881
|
+
if (opts.save_to) {
|
|
35882
|
+
var output = [{
|
|
35883
|
+
filename: opts.save_to + (opts.save_to.endsWith('.json') ? '' : '.json'),
|
|
35884
|
+
content: JSON.stringify(arr, null, 2)
|
|
35885
|
+
}];
|
|
35886
|
+
writeFiles(output, opts);
|
|
35887
|
+
}
|
|
35888
|
+
if (opts.to_layer) {
|
|
35889
|
+
return {
|
|
35890
|
+
info: {},
|
|
35891
|
+
layers: [{
|
|
35892
|
+
name: opts.name || 'info',
|
|
35893
|
+
data: new DataTable(arr)
|
|
35894
|
+
}]
|
|
35895
|
+
};
|
|
35896
|
+
}
|
|
35897
|
+
message(formatInfo(arr));
|
|
35898
|
+
};
|
|
35899
|
+
|
|
35900
|
+
cmd.printInfo = cmd.info; // old name
|
|
35901
|
+
|
|
35902
|
+
function getLayerInfo(lyr, dataset) {
|
|
35903
|
+
var n = getFeatureCount(lyr);
|
|
35904
|
+
var o = {
|
|
35905
|
+
layer_name: lyr.name,
|
|
35906
|
+
geometry_type: lyr.geometry_type,
|
|
35907
|
+
feature_count: n,
|
|
35908
|
+
null_shape_count: 0,
|
|
35909
|
+
null_data_count: lyr.data ? countNullRecords(lyr.data.getRecords()) : n
|
|
35910
|
+
};
|
|
35911
|
+
if (lyr.shapes && lyr.shapes.length > 0) {
|
|
35912
|
+
o.null_shape_count = countNullShapes(lyr.shapes);
|
|
35913
|
+
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
35914
|
+
o.proj4 = getProjInfo(dataset);
|
|
35915
|
+
}
|
|
35916
|
+
o.source_file = getLayerSourceFile(lyr, dataset) || null;
|
|
35917
|
+
o.attribute_data = getAttributeTableInfo(lyr);
|
|
35918
|
+
return o;
|
|
35919
|
+
}
|
|
35920
|
+
|
|
35921
|
+
// i: (optional) record index
|
|
35922
|
+
function getAttributeTableInfo(lyr, i) {
|
|
35923
|
+
if (!lyr.data || lyr.data.size() === 0 || lyr.data.getFields().length === 0) {
|
|
35924
|
+
return null;
|
|
35925
|
+
}
|
|
35926
|
+
var fields = applyFieldOrder(lyr.data.getFields(), 'ascending');
|
|
35927
|
+
var valueName = i === undefined ? 'first_value' : 'value';
|
|
35928
|
+
return fields.map(function(fname) {
|
|
35929
|
+
return {
|
|
35930
|
+
field: fname,
|
|
35931
|
+
[valueName]: lyr.data.getReadOnlyRecordAt(i || 0)[fname]
|
|
35932
|
+
};
|
|
35933
|
+
});
|
|
35934
|
+
}
|
|
35935
|
+
|
|
35936
|
+
function formatInfo(arr) {
|
|
35937
|
+
var str = '';
|
|
35938
|
+
arr.forEach(function(info, i) {
|
|
35939
|
+
var title = 'Layer: ' + (info.layer_name || '[unnamed layer]');
|
|
35940
|
+
var tableStr = formatAttributeTableInfo(info.attribute_data);
|
|
35941
|
+
var tableWidth = measureLongestLine(tableStr);
|
|
35942
|
+
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
35943
|
+
str += '\n';
|
|
35944
|
+
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
35945
|
+
str += title + '\n';
|
|
35946
|
+
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
35947
|
+
str += formatLayerInfo(info);
|
|
35948
|
+
str += tableStr;
|
|
35949
|
+
});
|
|
35950
|
+
return str;
|
|
35951
|
+
}
|
|
35952
|
+
|
|
35953
|
+
function formatLayerInfo(data) {
|
|
35954
|
+
var str = '';
|
|
35955
|
+
str += "Type: " + (data.geometry_type || "tabular data") + "\n";
|
|
35956
|
+
str += utils.format("Records: %,d\n",data.feature_count);
|
|
35957
|
+
if (data.null_shape_count > 0) {
|
|
35958
|
+
str += utils.format("Nulls: %'d", data.null_shape_count) + "\n";
|
|
35959
|
+
}
|
|
35960
|
+
if (data.geometry_type && data.feature_count > data.null_shape_count) {
|
|
35961
|
+
str += "Bounds: " + data.bbox.join(',') + "\n";
|
|
35962
|
+
str += "CRS: " + data.proj4 + "\n";
|
|
35963
|
+
}
|
|
35964
|
+
str += "Source: " + (data.source_file || 'n/a') + "\n";
|
|
35965
|
+
return str;
|
|
35966
|
+
}
|
|
35967
|
+
|
|
35968
|
+
function formatAttributeTableInfo(arr) {
|
|
35969
|
+
if (!arr) return "Attribute data: [none]\n";
|
|
35970
|
+
var header = "\nAttribute data\n";
|
|
35971
|
+
var valKey = 'first_value' in arr[0] ? 'first_value' : 'value';
|
|
35972
|
+
var vals = [];
|
|
35973
|
+
var fields = [];
|
|
35974
|
+
arr.forEach(function(o) {
|
|
35975
|
+
fields.push(o.field);
|
|
35976
|
+
vals.push(o[valKey]);
|
|
35977
|
+
});
|
|
35978
|
+
var maxIntegralChars = vals.reduce(function(max, val) {
|
|
35979
|
+
if (utils.isNumber(val)) {
|
|
35980
|
+
max = Math.max(max, countIntegralChars(val));
|
|
35981
|
+
}
|
|
35982
|
+
return max;
|
|
35983
|
+
}, 0);
|
|
35984
|
+
var col1Arr = ['Field'].concat(fields);
|
|
35985
|
+
var col2Arr = vals.reduce(function(memo, val) {
|
|
35986
|
+
memo.push(formatTableValue(val, maxIntegralChars));
|
|
35987
|
+
return memo;
|
|
35988
|
+
}, [valKey == 'first_value' ? 'First value' : 'Value']);
|
|
35989
|
+
var col1Chars = maxChars(col1Arr);
|
|
35990
|
+
var col2Chars = maxChars(col2Arr);
|
|
35991
|
+
var sepStr = (utils.rpad('', col1Chars + 2, '-') + '+' +
|
|
35992
|
+
utils.rpad('', col2Chars + 2, '-')).substr(0, MAX_RULE_LEN);
|
|
35993
|
+
var sepLine = sepStr + '\n';
|
|
35994
|
+
var table = '';
|
|
35995
|
+
col1Arr.forEach(function(col1, i) {
|
|
35996
|
+
var w = stringDisplayWidth(col1);
|
|
35997
|
+
table += ' ' + col1 + utils.rpad('', col1Chars - w, ' ') + ' | ' +
|
|
35998
|
+
col2Arr[i] + '\n';
|
|
35999
|
+
if (i === 0) table += sepLine; // separator after first line
|
|
36000
|
+
});
|
|
36001
|
+
return header + sepLine + table + sepLine;
|
|
36002
|
+
}
|
|
36003
|
+
|
|
36004
|
+
function measureLongestLine(str) {
|
|
36005
|
+
return Math.max.apply(null, str.split('\n').map(function(line) {return stringDisplayWidth(line);}));
|
|
36006
|
+
}
|
|
36007
|
+
|
|
36008
|
+
function stringDisplayWidth(str) {
|
|
36009
|
+
var w = 0;
|
|
36010
|
+
for (var i = 0, n=str.length; i < n; i++) {
|
|
36011
|
+
w += charDisplayWidth(str.charCodeAt(i));
|
|
36012
|
+
}
|
|
36013
|
+
return w;
|
|
36014
|
+
}
|
|
36015
|
+
|
|
36016
|
+
// see https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
|
36017
|
+
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
36018
|
+
function charDisplayWidth(c) {
|
|
36019
|
+
if (c >= 0x1100 &&
|
|
36020
|
+
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
36021
|
+
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
36022
|
+
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
36023
|
+
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
36024
|
+
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
36025
|
+
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
36026
|
+
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
36027
|
+
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
36028
|
+
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
36029
|
+
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
36030
|
+
return 1;
|
|
36031
|
+
}
|
|
36032
|
+
|
|
36033
|
+
// TODO: consider polygons with zero area or other invalid geometries
|
|
36034
|
+
function countNullShapes(shapes) {
|
|
36035
|
+
var count = 0;
|
|
36036
|
+
for (var i=0; i<shapes.length; i++) {
|
|
36037
|
+
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
36038
|
+
}
|
|
36039
|
+
return count;
|
|
36040
|
+
}
|
|
36041
|
+
|
|
36042
|
+
function countNullRecords(records) {
|
|
36043
|
+
var count = 0;
|
|
36044
|
+
for (var i=0; i<records.length; i++) {
|
|
36045
|
+
if (!records[i]) count++;
|
|
36046
|
+
}
|
|
36047
|
+
return count;
|
|
36048
|
+
}
|
|
36049
|
+
|
|
36050
|
+
function maxChars(arr) {
|
|
36051
|
+
return arr.reduce(function(memo, str) {
|
|
36052
|
+
var w = stringDisplayWidth(str);
|
|
36053
|
+
return w > memo ? w : memo;
|
|
36054
|
+
}, 0);
|
|
36055
|
+
}
|
|
36056
|
+
|
|
36057
|
+
function formatString(str) {
|
|
36058
|
+
var replacements = {
|
|
36059
|
+
'\n': '\\n',
|
|
36060
|
+
'\r': '\\r',
|
|
36061
|
+
'\t': '\\t'
|
|
36062
|
+
};
|
|
36063
|
+
var cleanChar = function(c) {
|
|
36064
|
+
// convert newlines and carriage returns
|
|
36065
|
+
// TODO: better handling of non-printing chars
|
|
36066
|
+
return c in replacements ? replacements[c] : '';
|
|
36067
|
+
};
|
|
36068
|
+
str = str.replace(/[\r\t\n]/g, cleanChar);
|
|
36069
|
+
return "'" + str + "'";
|
|
36070
|
+
}
|
|
36071
|
+
|
|
36072
|
+
function countIntegralChars(val) {
|
|
36073
|
+
return utils.isNumber(val) ? (utils.formatNumber(val) + '.').indexOf('.') : 0;
|
|
36074
|
+
}
|
|
36075
|
+
|
|
36076
|
+
function formatTableValue(val, integralChars) {
|
|
36077
|
+
var str;
|
|
36078
|
+
if (utils.isNumber(val)) {
|
|
36079
|
+
str = utils.lpad("", integralChars - countIntegralChars(val), ' ') +
|
|
36080
|
+
utils.formatNumber(val);
|
|
36081
|
+
} else if (utils.isString(val)) {
|
|
36082
|
+
str = formatString(val);
|
|
36083
|
+
} else if (utils.isDate(val)) {
|
|
36084
|
+
str = utils.formatDateISO(val) + ' (Date)';
|
|
36085
|
+
} else if (utils.isObject(val)) { // if {} or [], display JSON
|
|
36086
|
+
str = JSON.stringify(val);
|
|
36087
|
+
} else {
|
|
36088
|
+
str = String(val);
|
|
36089
|
+
}
|
|
36090
|
+
|
|
36091
|
+
if (typeof str != 'string') {
|
|
36092
|
+
// e.g. JSON.stringify converts functions to undefined
|
|
36093
|
+
str = '[' + (typeof val) + ']';
|
|
36094
|
+
}
|
|
36095
|
+
|
|
36096
|
+
return str;
|
|
36097
|
+
}
|
|
36098
|
+
|
|
36099
|
+
var Info = /*#__PURE__*/Object.freeze({
|
|
36100
|
+
__proto__: null,
|
|
36101
|
+
getLayerInfo: getLayerInfo,
|
|
36102
|
+
getAttributeTableInfo: getAttributeTableInfo,
|
|
36103
|
+
formatAttributeTableInfo: formatAttributeTableInfo,
|
|
36104
|
+
formatTableValue: formatTableValue
|
|
36105
|
+
});
|
|
36106
|
+
|
|
36107
|
+
// import { importGeoJSON } from '../geojson/geojson-import';
|
|
36108
|
+
|
|
36109
|
+
|
|
36110
|
+
function addTargetProxies(targets, ctx) {
|
|
36111
|
+
if (targets && targets.length > 0) {
|
|
36112
|
+
var proxies = expandCommandTargets(targets).reduce(function(memo, target) {
|
|
36113
|
+
var proxy = getTargetProxy(target);
|
|
36114
|
+
memo.push(proxy);
|
|
36115
|
+
// index targets by layer name too
|
|
36116
|
+
if (target.layer.name) {
|
|
36117
|
+
memo[target.layer.name] = proxy;
|
|
36118
|
+
}
|
|
36119
|
+
return memo;
|
|
36120
|
+
}, []);
|
|
36121
|
+
Object.defineProperty(ctx, 'targets', {value: proxies});
|
|
36122
|
+
if (proxies.length == 1) {
|
|
36123
|
+
Object.defineProperty(ctx, 'target', {value: proxies[0]});
|
|
36124
|
+
}
|
|
36125
|
+
}
|
|
36126
|
+
}
|
|
36127
|
+
|
|
36128
|
+
function getTargetProxy(target) {
|
|
36129
|
+
var proxy = getLayerInfo(target.layer, target.dataset); // layer_name, feature_count etc
|
|
36130
|
+
proxy.layer = target.layer;
|
|
36131
|
+
proxy.dataset = target.dataset;
|
|
36132
|
+
addGetters(proxy, {
|
|
36133
|
+
// export as an object, not a string or buffer
|
|
36134
|
+
geojson: getGeoJSON
|
|
36135
|
+
});
|
|
36136
|
+
|
|
36137
|
+
function getGeoJSON() {
|
|
36138
|
+
var features = exportLayerAsGeoJSON(target.layer, target.dataset, {rfc7946: true}, true);
|
|
36139
|
+
return {
|
|
36140
|
+
type: 'FeatureCollection',
|
|
36141
|
+
features: features
|
|
36142
|
+
};
|
|
36143
|
+
}
|
|
36144
|
+
|
|
36145
|
+
return proxy;
|
|
36146
|
+
}
|
|
36147
|
+
|
|
35676
36148
|
function compileIfCommandExpression(expr, catalog, opts) {
|
|
35677
36149
|
return compileLayerExpression(expr, catalog, opts);
|
|
35678
36150
|
}
|
|
35679
36151
|
|
|
35680
|
-
|
|
35681
36152
|
function compileLayerExpression(expr, catalog, opts) {
|
|
35682
36153
|
var targetId = opts.layer || opts.target || null;
|
|
35683
36154
|
var targets = catalog.findCommandTargets(targetId);
|
|
@@ -35693,6 +36164,10 @@ ${svg}
|
|
|
35693
36164
|
} else {
|
|
35694
36165
|
ctx = getNullLayerProxy(targets);
|
|
35695
36166
|
}
|
|
36167
|
+
|
|
36168
|
+
// add target/targets proxies, for consistency with the -run command
|
|
36169
|
+
addTargetProxies(targets, ctx);
|
|
36170
|
+
|
|
35696
36171
|
ctx.global = defs; // TODO: remove duplication with mapshaper.expressions.mjs
|
|
35697
36172
|
var func = compileExpressionToFunction(expr, opts);
|
|
35698
36173
|
|
|
@@ -38039,7 +38514,7 @@ ${svg}
|
|
|
38039
38514
|
getPointFeatureBounds(shp) : targetDataset.arcs.getMultiShapeBounds(shp);
|
|
38040
38515
|
bounds = applyRectangleOptions(bounds, crsInfo.crs, opts);
|
|
38041
38516
|
if (!bounds) return null;
|
|
38042
|
-
return
|
|
38517
|
+
return bboxToPolygon(bounds.toArray(), opts);
|
|
38043
38518
|
});
|
|
38044
38519
|
var geojson = {
|
|
38045
38520
|
type: 'FeatureCollection',
|
|
@@ -38089,8 +38564,16 @@ ${svg}
|
|
|
38089
38564
|
if (!bounds || !bounds.hasBounds()) {
|
|
38090
38565
|
stop('Missing rectangle extent');
|
|
38091
38566
|
}
|
|
38092
|
-
var
|
|
38093
|
-
|
|
38567
|
+
var feature = {
|
|
38568
|
+
type: 'Feature',
|
|
38569
|
+
properties: {},
|
|
38570
|
+
geometry: bboxToPolygon(bounds.toArray(), opts)
|
|
38571
|
+
};
|
|
38572
|
+
if (opts.width > 0) {
|
|
38573
|
+
feature.properties.width = opts.width;
|
|
38574
|
+
feature.properties.type = 'frame';
|
|
38575
|
+
}
|
|
38576
|
+
var dataset = importGeoJSON(feature, {});
|
|
38094
38577
|
dataset.layers[0].name = opts.name || 'rectangle';
|
|
38095
38578
|
setDatasetCrsInfo(dataset, crsInfo);
|
|
38096
38579
|
return dataset;
|
|
@@ -38140,17 +38623,13 @@ ${svg}
|
|
|
38140
38623
|
return bounds;
|
|
38141
38624
|
}
|
|
38142
38625
|
|
|
38143
|
-
function
|
|
38626
|
+
function bboxToPolygon(bbox, optsArg) {
|
|
38144
38627
|
var opts = optsArg || {};
|
|
38145
|
-
var coords =
|
|
38146
|
-
[bbox[2], bbox[1]], [bbox[0], bbox[1]]];
|
|
38628
|
+
var coords = bboxToCoords(bbox);
|
|
38147
38629
|
if (opts.interval > 0) {
|
|
38148
38630
|
coords = densifyPathByInterval(coords, opts.interval);
|
|
38149
38631
|
}
|
|
38150
|
-
return
|
|
38151
|
-
type: 'LineString',
|
|
38152
|
-
coordinates: coords
|
|
38153
|
-
} : {
|
|
38632
|
+
return {
|
|
38154
38633
|
type: 'Polygon',
|
|
38155
38634
|
coordinates: [coords]
|
|
38156
38635
|
};
|
|
@@ -38159,7 +38638,7 @@ ${svg}
|
|
|
38159
38638
|
var Rectangle = /*#__PURE__*/Object.freeze({
|
|
38160
38639
|
__proto__: null,
|
|
38161
38640
|
applyAspectRatio: applyAspectRatio,
|
|
38162
|
-
|
|
38641
|
+
bboxToPolygon: bboxToPolygon
|
|
38163
38642
|
});
|
|
38164
38643
|
|
|
38165
38644
|
function getSemiMinorAxis(P) {
|
|
@@ -38713,8 +39192,7 @@ ${svg}
|
|
|
38713
39192
|
var rotation = getRotationParams(dest);
|
|
38714
39193
|
if (!bbox) error('Missing expected clip bbox.');
|
|
38715
39194
|
opts = Object.assign({interval: 0.5}, opts); // make sure edges can curve
|
|
38716
|
-
var
|
|
38717
|
-
var dataset = importGeoJSON(geojson);
|
|
39195
|
+
var dataset = importGeoJSON(bboxToPolygon(bbox, opts));
|
|
38718
39196
|
if (rotation) {
|
|
38719
39197
|
rotateDataset(dataset, {rotation: rotation, invert: true});
|
|
38720
39198
|
}
|
|
@@ -38903,7 +39381,7 @@ ${svg}
|
|
|
38903
39381
|
var e = 1e-8;
|
|
38904
39382
|
var bbox = [lon-e, -91, lon+e, 91];
|
|
38905
39383
|
// densify (so cut line can curve, e.g. Cupola projection)
|
|
38906
|
-
var geojson =
|
|
39384
|
+
var geojson = bboxToPolygon(bbox, {interval: 0.5});
|
|
38907
39385
|
var clip = importGeoJSON(geojson);
|
|
38908
39386
|
clipLayersInPlace(pathLayers, clip, dataset, 'erase');
|
|
38909
39387
|
}
|
|
@@ -39206,7 +39684,6 @@ ${svg}
|
|
|
39206
39684
|
|
|
39207
39685
|
function createProjectedGraticule(dest, opts) {
|
|
39208
39686
|
var src = parseCrsString('wgs84');
|
|
39209
|
-
// var outline = getOutlineDataset(src, dest, {inset: 0, geometry_type: 'polyline'});
|
|
39210
39687
|
var outline = getOutlineDataset(src, dest, {});
|
|
39211
39688
|
var graticule = importGeoJSON(createGraticule(dest, !!outline, opts));
|
|
39212
39689
|
projectDataset(graticule, src, dest, {no_clip: false}); // TODO: densify?
|
|
@@ -39388,7 +39865,6 @@ ${svg}
|
|
|
39388
39865
|
}
|
|
39389
39866
|
|
|
39390
39867
|
function skipCommand(cmdName, job) {
|
|
39391
|
-
// allow all control commands to run
|
|
39392
39868
|
if (jobIsStopped(job)) return true;
|
|
39393
39869
|
if (isControlFlowCommand(cmdName)) return false;
|
|
39394
39870
|
return !inActiveBranch(job);
|
|
@@ -39481,240 +39957,6 @@ ${svg}
|
|
|
39481
39957
|
utils.extend(getStashedVar('defs'), obj);
|
|
39482
39958
|
};
|
|
39483
39959
|
|
|
39484
|
-
var MAX_RULE_LEN = 50;
|
|
39485
|
-
|
|
39486
|
-
cmd.info = function(targets, opts) {
|
|
39487
|
-
var layers = expandCommandTargets(targets);
|
|
39488
|
-
var arr = layers.map(function(o) {
|
|
39489
|
-
return getLayerInfo(o.layer, o.dataset);
|
|
39490
|
-
});
|
|
39491
|
-
|
|
39492
|
-
if (opts.save_to) {
|
|
39493
|
-
var output = [{
|
|
39494
|
-
filename: opts.save_to + (opts.save_to.endsWith('.json') ? '' : '.json'),
|
|
39495
|
-
content: JSON.stringify(arr, null, 2)
|
|
39496
|
-
}];
|
|
39497
|
-
writeFiles(output, opts);
|
|
39498
|
-
}
|
|
39499
|
-
if (opts.to_layer) {
|
|
39500
|
-
return {
|
|
39501
|
-
info: {},
|
|
39502
|
-
layers: [{
|
|
39503
|
-
name: opts.name || 'info',
|
|
39504
|
-
data: new DataTable(arr)
|
|
39505
|
-
}]
|
|
39506
|
-
};
|
|
39507
|
-
}
|
|
39508
|
-
message(formatInfo(arr));
|
|
39509
|
-
};
|
|
39510
|
-
|
|
39511
|
-
cmd.printInfo = cmd.info; // old name
|
|
39512
|
-
|
|
39513
|
-
function getLayerInfo(lyr, dataset) {
|
|
39514
|
-
var n = getFeatureCount(lyr);
|
|
39515
|
-
var o = {
|
|
39516
|
-
layer_name: lyr.name,
|
|
39517
|
-
geometry_type: lyr.geometry_type,
|
|
39518
|
-
feature_count: n,
|
|
39519
|
-
null_shape_count: 0,
|
|
39520
|
-
null_data_count: lyr.data ? countNullRecords(lyr.data.getRecords()) : n
|
|
39521
|
-
};
|
|
39522
|
-
if (lyr.shapes && lyr.shapes.length > 0) {
|
|
39523
|
-
o.null_shape_count = countNullShapes(lyr.shapes);
|
|
39524
|
-
o.bbox = getLayerBounds(lyr, dataset.arcs).toArray();
|
|
39525
|
-
o.proj4 = getProjInfo(dataset);
|
|
39526
|
-
}
|
|
39527
|
-
o.source_file = getLayerSourceFile(lyr, dataset) || null;
|
|
39528
|
-
o.attribute_data = getAttributeTableInfo(lyr);
|
|
39529
|
-
return o;
|
|
39530
|
-
}
|
|
39531
|
-
|
|
39532
|
-
// i: (optional) record index
|
|
39533
|
-
function getAttributeTableInfo(lyr, i) {
|
|
39534
|
-
if (!lyr.data || lyr.data.size() === 0 || lyr.data.getFields().length === 0) {
|
|
39535
|
-
return null;
|
|
39536
|
-
}
|
|
39537
|
-
var fields = applyFieldOrder(lyr.data.getFields(), 'ascending');
|
|
39538
|
-
var valueName = i === undefined ? 'first_value' : 'value';
|
|
39539
|
-
return fields.map(function(fname) {
|
|
39540
|
-
return {
|
|
39541
|
-
field: fname,
|
|
39542
|
-
[valueName]: lyr.data.getReadOnlyRecordAt(i || 0)[fname]
|
|
39543
|
-
};
|
|
39544
|
-
});
|
|
39545
|
-
}
|
|
39546
|
-
|
|
39547
|
-
function formatInfo(arr) {
|
|
39548
|
-
var str = '';
|
|
39549
|
-
arr.forEach(function(info, i) {
|
|
39550
|
-
var title = 'Layer: ' + (info.layer_name || '[unnamed layer]');
|
|
39551
|
-
var tableStr = formatAttributeTableInfo(info.attribute_data);
|
|
39552
|
-
var tableWidth = measureLongestLine(tableStr);
|
|
39553
|
-
var ruleLen = Math.min(Math.max(title.length, tableWidth), MAX_RULE_LEN);
|
|
39554
|
-
str += '\n';
|
|
39555
|
-
str += utils.lpad('', ruleLen, '=') + '\n';
|
|
39556
|
-
str += title + '\n';
|
|
39557
|
-
str += utils.lpad('', ruleLen, '-') + '\n';
|
|
39558
|
-
str += formatLayerInfo(info);
|
|
39559
|
-
str += tableStr;
|
|
39560
|
-
});
|
|
39561
|
-
return str;
|
|
39562
|
-
}
|
|
39563
|
-
|
|
39564
|
-
function formatLayerInfo(data) {
|
|
39565
|
-
var str = '';
|
|
39566
|
-
str += "Type: " + (data.geometry_type || "tabular data") + "\n";
|
|
39567
|
-
str += utils.format("Records: %,d\n",data.feature_count);
|
|
39568
|
-
if (data.null_shape_count > 0) {
|
|
39569
|
-
str += utils.format("Nulls: %'d", data.null_shape_count) + "\n";
|
|
39570
|
-
}
|
|
39571
|
-
if (data.geometry_type && data.feature_count > data.null_shape_count) {
|
|
39572
|
-
str += "Bounds: " + data.bbox.join(',') + "\n";
|
|
39573
|
-
str += "CRS: " + data.proj4 + "\n";
|
|
39574
|
-
}
|
|
39575
|
-
str += "Source: " + (data.source_file || 'n/a') + "\n";
|
|
39576
|
-
return str;
|
|
39577
|
-
}
|
|
39578
|
-
|
|
39579
|
-
function formatAttributeTableInfo(arr) {
|
|
39580
|
-
if (!arr) return "Attribute data: [none]\n";
|
|
39581
|
-
var header = "\nAttribute data\n";
|
|
39582
|
-
var valKey = 'first_value' in arr[0] ? 'first_value' : 'value';
|
|
39583
|
-
var vals = [];
|
|
39584
|
-
var fields = [];
|
|
39585
|
-
arr.forEach(function(o) {
|
|
39586
|
-
fields.push(o.field);
|
|
39587
|
-
vals.push(o[valKey]);
|
|
39588
|
-
});
|
|
39589
|
-
var maxIntegralChars = vals.reduce(function(max, val) {
|
|
39590
|
-
if (utils.isNumber(val)) {
|
|
39591
|
-
max = Math.max(max, countIntegralChars(val));
|
|
39592
|
-
}
|
|
39593
|
-
return max;
|
|
39594
|
-
}, 0);
|
|
39595
|
-
var col1Arr = ['Field'].concat(fields);
|
|
39596
|
-
var col2Arr = vals.reduce(function(memo, val) {
|
|
39597
|
-
memo.push(formatTableValue(val, maxIntegralChars));
|
|
39598
|
-
return memo;
|
|
39599
|
-
}, [valKey == 'first_value' ? 'First value' : 'Value']);
|
|
39600
|
-
var col1Chars = maxChars(col1Arr);
|
|
39601
|
-
var col2Chars = maxChars(col2Arr);
|
|
39602
|
-
var sepStr = (utils.rpad('', col1Chars + 2, '-') + '+' +
|
|
39603
|
-
utils.rpad('', col2Chars + 2, '-')).substr(0, MAX_RULE_LEN);
|
|
39604
|
-
var sepLine = sepStr + '\n';
|
|
39605
|
-
var table = '';
|
|
39606
|
-
col1Arr.forEach(function(col1, i) {
|
|
39607
|
-
var w = stringDisplayWidth(col1);
|
|
39608
|
-
table += ' ' + col1 + utils.rpad('', col1Chars - w, ' ') + ' | ' +
|
|
39609
|
-
col2Arr[i] + '\n';
|
|
39610
|
-
if (i === 0) table += sepLine; // separator after first line
|
|
39611
|
-
});
|
|
39612
|
-
return header + sepLine + table + sepLine;
|
|
39613
|
-
}
|
|
39614
|
-
|
|
39615
|
-
function measureLongestLine(str) {
|
|
39616
|
-
return Math.max.apply(null, str.split('\n').map(function(line) {return stringDisplayWidth(line);}));
|
|
39617
|
-
}
|
|
39618
|
-
|
|
39619
|
-
function stringDisplayWidth(str) {
|
|
39620
|
-
var w = 0;
|
|
39621
|
-
for (var i = 0, n=str.length; i < n; i++) {
|
|
39622
|
-
w += charDisplayWidth(str.charCodeAt(i));
|
|
39623
|
-
}
|
|
39624
|
-
return w;
|
|
39625
|
-
}
|
|
39626
|
-
|
|
39627
|
-
// see https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
|
39628
|
-
// this is a simplified version, focusing on double-width CJK chars and ignoring nonprinting etc chars
|
|
39629
|
-
function charDisplayWidth(c) {
|
|
39630
|
-
if (c >= 0x1100 &&
|
|
39631
|
-
(c <= 0x115f || c == 0x2329 || c == 0x232a ||
|
|
39632
|
-
(c >= 0x2e80 && c <= 0xa4cf && c != 0x303f) || /* CJK ... Yi */
|
|
39633
|
-
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
|
|
39634
|
-
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
|
|
39635
|
-
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
|
|
39636
|
-
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
|
|
39637
|
-
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
|
|
39638
|
-
(c >= 0xffe0 && c <= 0xffe6) ||
|
|
39639
|
-
(c >= 0x20000 && c <= 0x2fffd) ||
|
|
39640
|
-
(c >= 0x30000 && c <= 0x3fffd))) return 2;
|
|
39641
|
-
return 1;
|
|
39642
|
-
}
|
|
39643
|
-
|
|
39644
|
-
// TODO: consider polygons with zero area or other invalid geometries
|
|
39645
|
-
function countNullShapes(shapes) {
|
|
39646
|
-
var count = 0;
|
|
39647
|
-
for (var i=0; i<shapes.length; i++) {
|
|
39648
|
-
if (!shapes[i] || shapes[i].length === 0) count++;
|
|
39649
|
-
}
|
|
39650
|
-
return count;
|
|
39651
|
-
}
|
|
39652
|
-
|
|
39653
|
-
function countNullRecords(records) {
|
|
39654
|
-
var count = 0;
|
|
39655
|
-
for (var i=0; i<records.length; i++) {
|
|
39656
|
-
if (!records[i]) count++;
|
|
39657
|
-
}
|
|
39658
|
-
return count;
|
|
39659
|
-
}
|
|
39660
|
-
|
|
39661
|
-
function maxChars(arr) {
|
|
39662
|
-
return arr.reduce(function(memo, str) {
|
|
39663
|
-
var w = stringDisplayWidth(str);
|
|
39664
|
-
return w > memo ? w : memo;
|
|
39665
|
-
}, 0);
|
|
39666
|
-
}
|
|
39667
|
-
|
|
39668
|
-
function formatString(str) {
|
|
39669
|
-
var replacements = {
|
|
39670
|
-
'\n': '\\n',
|
|
39671
|
-
'\r': '\\r',
|
|
39672
|
-
'\t': '\\t'
|
|
39673
|
-
};
|
|
39674
|
-
var cleanChar = function(c) {
|
|
39675
|
-
// convert newlines and carriage returns
|
|
39676
|
-
// TODO: better handling of non-printing chars
|
|
39677
|
-
return c in replacements ? replacements[c] : '';
|
|
39678
|
-
};
|
|
39679
|
-
str = str.replace(/[\r\t\n]/g, cleanChar);
|
|
39680
|
-
return "'" + str + "'";
|
|
39681
|
-
}
|
|
39682
|
-
|
|
39683
|
-
function countIntegralChars(val) {
|
|
39684
|
-
return utils.isNumber(val) ? (utils.formatNumber(val) + '.').indexOf('.') : 0;
|
|
39685
|
-
}
|
|
39686
|
-
|
|
39687
|
-
function formatTableValue(val, integralChars) {
|
|
39688
|
-
var str;
|
|
39689
|
-
if (utils.isNumber(val)) {
|
|
39690
|
-
str = utils.lpad("", integralChars - countIntegralChars(val), ' ') +
|
|
39691
|
-
utils.formatNumber(val);
|
|
39692
|
-
} else if (utils.isString(val)) {
|
|
39693
|
-
str = formatString(val);
|
|
39694
|
-
} else if (utils.isDate(val)) {
|
|
39695
|
-
str = utils.formatDateISO(val) + ' (Date)';
|
|
39696
|
-
} else if (utils.isObject(val)) { // if {} or [], display JSON
|
|
39697
|
-
str = JSON.stringify(val);
|
|
39698
|
-
} else {
|
|
39699
|
-
str = String(val);
|
|
39700
|
-
}
|
|
39701
|
-
|
|
39702
|
-
if (typeof str != 'string') {
|
|
39703
|
-
// e.g. JSON.stringify converts functions to undefined
|
|
39704
|
-
str = '[' + (typeof val) + ']';
|
|
39705
|
-
}
|
|
39706
|
-
|
|
39707
|
-
return str;
|
|
39708
|
-
}
|
|
39709
|
-
|
|
39710
|
-
var Info = /*#__PURE__*/Object.freeze({
|
|
39711
|
-
__proto__: null,
|
|
39712
|
-
getLayerInfo: getLayerInfo,
|
|
39713
|
-
getAttributeTableInfo: getAttributeTableInfo,
|
|
39714
|
-
formatAttributeTableInfo: formatAttributeTableInfo,
|
|
39715
|
-
formatTableValue: formatTableValue
|
|
39716
|
-
});
|
|
39717
|
-
|
|
39718
39960
|
// TODO: make sure that the inlay shapes and data are not shared
|
|
39719
39961
|
cmd.inlay = function(targetLayers, src, targetDataset, opts) {
|
|
39720
39962
|
var mergedDataset = mergeLayersForOverlay(targetLayers, targetDataset, src, opts);
|
|
@@ -42031,49 +42273,13 @@ ${svg}
|
|
|
42031
42273
|
}, {});
|
|
42032
42274
|
}
|
|
42033
42275
|
|
|
42034
|
-
// import { importGeoJSON } from '../geojson/geojson-import';
|
|
42035
|
-
|
|
42036
|
-
function getTargetProxy(target) {
|
|
42037
|
-
var proxy = getLayerInfo(target.layer, target.dataset); // layer_name, feature_count etc
|
|
42038
|
-
proxy.layer = target.layer;
|
|
42039
|
-
proxy.dataset = target.dataset;
|
|
42040
|
-
addGetters(proxy, {
|
|
42041
|
-
// export as an object, not a string or buffer
|
|
42042
|
-
geojson: getGeoJSON
|
|
42043
|
-
});
|
|
42044
|
-
|
|
42045
|
-
function getGeoJSON() {
|
|
42046
|
-
var features = exportLayerAsGeoJSON(target.layer, target.dataset, {rfc7946: true}, true);
|
|
42047
|
-
return {
|
|
42048
|
-
type: 'FeatureCollection',
|
|
42049
|
-
features: features
|
|
42050
|
-
};
|
|
42051
|
-
}
|
|
42052
|
-
|
|
42053
|
-
return proxy;
|
|
42054
|
-
}
|
|
42055
|
-
|
|
42056
42276
|
// Support for evaluating expressions embedded in curly-brace templates
|
|
42057
42277
|
|
|
42058
42278
|
// Returns: a string (e.g. a command string used by the -run command)
|
|
42059
42279
|
async function evalTemplateExpression(expression, targets, ctx) {
|
|
42060
42280
|
ctx = ctx || getBaseContext();
|
|
42061
42281
|
// TODO: throw an error if target is used when there are multiple targets
|
|
42062
|
-
|
|
42063
|
-
var proxies = expandCommandTargets(targets).reduce(function(memo, target) {
|
|
42064
|
-
var proxy = getTargetProxy(target);
|
|
42065
|
-
memo.push(proxy);
|
|
42066
|
-
// index targets by layer name too
|
|
42067
|
-
if (target.layer.name) {
|
|
42068
|
-
memo[target.layer.name] = proxy;
|
|
42069
|
-
}
|
|
42070
|
-
return memo;
|
|
42071
|
-
}, []);
|
|
42072
|
-
Object.defineProperty(ctx, 'targets', {value: proxies});
|
|
42073
|
-
if (proxies.length == 1) {
|
|
42074
|
-
Object.defineProperty(ctx, 'target', {value: proxies[0]});
|
|
42075
|
-
}
|
|
42076
|
-
}
|
|
42282
|
+
addTargetProxies(targets, ctx);
|
|
42077
42283
|
// Add global functions and data to the expression context
|
|
42078
42284
|
// (e.g. functions imported via the -require command)
|
|
42079
42285
|
var globals = getStashedVar('defs') || {};
|
|
@@ -44564,6 +44770,10 @@ ${svg}
|
|
|
44564
44770
|
return done(null);
|
|
44565
44771
|
}
|
|
44566
44772
|
|
|
44773
|
+
if (name == 'comment') {
|
|
44774
|
+
return done(null);
|
|
44775
|
+
}
|
|
44776
|
+
|
|
44567
44777
|
if (!job) job = new Job();
|
|
44568
44778
|
job.startCommand(command);
|
|
44569
44779
|
|
|
@@ -44724,8 +44934,9 @@ ${svg}
|
|
|
44724
44934
|
} else if (name == 'filter-slivers') {
|
|
44725
44935
|
applyCommandToEachLayer(cmd.filterSlivers, targetLayers, targetDataset, opts);
|
|
44726
44936
|
|
|
44727
|
-
|
|
44728
|
-
|
|
44937
|
+
// // 'frame' and 'rectangle' have merged
|
|
44938
|
+
// } else if (name == 'frame') {
|
|
44939
|
+
// cmd.frame(job.catalog, source, opts);
|
|
44729
44940
|
|
|
44730
44941
|
} else if (name == 'fuzzy-join') {
|
|
44731
44942
|
applyCommandToEachLayer(cmd.fuzzyJoin, targetLayers, arcs, source, opts);
|
|
@@ -44793,7 +45004,8 @@ ${svg}
|
|
|
44793
45004
|
outputLayers = cmd.mosaic(targetLayers, targetDataset, opts);
|
|
44794
45005
|
|
|
44795
45006
|
} else if (name == 'o') {
|
|
44796
|
-
|
|
45007
|
+
// kludge
|
|
45008
|
+
outputFiles = await exportTargetLayers(job.catalog, targets, opts);
|
|
44797
45009
|
if (opts.final) {
|
|
44798
45010
|
// don't propagate data if output is final
|
|
44799
45011
|
//// catalog = null;
|
|
@@ -44826,7 +45038,10 @@ ${svg}
|
|
|
44826
45038
|
cmd.proj(targ.dataset, job.catalog, opts);
|
|
44827
45039
|
});
|
|
44828
45040
|
|
|
44829
|
-
} else if (name == 'rectangle') {
|
|
45041
|
+
} else if (name == 'rectangle' || name == 'frame') {
|
|
45042
|
+
if (name == 'frame' && !opts.width) {
|
|
45043
|
+
stop('Command requires a width= argument');
|
|
45044
|
+
}
|
|
44830
45045
|
if (source || opts.bbox || targets.length === 0) {
|
|
44831
45046
|
job.catalog.addDataset(cmd.rectangle(source, opts));
|
|
44832
45047
|
} else {
|
|
@@ -44992,7 +45207,7 @@ ${svg}
|
|
|
44992
45207
|
});
|
|
44993
45208
|
}
|
|
44994
45209
|
|
|
44995
|
-
var version = "0.6.
|
|
45210
|
+
var version = "0.6.66";
|
|
44996
45211
|
|
|
44997
45212
|
// Parse command line args into commands and run them
|
|
44998
45213
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -45734,6 +45949,7 @@ ${svg}
|
|
|
45734
45949
|
Projections,
|
|
45735
45950
|
ProjectionParams,
|
|
45736
45951
|
Rectangle,
|
|
45952
|
+
RectangleUtils,
|
|
45737
45953
|
Rounding,
|
|
45738
45954
|
RunCommands,
|
|
45739
45955
|
Scalebar,
|