mapshaper 0.6.65 → 0.6.67
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 +259 -128
- package/package.json +1 -1
- package/www/index.html +4 -3
- package/www/mapshaper-gui.js +554 -324
- package/www/mapshaper.js +259 -128
- package/www/page.css +11 -4
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) {
|
|
@@ -4140,7 +4195,7 @@
|
|
|
4140
4195
|
[bbox[2], bbox[1]], [bbox[0], bbox[1]]];
|
|
4141
4196
|
}
|
|
4142
4197
|
|
|
4143
|
-
var
|
|
4198
|
+
var RectangleUtils = /*#__PURE__*/Object.freeze({
|
|
4144
4199
|
__proto__: null,
|
|
4145
4200
|
pathIsRectangle: pathIsRectangle,
|
|
4146
4201
|
bboxToCoords: bboxToCoords
|
|
@@ -4186,6 +4241,10 @@
|
|
|
4186
4241
|
return lyr.geometry_type == 'point' && layerHasNonNullShapes(lyr);
|
|
4187
4242
|
}
|
|
4188
4243
|
|
|
4244
|
+
function layerIsRectangle(lyr, arcs) {
|
|
4245
|
+
return layerOnlyHasRectangles(lyr, arcs) && lyr.shapes.length == 1;
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4189
4248
|
function layerOnlyHasRectangles(lyr, arcs) {
|
|
4190
4249
|
if (!layerHasPaths(lyr)) return false;
|
|
4191
4250
|
if (countMultiPartFeatures(lyr) > 0) return false;
|
|
@@ -4438,6 +4497,7 @@
|
|
|
4438
4497
|
layerHasGeometry: layerHasGeometry,
|
|
4439
4498
|
layerHasPaths: layerHasPaths,
|
|
4440
4499
|
layerHasPoints: layerHasPoints,
|
|
4500
|
+
layerIsRectangle: layerIsRectangle,
|
|
4441
4501
|
layerOnlyHasRectangles: layerOnlyHasRectangles,
|
|
4442
4502
|
layerHasNonNullShapes: layerHasNonNullShapes,
|
|
4443
4503
|
deleteFeatureById: deleteFeatureById,
|
|
@@ -13335,6 +13395,19 @@
|
|
|
13335
13395
|
miles: 1609.344 // International Statute Mile
|
|
13336
13396
|
};
|
|
13337
13397
|
|
|
13398
|
+
// str: display size in px, pt or in
|
|
13399
|
+
// using: 72pt per inch, 1pt per pixel.
|
|
13400
|
+
function parseSizeParam(p) {
|
|
13401
|
+
var str = String(p),
|
|
13402
|
+
num = parseFloat(str),
|
|
13403
|
+
units = /px|pix/.test(str) && 'px' || /pt|point/.test(str) && 'pt' ||
|
|
13404
|
+
/in/.test(str) && 'in' || !isNaN(+str) && 'px' || null;
|
|
13405
|
+
if (isNaN(num) || !units) {
|
|
13406
|
+
stop('Invalid size:', str);
|
|
13407
|
+
}
|
|
13408
|
+
return units == 'in' && num * 72 || num;
|
|
13409
|
+
}
|
|
13410
|
+
|
|
13338
13411
|
// Return coeff. for converting a distance measure to dataset coordinates
|
|
13339
13412
|
// @paramUnits: units code of distance param, or null if units are not specified
|
|
13340
13413
|
// @crs: Proj.4 CRS object, or null (unknown latlong CRS);
|
|
@@ -13478,6 +13551,7 @@
|
|
|
13478
13551
|
|
|
13479
13552
|
var Units = /*#__PURE__*/Object.freeze({
|
|
13480
13553
|
__proto__: null,
|
|
13554
|
+
parseSizeParam: parseSizeParam,
|
|
13481
13555
|
getIntervalConversionFactor: getIntervalConversionFactor,
|
|
13482
13556
|
parseMeasure: parseMeasure,
|
|
13483
13557
|
parseMeasure2: parseMeasure2,
|
|
@@ -18155,7 +18229,7 @@
|
|
|
18155
18229
|
var frameLyr = findFrameLayerInDataset(dataset);
|
|
18156
18230
|
var frameData;
|
|
18157
18231
|
if (frameLyr) {
|
|
18158
|
-
frameData =
|
|
18232
|
+
frameData = getFrameLayerData(frameLyr, dataset.arcs);
|
|
18159
18233
|
} else {
|
|
18160
18234
|
frameData = calcFrameData(dataset, exportOpts);
|
|
18161
18235
|
}
|
|
@@ -18163,6 +18237,21 @@
|
|
|
18163
18237
|
return frameData;
|
|
18164
18238
|
}
|
|
18165
18239
|
|
|
18240
|
+
|
|
18241
|
+
function getFrameLayerData(lyr, arcs) {
|
|
18242
|
+
var bounds = getLayerBounds(lyr, arcs);
|
|
18243
|
+
var d = lyr.data.getReadOnlyRecordAt(0);
|
|
18244
|
+
var w = d.width || 800;
|
|
18245
|
+
var h = w * bounds.height() / bounds.width();
|
|
18246
|
+
return {
|
|
18247
|
+
type: 'frame',
|
|
18248
|
+
width: w,
|
|
18249
|
+
height: h,
|
|
18250
|
+
bbox: bounds.toArray()
|
|
18251
|
+
};
|
|
18252
|
+
}
|
|
18253
|
+
|
|
18254
|
+
|
|
18166
18255
|
function calcFrameData(dataset, opts) {
|
|
18167
18256
|
var bounds;
|
|
18168
18257
|
if (opts.svg_bbox) {
|
|
@@ -18180,10 +18269,6 @@
|
|
|
18180
18269
|
};
|
|
18181
18270
|
}
|
|
18182
18271
|
|
|
18183
|
-
function getFrameLayerData(lyr) {
|
|
18184
|
-
return lyr.data && lyr.data.getReadOnlyRecordAt(0);
|
|
18185
|
-
}
|
|
18186
|
-
|
|
18187
18272
|
// Used by mapshaper-frame and mapshaper-pixel-transform. TODO: refactor
|
|
18188
18273
|
function getFrameSize(bounds, opts) {
|
|
18189
18274
|
var aspectRatio = bounds.width() / bounds.height();
|
|
@@ -18199,30 +18284,34 @@
|
|
|
18199
18284
|
|
|
18200
18285
|
|
|
18201
18286
|
// @lyr dataset layer
|
|
18202
|
-
function isFrameLayer(lyr) {
|
|
18203
|
-
return getFurnitureLayerType(lyr) == 'frame'
|
|
18287
|
+
function isFrameLayer(lyr, arcs) {
|
|
18288
|
+
return getFurnitureLayerType(lyr) == 'frame' &&
|
|
18289
|
+
layerIsRectangle(lyr, arcs);
|
|
18204
18290
|
}
|
|
18205
18291
|
|
|
18206
18292
|
function findFrameLayerInDataset(dataset) {
|
|
18207
18293
|
return utils.find(dataset.layers, function(lyr) {
|
|
18208
|
-
return isFrameLayer(lyr);
|
|
18294
|
+
return isFrameLayer(lyr, dataset.arcs);
|
|
18209
18295
|
});
|
|
18210
18296
|
}
|
|
18211
18297
|
|
|
18298
|
+
// TODO: handle multiple frames in catalog
|
|
18212
18299
|
function findFrameDataset(catalog) {
|
|
18213
|
-
var target =
|
|
18214
|
-
|
|
18215
|
-
});
|
|
18216
|
-
return target ? target.dataset : null;
|
|
18300
|
+
var target = findFrame(catalog);
|
|
18301
|
+
return target && target.dataset || null;
|
|
18217
18302
|
}
|
|
18218
18303
|
|
|
18219
18304
|
function findFrameLayer(catalog) {
|
|
18220
|
-
var target =
|
|
18221
|
-
return isFrameLayer(o.layer);
|
|
18222
|
-
});
|
|
18305
|
+
var target = findFrame(catalog);
|
|
18223
18306
|
return target && target.layer || null;
|
|
18224
18307
|
}
|
|
18225
18308
|
|
|
18309
|
+
function findFrame(catalog) {
|
|
18310
|
+
return utils.find(catalog.getLayers(), function(o) {
|
|
18311
|
+
return isFrameLayer(o.layer, o.dataset.arcs);
|
|
18312
|
+
});
|
|
18313
|
+
}
|
|
18314
|
+
|
|
18226
18315
|
function getFrameLayerBounds(lyr) {
|
|
18227
18316
|
return new Bounds(getFurnitureLayerData(lyr).bbox);
|
|
18228
18317
|
}
|
|
@@ -18358,9 +18447,11 @@
|
|
|
18358
18447
|
getFrameData: getFrameData,
|
|
18359
18448
|
getFrameLayerData: getFrameLayerData,
|
|
18360
18449
|
getFrameSize: getFrameSize,
|
|
18450
|
+
isFrameLayer: isFrameLayer,
|
|
18361
18451
|
findFrameLayerInDataset: findFrameLayerInDataset,
|
|
18362
18452
|
findFrameDataset: findFrameDataset,
|
|
18363
18453
|
findFrameLayer: findFrameLayer,
|
|
18454
|
+
findFrame: findFrame,
|
|
18364
18455
|
getFrameLayerBounds: getFrameLayerBounds,
|
|
18365
18456
|
getMapFrameMetersPerPixel: getMapFrameMetersPerPixel,
|
|
18366
18457
|
calcOutputSizeInPixels: calcOutputSizeInPixels,
|
|
@@ -18800,6 +18891,7 @@
|
|
|
18800
18891
|
'font-family': null,
|
|
18801
18892
|
'font-size': null,
|
|
18802
18893
|
'font-style': null,
|
|
18894
|
+
'font-stretch': null,
|
|
18803
18895
|
'font-weight': null,
|
|
18804
18896
|
'label-text': null, // leaving this null
|
|
18805
18897
|
'letter-spacing': 'measure',
|
|
@@ -18849,7 +18941,7 @@
|
|
|
18849
18941
|
polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit')),
|
|
18850
18942
|
point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
|
|
18851
18943
|
label: utils.arrayToIndex(commonProperties.concat(
|
|
18852
|
-
'fill,font-family,font-size,text-anchor,font-weight,font-style,letter-spacing,dominant-baseline'.split(',')))
|
|
18944
|
+
'fill,font-family,font-size,text-anchor,font-weight,font-style,font-stretch,letter-spacing,dominant-baseline'.split(',')))
|
|
18853
18945
|
};
|
|
18854
18946
|
|
|
18855
18947
|
// symType: point, polygon, polyline, label
|
|
@@ -18859,6 +18951,10 @@
|
|
|
18859
18951
|
if (filter && !filter(fields[i])) continue;
|
|
18860
18952
|
setAttribute(svgObj, fields[i], rec[fields[i]]);
|
|
18861
18953
|
}
|
|
18954
|
+
// kludge to prevent default black fill on polygons with stroke styles
|
|
18955
|
+
if ((symType == 'polygon' || symType == 'circle') && rec.stroke && !rec.fill) {
|
|
18956
|
+
setAttribute(svgObj, 'fill', 'none');
|
|
18957
|
+
}
|
|
18862
18958
|
}
|
|
18863
18959
|
|
|
18864
18960
|
function setAttribute(obj, k, v) {
|
|
@@ -19633,83 +19729,9 @@
|
|
|
19633
19729
|
parseScalebarLabelToKm: parseScalebarLabelToKm
|
|
19634
19730
|
});
|
|
19635
19731
|
|
|
19636
|
-
cmd.frame = function(catalog, source, opts) {
|
|
19637
|
-
var size, bounds, tmp, dataset;
|
|
19638
|
-
if (+opts.width > 0 === false && +opts.pixels > 0 === false) {
|
|
19639
|
-
stop("Missing a width or area");
|
|
19640
|
-
}
|
|
19641
|
-
if (opts.width && opts.height) {
|
|
19642
|
-
opts = utils.extend({}, opts);
|
|
19643
|
-
// Height is a string containing either a number or a
|
|
19644
|
-
// comma-sep. pair of numbers (range); here we convert height to
|
|
19645
|
-
// an aspect-ratio parameter for the rectangle() function
|
|
19646
|
-
opts.aspect_ratio = getAspectRatioArg(opts.width, opts.height);
|
|
19647
|
-
// TODO: currently returns max,min aspect ratio, should return in min,max order
|
|
19648
|
-
// (rectangle() function should handle max,min argument correctly now anyway)
|
|
19649
|
-
}
|
|
19650
|
-
tmp = cmd.rectangle(source, opts);
|
|
19651
|
-
bounds = getDatasetBounds(tmp);
|
|
19652
|
-
if (probablyDecimalDegreeBounds(bounds)) {
|
|
19653
|
-
stop('Frames require projected, not geographical coordinates');
|
|
19654
|
-
} else if (!getDatasetCRS(tmp)) {
|
|
19655
|
-
message('Warning: missing projection data. Assuming coordinates are meters and k (scale factor) is 1');
|
|
19656
|
-
}
|
|
19657
|
-
size = getFrameSize(bounds, opts);
|
|
19658
|
-
if (size[0] > 0 === false) {
|
|
19659
|
-
stop('Missing a valid frame width');
|
|
19660
|
-
}
|
|
19661
|
-
if (size[1] > 0 === false) {
|
|
19662
|
-
stop('Missing a valid frame height');
|
|
19663
|
-
}
|
|
19664
|
-
dataset = {info: {}, layers:[{
|
|
19665
|
-
name: opts.name || 'frame',
|
|
19666
|
-
data: new DataTable([{
|
|
19667
|
-
width: size[0],
|
|
19668
|
-
height: size[1],
|
|
19669
|
-
bbox: bounds.toArray(),
|
|
19670
|
-
type: 'frame'
|
|
19671
|
-
}])
|
|
19672
|
-
}]};
|
|
19673
|
-
catalog.addDataset(dataset);
|
|
19674
|
-
};
|
|
19675
|
-
|
|
19676
|
-
|
|
19677
|
-
// Convert width and height args to aspect ratio arg for the rectangle() function
|
|
19678
|
-
function getAspectRatioArg(widthArg, heightArg) {
|
|
19679
|
-
// heightArg is a string containing either a number or a
|
|
19680
|
-
// comma-sep. pair of numbers (range);
|
|
19681
|
-
return heightArg.split(',').map(function(opt) {
|
|
19682
|
-
var height = Number(opt),
|
|
19683
|
-
width = Number(widthArg);
|
|
19684
|
-
if (!opt) return '';
|
|
19685
|
-
return width / height;
|
|
19686
|
-
}).reverse().join(',');
|
|
19687
|
-
}
|
|
19688
|
-
|
|
19689
|
-
function renderFrame(d) {
|
|
19690
|
-
var lineWidth = 1,
|
|
19691
|
-
// inset stroke by half of line width
|
|
19692
|
-
off = lineWidth / 2,
|
|
19693
|
-
obj = importPolygon([[[off, off], [off, d.height - off],
|
|
19694
|
-
[d.width - off, d.height - off],
|
|
19695
|
-
[d.width - off, off], [off, off]]]);
|
|
19696
|
-
utils.extend(obj.properties, {
|
|
19697
|
-
fill: 'none',
|
|
19698
|
-
stroke: d.stroke || 'black',
|
|
19699
|
-
'stroke-width': d['stroke-width'] || lineWidth
|
|
19700
|
-
});
|
|
19701
|
-
return [obj];
|
|
19702
|
-
}
|
|
19703
|
-
|
|
19704
|
-
var Frame = /*#__PURE__*/Object.freeze({
|
|
19705
|
-
__proto__: null,
|
|
19706
|
-
getAspectRatioArg: getAspectRatioArg,
|
|
19707
|
-
renderFrame: renderFrame
|
|
19708
|
-
});
|
|
19709
|
-
|
|
19710
19732
|
var furnitureRenderers = {
|
|
19711
|
-
scalebar: renderScalebar
|
|
19712
|
-
frame: renderFrame
|
|
19733
|
+
scalebar: renderScalebar
|
|
19734
|
+
// frame: renderFrame
|
|
19713
19735
|
};
|
|
19714
19736
|
|
|
19715
19737
|
// @lyr a layer in a dataset
|
|
@@ -22057,7 +22079,13 @@ ${svg}
|
|
|
22057
22079
|
|
|
22058
22080
|
// @targets - non-empty output from Catalog#findCommandTargets()
|
|
22059
22081
|
//
|
|
22060
|
-
async function exportTargetLayers(targets, opts) {
|
|
22082
|
+
async function exportTargetLayers(catalog, targets, opts) {
|
|
22083
|
+
// kludge: get extent of 'fit-extent' layer (if given)
|
|
22084
|
+
if (opts.fit_extent) {
|
|
22085
|
+
var target = catalog.findSingleLayer(opts.fit_extent);
|
|
22086
|
+
var bounds = getLayerBounds(target.layer, target.dataset.arcs);
|
|
22087
|
+
opts = Object.assign({svg_bbox: bounds.toArray()}, opts);
|
|
22088
|
+
}
|
|
22061
22089
|
// convert target fmt to dataset fmt
|
|
22062
22090
|
var datasets = targets.map(function(target) {
|
|
22063
22091
|
return utils.defaults({layers: target.layers}, target.dataset);
|
|
@@ -24139,6 +24167,9 @@ ${svg}
|
|
|
24139
24167
|
describe: '[SVG] bounding box of SVG map in projected map units',
|
|
24140
24168
|
type: 'bbox'
|
|
24141
24169
|
})
|
|
24170
|
+
.option('fit-extent', {
|
|
24171
|
+
describe: '[SVG] layer to use for the map extent'
|
|
24172
|
+
})
|
|
24142
24173
|
.option('point-symbol', {
|
|
24143
24174
|
describe: '[SVG] circle or square (default is circle)'
|
|
24144
24175
|
})
|
|
@@ -25083,12 +25114,16 @@ ${svg}
|
|
|
25083
25114
|
.validate(validateProjOpts);
|
|
25084
25115
|
|
|
25085
25116
|
parser.command('rectangle')
|
|
25086
|
-
.describe('create a rectangle from a bbox or target layer
|
|
25117
|
+
.describe('create a rectangle from a bbox or target layer')
|
|
25087
25118
|
.option('bbox', {
|
|
25088
25119
|
describe: 'rectangle coordinates (xmin,ymin,xmax,ymax)',
|
|
25089
25120
|
type: 'bbox'
|
|
25090
25121
|
})
|
|
25091
25122
|
.option('offset', offsetOpt)
|
|
25123
|
+
.option('width', {
|
|
25124
|
+
describe: 'set width of map in pixels, use rectangle as frame'
|
|
25125
|
+
// type: 'number' // use string, to allow units (e.g. in, px, pt)
|
|
25126
|
+
})
|
|
25092
25127
|
.option('aspect-ratio', aspectRatioOpt)
|
|
25093
25128
|
.option('source', {
|
|
25094
25129
|
describe: 'name of layer to enclose'
|
|
@@ -25364,7 +25399,10 @@ ${svg}
|
|
|
25364
25399
|
.option('font-style', {
|
|
25365
25400
|
describe: 'CSS font style property of labels (e.g. italic)'
|
|
25366
25401
|
})
|
|
25367
|
-
|
|
25402
|
+
.option('font-stretch', {
|
|
25403
|
+
describe: 'CSS font stretch property of labels (e.g. condensed)'
|
|
25404
|
+
})
|
|
25405
|
+
.option('letter-spacing', {
|
|
25368
25406
|
describe: 'CSS letter-spacing property of labels'
|
|
25369
25407
|
})
|
|
25370
25408
|
.option('line-height', {
|
|
@@ -25656,20 +25694,20 @@ ${svg}
|
|
|
25656
25694
|
describe: 'frame coordinates (xmin,ymin,xmax,ymax)',
|
|
25657
25695
|
type: 'bbox'
|
|
25658
25696
|
})
|
|
25659
|
-
.option('offset', offsetOpt)
|
|
25697
|
+
// .option('offset', offsetOpt)
|
|
25660
25698
|
.option('width', {
|
|
25661
|
-
describe: '
|
|
25662
|
-
})
|
|
25663
|
-
.option('height', {
|
|
25664
|
-
describe: 'pixel height of output (may be a range)'
|
|
25665
|
-
})
|
|
25666
|
-
.option('pixels', {
|
|
25667
|
-
describe: 'area of output in pixels (alternative to width and height)',
|
|
25668
|
-
type: 'number'
|
|
25669
|
-
})
|
|
25670
|
-
.option('source', {
|
|
25671
|
-
describe: 'name of layer to enclose'
|
|
25699
|
+
describe: 'width of output (default is 800px)'
|
|
25672
25700
|
})
|
|
25701
|
+
// .option('height', {
|
|
25702
|
+
// describe: 'pixel height of output (may be a range)'
|
|
25703
|
+
// })
|
|
25704
|
+
// .option('pixels', {
|
|
25705
|
+
// describe: 'area of output in pixels (alternative to width and height)',
|
|
25706
|
+
// type: 'number'
|
|
25707
|
+
// })
|
|
25708
|
+
// .option('source', {
|
|
25709
|
+
// describe: 'name of layer to enclose'
|
|
25710
|
+
// })
|
|
25673
25711
|
.option('name', nameOpt);
|
|
25674
25712
|
|
|
25675
25713
|
parser.command('fuzzy-join')
|
|
@@ -37668,6 +37706,79 @@ ${svg}
|
|
|
37668
37706
|
return parsed[0];
|
|
37669
37707
|
}
|
|
37670
37708
|
|
|
37709
|
+
cmd.frame = function(catalog, source, opts) {
|
|
37710
|
+
var size, bounds, tmp, dataset;
|
|
37711
|
+
if (+opts.width > 0 === false && +opts.pixels > 0 === false) {
|
|
37712
|
+
stop("Missing a width or area");
|
|
37713
|
+
}
|
|
37714
|
+
if (opts.width && opts.height) {
|
|
37715
|
+
opts = utils.extend({}, opts);
|
|
37716
|
+
// Height is a string containing either a number or a
|
|
37717
|
+
// comma-sep. pair of numbers (range); here we convert height to
|
|
37718
|
+
// an aspect-ratio parameter for the rectangle() function
|
|
37719
|
+
opts.aspect_ratio = getAspectRatioArg(opts.width, opts.height);
|
|
37720
|
+
// TODO: currently returns max,min aspect ratio, should return in min,max order
|
|
37721
|
+
// (rectangle() function should handle max,min argument correctly now anyway)
|
|
37722
|
+
}
|
|
37723
|
+
tmp = cmd.rectangle(source, opts);
|
|
37724
|
+
bounds = getDatasetBounds(tmp);
|
|
37725
|
+
if (probablyDecimalDegreeBounds(bounds)) {
|
|
37726
|
+
stop('Frames require projected, not geographical coordinates');
|
|
37727
|
+
} else if (!getDatasetCRS(tmp)) {
|
|
37728
|
+
message('Warning: missing projection data. Assuming coordinates are meters and k (scale factor) is 1');
|
|
37729
|
+
}
|
|
37730
|
+
size = getFrameSize(bounds, opts);
|
|
37731
|
+
if (size[0] > 0 === false) {
|
|
37732
|
+
stop('Missing a valid frame width');
|
|
37733
|
+
}
|
|
37734
|
+
if (size[1] > 0 === false) {
|
|
37735
|
+
stop('Missing a valid frame height');
|
|
37736
|
+
}
|
|
37737
|
+
dataset = {info: {}, layers:[{
|
|
37738
|
+
name: opts.name || 'frame',
|
|
37739
|
+
data: new DataTable([{
|
|
37740
|
+
width: size[0],
|
|
37741
|
+
height: size[1],
|
|
37742
|
+
bbox: bounds.toArray(),
|
|
37743
|
+
type: 'frame'
|
|
37744
|
+
}])
|
|
37745
|
+
}]};
|
|
37746
|
+
catalog.addDataset(dataset);
|
|
37747
|
+
};
|
|
37748
|
+
|
|
37749
|
+
|
|
37750
|
+
// Convert width and height args to aspect ratio arg for the rectangle() function
|
|
37751
|
+
function getAspectRatioArg(widthArg, heightArg) {
|
|
37752
|
+
// heightArg is a string containing either a number or a
|
|
37753
|
+
// comma-sep. pair of numbers (range);
|
|
37754
|
+
return heightArg.split(',').map(function(opt) {
|
|
37755
|
+
var height = Number(opt),
|
|
37756
|
+
width = Number(widthArg);
|
|
37757
|
+
if (!opt) return '';
|
|
37758
|
+
return width / height;
|
|
37759
|
+
}).reverse().join(',');
|
|
37760
|
+
}
|
|
37761
|
+
|
|
37762
|
+
// export function renderFrame(d) {
|
|
37763
|
+
// var lineWidth = 1,
|
|
37764
|
+
// // inset stroke by half of line width
|
|
37765
|
+
// off = lineWidth / 2,
|
|
37766
|
+
// obj = importPolygon([[[off, off], [off, d.height - off],
|
|
37767
|
+
// [d.width - off, d.height - off],
|
|
37768
|
+
// [d.width - off, off], [off, off]]]);
|
|
37769
|
+
// utils.extend(obj.properties, {
|
|
37770
|
+
// fill: 'none',
|
|
37771
|
+
// stroke: d.stroke || 'black',
|
|
37772
|
+
// 'stroke-width': d['stroke-width'] || lineWidth
|
|
37773
|
+
// });
|
|
37774
|
+
// return [obj];
|
|
37775
|
+
// }
|
|
37776
|
+
|
|
37777
|
+
var Frame = /*#__PURE__*/Object.freeze({
|
|
37778
|
+
__proto__: null,
|
|
37779
|
+
getAspectRatioArg: getAspectRatioArg
|
|
37780
|
+
});
|
|
37781
|
+
|
|
37671
37782
|
cmd.filterIslands = function(lyr, dataset, optsArg) {
|
|
37672
37783
|
var opts = utils.extend({sliver_control: 0}, optsArg); // no sliver control
|
|
37673
37784
|
var arcs = dataset.arcs;
|
|
@@ -38408,7 +38519,7 @@ ${svg}
|
|
|
38408
38519
|
getPointFeatureBounds(shp) : targetDataset.arcs.getMultiShapeBounds(shp);
|
|
38409
38520
|
bounds = applyRectangleOptions(bounds, crsInfo.crs, opts);
|
|
38410
38521
|
if (!bounds) return null;
|
|
38411
|
-
return
|
|
38522
|
+
return bboxToPolygon(bounds.toArray(), opts);
|
|
38412
38523
|
});
|
|
38413
38524
|
var geojson = {
|
|
38414
38525
|
type: 'FeatureCollection',
|
|
@@ -38434,6 +38545,13 @@ ${svg}
|
|
|
38434
38545
|
// Create rectangles around one or more target layers
|
|
38435
38546
|
//
|
|
38436
38547
|
cmd.rectangle2 = function(target, opts) {
|
|
38548
|
+
// if target layer is a rectangle and we're applying frame properties,
|
|
38549
|
+
// turn the target into a frame instead of creating a new rectangle
|
|
38550
|
+
if (target.layers.length == 1 && opts.width &&
|
|
38551
|
+
layerIsRectangle(target.layers[0], target.dataset.arcs)) {
|
|
38552
|
+
applyFrameProperties(target.layers[0], opts);
|
|
38553
|
+
return;
|
|
38554
|
+
}
|
|
38437
38555
|
var datasets = target.layers.map(function(lyr) {
|
|
38438
38556
|
var dataset = cmd.rectangle({layer: lyr, dataset: target.dataset}, opts);
|
|
38439
38557
|
setOutputLayerName(dataset.layers[0], lyr, null, opts);
|
|
@@ -38458,13 +38576,26 @@ ${svg}
|
|
|
38458
38576
|
if (!bounds || !bounds.hasBounds()) {
|
|
38459
38577
|
stop('Missing rectangle extent');
|
|
38460
38578
|
}
|
|
38461
|
-
var
|
|
38462
|
-
|
|
38579
|
+
var feature = {
|
|
38580
|
+
type: 'Feature',
|
|
38581
|
+
properties: {},
|
|
38582
|
+
geometry: bboxToPolygon(bounds.toArray(), opts)
|
|
38583
|
+
};
|
|
38584
|
+
var dataset = importGeoJSON(feature, {});
|
|
38585
|
+
applyFrameProperties(dataset.layers[0], opts);
|
|
38463
38586
|
dataset.layers[0].name = opts.name || 'rectangle';
|
|
38464
38587
|
setDatasetCrsInfo(dataset, crsInfo);
|
|
38465
38588
|
return dataset;
|
|
38466
38589
|
};
|
|
38467
38590
|
|
|
38591
|
+
function applyFrameProperties(lyr, opts) {
|
|
38592
|
+
if (!opts.width) return;
|
|
38593
|
+
if (!lyr.data) initDataTable(lyr);
|
|
38594
|
+
var d = lyr.data.getRecords()[0] || {};
|
|
38595
|
+
d.width = parseSizeParam(opts.width);
|
|
38596
|
+
d.type = 'frame';
|
|
38597
|
+
}
|
|
38598
|
+
|
|
38468
38599
|
function applyRectangleOptions(bounds, crs, opts) {
|
|
38469
38600
|
var isGeoBox = probablyDecimalDegreeBounds(bounds);
|
|
38470
38601
|
if (opts.offset) {
|
|
@@ -38509,16 +38640,13 @@ ${svg}
|
|
|
38509
38640
|
return bounds;
|
|
38510
38641
|
}
|
|
38511
38642
|
|
|
38512
|
-
function
|
|
38643
|
+
function bboxToPolygon(bbox, optsArg) {
|
|
38513
38644
|
var opts = optsArg || {};
|
|
38514
38645
|
var coords = bboxToCoords(bbox);
|
|
38515
38646
|
if (opts.interval > 0) {
|
|
38516
38647
|
coords = densifyPathByInterval(coords, opts.interval);
|
|
38517
38648
|
}
|
|
38518
|
-
return
|
|
38519
|
-
type: 'LineString',
|
|
38520
|
-
coordinates: coords
|
|
38521
|
-
} : {
|
|
38649
|
+
return {
|
|
38522
38650
|
type: 'Polygon',
|
|
38523
38651
|
coordinates: [coords]
|
|
38524
38652
|
};
|
|
@@ -38527,7 +38655,7 @@ ${svg}
|
|
|
38527
38655
|
var Rectangle = /*#__PURE__*/Object.freeze({
|
|
38528
38656
|
__proto__: null,
|
|
38529
38657
|
applyAspectRatio: applyAspectRatio,
|
|
38530
|
-
|
|
38658
|
+
bboxToPolygon: bboxToPolygon
|
|
38531
38659
|
});
|
|
38532
38660
|
|
|
38533
38661
|
function getSemiMinorAxis(P) {
|
|
@@ -39081,8 +39209,7 @@ ${svg}
|
|
|
39081
39209
|
var rotation = getRotationParams(dest);
|
|
39082
39210
|
if (!bbox) error('Missing expected clip bbox.');
|
|
39083
39211
|
opts = Object.assign({interval: 0.5}, opts); // make sure edges can curve
|
|
39084
|
-
var
|
|
39085
|
-
var dataset = importGeoJSON(geojson);
|
|
39212
|
+
var dataset = importGeoJSON(bboxToPolygon(bbox, opts));
|
|
39086
39213
|
if (rotation) {
|
|
39087
39214
|
rotateDataset(dataset, {rotation: rotation, invert: true});
|
|
39088
39215
|
}
|
|
@@ -39271,7 +39398,7 @@ ${svg}
|
|
|
39271
39398
|
var e = 1e-8;
|
|
39272
39399
|
var bbox = [lon-e, -91, lon+e, 91];
|
|
39273
39400
|
// densify (so cut line can curve, e.g. Cupola projection)
|
|
39274
|
-
var geojson =
|
|
39401
|
+
var geojson = bboxToPolygon(bbox, {interval: 0.5});
|
|
39275
39402
|
var clip = importGeoJSON(geojson);
|
|
39276
39403
|
clipLayersInPlace(pathLayers, clip, dataset, 'erase');
|
|
39277
39404
|
}
|
|
@@ -39574,7 +39701,6 @@ ${svg}
|
|
|
39574
39701
|
|
|
39575
39702
|
function createProjectedGraticule(dest, opts) {
|
|
39576
39703
|
var src = parseCrsString('wgs84');
|
|
39577
|
-
// var outline = getOutlineDataset(src, dest, {inset: 0, geometry_type: 'polyline'});
|
|
39578
39704
|
var outline = getOutlineDataset(src, dest, {});
|
|
39579
39705
|
var graticule = importGeoJSON(createGraticule(dest, !!outline, opts));
|
|
39580
39706
|
projectDataset(graticule, src, dest, {no_clip: false}); // TODO: densify?
|
|
@@ -44825,8 +44951,9 @@ ${svg}
|
|
|
44825
44951
|
} else if (name == 'filter-slivers') {
|
|
44826
44952
|
applyCommandToEachLayer(cmd.filterSlivers, targetLayers, targetDataset, opts);
|
|
44827
44953
|
|
|
44828
|
-
|
|
44829
|
-
|
|
44954
|
+
// // 'frame' and 'rectangle' have merged
|
|
44955
|
+
// } else if (name == 'frame') {
|
|
44956
|
+
// cmd.frame(job.catalog, source, opts);
|
|
44830
44957
|
|
|
44831
44958
|
} else if (name == 'fuzzy-join') {
|
|
44832
44959
|
applyCommandToEachLayer(cmd.fuzzyJoin, targetLayers, arcs, source, opts);
|
|
@@ -44894,7 +45021,8 @@ ${svg}
|
|
|
44894
45021
|
outputLayers = cmd.mosaic(targetLayers, targetDataset, opts);
|
|
44895
45022
|
|
|
44896
45023
|
} else if (name == 'o') {
|
|
44897
|
-
|
|
45024
|
+
// kludge
|
|
45025
|
+
outputFiles = await exportTargetLayers(job.catalog, targets, opts);
|
|
44898
45026
|
if (opts.final) {
|
|
44899
45027
|
// don't propagate data if output is final
|
|
44900
45028
|
//// catalog = null;
|
|
@@ -44927,7 +45055,10 @@ ${svg}
|
|
|
44927
45055
|
cmd.proj(targ.dataset, job.catalog, opts);
|
|
44928
45056
|
});
|
|
44929
45057
|
|
|
44930
|
-
} else if (name == 'rectangle') {
|
|
45058
|
+
} else if (name == 'rectangle' || name == 'frame') {
|
|
45059
|
+
if (name == 'frame' && !opts.width) {
|
|
45060
|
+
stop('Command requires a width= argument');
|
|
45061
|
+
}
|
|
44931
45062
|
if (source || opts.bbox || targets.length === 0) {
|
|
44932
45063
|
job.catalog.addDataset(cmd.rectangle(source, opts));
|
|
44933
45064
|
} else {
|
|
@@ -45093,7 +45224,7 @@ ${svg}
|
|
|
45093
45224
|
});
|
|
45094
45225
|
}
|
|
45095
45226
|
|
|
45096
|
-
var version = "0.6.
|
|
45227
|
+
var version = "0.6.67";
|
|
45097
45228
|
|
|
45098
45229
|
// Parse command line args into commands and run them
|
|
45099
45230
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
|
@@ -45835,7 +45966,7 @@ ${svg}
|
|
|
45835
45966
|
Projections,
|
|
45836
45967
|
ProjectionParams,
|
|
45837
45968
|
Rectangle,
|
|
45838
|
-
|
|
45969
|
+
RectangleUtils,
|
|
45839
45970
|
Rounding,
|
|
45840
45971
|
RunCommands,
|
|
45841
45972
|
Scalebar,
|
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -104,8 +104,8 @@
|
|
|
104
104
|
<h4>Source files</h4>
|
|
105
105
|
<div class="file-list"></div>
|
|
106
106
|
<div>
|
|
107
|
-
<div id="add-file-btn" class="dialog-btn btn">Add
|
|
108
|
-
|
|
107
|
+
<div id="add-file-btn" class="dialog-btn btn">Add files</div>
|
|
108
|
+
<div id="add-empty-btn" class="dialog-btn btn">Add empty layer</div>
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
111
111
|
</div>
|
|
@@ -134,7 +134,8 @@
|
|
|
134
134
|
<div class="filter-btn btn dialog-btn">Keep</div>
|
|
135
135
|
<div class="duplicate-btn btn dialog-btn">Duplicate</div>
|
|
136
136
|
<div class="split-btn btn dialog-btn">Split</div>
|
|
137
|
-
<div class="coords-btn btn dialog-btn">Coords</div>
|
|
137
|
+
<div class="coords-btn btn dialog-btn toggle-btn">Coords</div>
|
|
138
|
+
<div class="data-btn btn dialog-btn toggle-btn">Edit data</div>
|
|
138
139
|
<div class="cancel-btn btn dialog-btn">Clear</div>
|
|
139
140
|
</div>
|
|
140
141
|
<div class="box-coords selectable"></div>
|