mapshaper 0.6.67 → 0.6.68
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 +170 -90
- package/package.json +1 -1
- package/www/mapshaper-gui.js +159 -112
- package/www/mapshaper.js +170 -90
package/mapshaper.js
CHANGED
|
@@ -14726,6 +14726,9 @@
|
|
|
14726
14726
|
bounds: function() {
|
|
14727
14727
|
return shapeBounds().toArray();
|
|
14728
14728
|
},
|
|
14729
|
+
bbox: function() {
|
|
14730
|
+
return shapeBounds().toArray();
|
|
14731
|
+
},
|
|
14729
14732
|
height: function() {
|
|
14730
14733
|
return shapeBounds().height();
|
|
14731
14734
|
},
|
|
@@ -17323,9 +17326,10 @@
|
|
|
17323
17326
|
}
|
|
17324
17327
|
|
|
17325
17328
|
function getGapRemovalMessage(removed, retained, areaLabel) {
|
|
17329
|
+
var tot = removed + retained;
|
|
17326
17330
|
if (removed > 0 === false) return '';
|
|
17327
|
-
return utils.format('Removed %,d
|
|
17328
|
-
removed,
|
|
17331
|
+
return utils.format('Removed %,d of %,d sliver%s using %s',
|
|
17332
|
+
removed, tot, utils.pluralSuffix(tot), areaLabel);
|
|
17329
17333
|
}
|
|
17330
17334
|
|
|
17331
17335
|
function dissolvePolygonGroups2(groups, lyr, dataset, opts) {
|
|
@@ -19274,12 +19278,12 @@
|
|
|
19274
19278
|
// Kludge for applying fill and other styles to a <text> element
|
|
19275
19279
|
// (for rendering labels in the GUI with the dot in Canvas, not SVG)
|
|
19276
19280
|
function renderStyledLabel(rec) {
|
|
19277
|
-
var o = renderLabel(rec);
|
|
19281
|
+
var o = renderLabel$1(rec);
|
|
19278
19282
|
applyStyleAttributes(o, 'label', rec);
|
|
19279
19283
|
return o;
|
|
19280
19284
|
}
|
|
19281
19285
|
|
|
19282
|
-
function renderLabel(rec) {
|
|
19286
|
+
function renderLabel$1(rec) {
|
|
19283
19287
|
var line = toLabelString(rec['label-text']);
|
|
19284
19288
|
var morelines, obj;
|
|
19285
19289
|
// Accepting \n (two chars) as an alternative to the newline character
|
|
@@ -19324,7 +19328,7 @@
|
|
|
19324
19328
|
var SvgLabels = /*#__PURE__*/Object.freeze({
|
|
19325
19329
|
__proto__: null,
|
|
19326
19330
|
renderStyledLabel: renderStyledLabel,
|
|
19327
|
-
renderLabel: renderLabel
|
|
19331
|
+
renderLabel: renderLabel$1
|
|
19328
19332
|
});
|
|
19329
19333
|
|
|
19330
19334
|
// convert data records (properties like svg-symbol, label-text, fill, r) to svg symbols
|
|
@@ -19536,13 +19540,64 @@
|
|
|
19536
19540
|
};
|
|
19537
19541
|
}
|
|
19538
19542
|
|
|
19539
|
-
|
|
19540
|
-
|
|
19541
|
-
|
|
19542
|
-
|
|
19543
|
-
|
|
19544
|
-
|
|
19543
|
+
function renderScalebar(d, frame) {
|
|
19544
|
+
if (!frame.crs) {
|
|
19545
|
+
message('Unable to render scalebar: unknown CRS.');
|
|
19546
|
+
return [];
|
|
19547
|
+
}
|
|
19548
|
+
if (frame.width > 0 === false) {
|
|
19549
|
+
return [];
|
|
19550
|
+
}
|
|
19551
|
+
|
|
19552
|
+
var opts = getScalebarOpts(d);
|
|
19553
|
+
var metersPerPx = getMapFrameMetersPerPixel(frame);
|
|
19554
|
+
var frameWidthPx = frame.width;
|
|
19555
|
+
var labels = d.label ? d.label.split(',') : null;
|
|
19556
|
+
var label1 = labels && labels[0] || null;
|
|
19557
|
+
var props1 = parseScalebarLabel(label1 || getAutoScalebarLabel(frameWidthPx, metersPerPx, 'mile'));
|
|
19558
|
+
var label2 = opts.style == 'b' && labels && labels[1] || null;
|
|
19559
|
+
var props2, length2;
|
|
19560
|
+
|
|
19561
|
+
if (props1.km > 0 === false) {
|
|
19562
|
+
message('Unusable scalebar label:', label1);
|
|
19563
|
+
return [];
|
|
19564
|
+
}
|
|
19565
|
+
|
|
19566
|
+
var length1 = Math.round(props1.km / metersPerPx * 1000);
|
|
19567
|
+
if (length1 > 0 === false) {
|
|
19568
|
+
stop("Null scalebar length");
|
|
19569
|
+
}
|
|
19570
|
+
|
|
19571
|
+
if (label2) {
|
|
19572
|
+
props2 = parseScalebarLabel(label2);
|
|
19573
|
+
length2 = Math.round(props2.km / metersPerPx * 1000);
|
|
19574
|
+
if (length2 > length1) {
|
|
19575
|
+
stop("First part of a dual-unit scalebar must be longer than the second part.");
|
|
19576
|
+
}
|
|
19577
|
+
}
|
|
19578
|
+
|
|
19579
|
+
var barPos = getScalebarPosition(opts);
|
|
19580
|
+
var labelPos = getLabelPosition(opts);
|
|
19581
|
+
var dx = barPos.xpos == 'right' ? frameWidthPx - length1 - opts.margin : opts.margin;
|
|
19582
|
+
var dy = barPos.ypos == 'bottom' ? frame.height - opts.margin : opts.margin;
|
|
19583
|
+
|
|
19584
|
+
// vshift to adjust for height above or below the baseline
|
|
19585
|
+
var labelHeight = Math.round(opts.label_offset + opts.tic_length + opts.font_size * 0.8 + opts.bar_width / 2);
|
|
19586
|
+
var bareHeight = Math.round(opts.bar_width / 2);
|
|
19587
|
+
var topHeight = labelPos.ypos == 'top' || label2 ? labelHeight : bareHeight;
|
|
19588
|
+
var bottomHeight = labelPos.ypos == 'bottom' || label2 ? labelHeight : bareHeight;
|
|
19589
|
+
if (barPos.ypos == 'top') {
|
|
19590
|
+
dy += topHeight;
|
|
19591
|
+
} else {
|
|
19592
|
+
dy -= bottomHeight;
|
|
19593
|
+
}
|
|
19594
|
+
|
|
19595
|
+
var g = renderAsSvg(length1, label1, length2, label2, opts);
|
|
19596
|
+
g.properties = {
|
|
19597
|
+
transform: 'translate(' + dx + ' ' + dy + ')'
|
|
19545
19598
|
};
|
|
19599
|
+
|
|
19600
|
+
return [g];
|
|
19546
19601
|
}
|
|
19547
19602
|
|
|
19548
19603
|
var styleOpts = {
|
|
@@ -19569,105 +19624,112 @@
|
|
|
19569
19624
|
return Object.assign({}, defaultOpts, styleOpts[style], d, {style: style});
|
|
19570
19625
|
}
|
|
19571
19626
|
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19627
|
+
function renderAsSvg(length, text, length2, text2, opts) {
|
|
19628
|
+
var labelPart = renderLabel(text, length, opts);
|
|
19629
|
+
var zeroLabelPart = renderLabel('0', length, Object.assign({flipx: true}, opts));
|
|
19630
|
+
var barPart = renderBar(length, length2, opts);
|
|
19631
|
+
var parts = opts.style == 'b' ? [zeroLabelPart, labelPart, barPart] : [labelPart, barPart];
|
|
19632
|
+
if (text2) {
|
|
19633
|
+
parts.push(renderLabel(text2, length2, Object.assign({flipy: true}, opts)));
|
|
19634
|
+
parts.push(renderLabel('0', length2, Object.assign({flipx: true, flipy: true}, opts)));
|
|
19635
|
+
}
|
|
19636
|
+
return {
|
|
19637
|
+
tag: 'g',
|
|
19638
|
+
children: parts
|
|
19639
|
+
};
|
|
19576
19640
|
}
|
|
19577
19641
|
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
var
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19642
|
+
// TODO: generalize to other kinds of furniture as they are developed
|
|
19643
|
+
function getScalebarPosition(opts) {
|
|
19644
|
+
var pos = opts.position || 'top-left';
|
|
19645
|
+
return {
|
|
19646
|
+
ypos: pos.includes('top') ? 'top' : 'bottom',
|
|
19647
|
+
xpos: pos.includes('left') ? 'left' : 'right'
|
|
19648
|
+
};
|
|
19649
|
+
}
|
|
19650
|
+
|
|
19651
|
+
function renderLabel(text, length, opts) {
|
|
19652
|
+
var labelPos = getLabelPosition(opts);
|
|
19653
|
+
var anchorX = length * labelPos.kx + labelPos.dx;
|
|
19654
|
+
var bottomLabelY = opts.bar_width + opts.tic_length + opts.label_offset;
|
|
19655
|
+
var topLabelY = -opts.label_offset - opts.tic_length;
|
|
19656
|
+
var anchorY = labelPos.ypos == 'top' ? topLabelY : bottomLabelY;
|
|
19587
19657
|
var labelOpts = {
|
|
19588
19658
|
'label-text': text,
|
|
19589
19659
|
'font-size': opts.font_size,
|
|
19590
|
-
'text-anchor':
|
|
19591
|
-
'dominant-baseline':
|
|
19660
|
+
'text-anchor': labelPos.anchor,
|
|
19661
|
+
'dominant-baseline': labelPos.ypos == 'top' ? 'auto' : 'hanging'
|
|
19592
19662
|
//// 'dominant-baseline': labelPos == 'top' ? 'text-after-edge' : 'text-before-edge'
|
|
19593
19663
|
// 'text-after-edge' is buggy in Safari and unsupported by Illustrator,
|
|
19594
19664
|
// so I'm using 'hanging' and 'auto', which seem to be well supported.
|
|
19595
19665
|
// downside: requires a kludgy multiplier to calculate scalebar height (see above)
|
|
19596
19666
|
};
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
var zeroLabel = symbolRenderers.label(zeroOpts, -xOff, anchorY);
|
|
19667
|
+
return symbolRenderers.label(labelOpts, anchorX, anchorY);
|
|
19668
|
+
}
|
|
19600
19669
|
|
|
19601
|
-
|
|
19602
|
-
var
|
|
19603
|
-
var
|
|
19604
|
-
var
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
if (opts.tic_length > 0) {
|
|
19609
|
-
coords = [[0, y2], [0, y], [length, y], [length, y2]];
|
|
19670
|
+
function getLabelPosition(opts) {
|
|
19671
|
+
var pos = opts.label_position;
|
|
19672
|
+
var ypos = pos.includes('bottom') && 'bottom' || 'top';
|
|
19673
|
+
var dx = 0;
|
|
19674
|
+
var xpos;
|
|
19675
|
+
if (opts.style == 'a') {
|
|
19676
|
+
xpos = pos.includes('center') && 'center' || pos.includes('right') && 'right' || 'left';
|
|
19610
19677
|
} else {
|
|
19611
|
-
|
|
19678
|
+
xpos = 'right'; // style b
|
|
19679
|
+
}
|
|
19680
|
+
if (opts.flipx) {
|
|
19681
|
+
xpos = xpos == 'left' && 'right' || xpos == 'right' && 'left' || xpos;
|
|
19682
|
+
}
|
|
19683
|
+
if (opts.flipy) {
|
|
19684
|
+
ypos = ypos == 'top' && 'bottom' || ypos == 'bottom' && 'top' || ypos;
|
|
19685
|
+
}
|
|
19686
|
+
if (opts.style == 'b') {
|
|
19687
|
+
dx = xpos == 'left' && -opts.font_size / 4 || xpos == 'right' && opts.font_size / 4 || 0;
|
|
19612
19688
|
}
|
|
19613
|
-
var barPart = importLineString(coords);
|
|
19614
|
-
Object.assign(barPart.properties, {
|
|
19615
|
-
stroke: 'black',
|
|
19616
|
-
fill: 'none',
|
|
19617
|
-
'stroke-width': opts.bar_width,
|
|
19618
|
-
'stroke-linecap': 'butt',
|
|
19619
|
-
'stroke-linejoin': 'miter'
|
|
19620
|
-
});
|
|
19621
|
-
var parts = opts.style == 'b' ? [zeroLabel, labelPart, barPart] : [labelPart, barPart];
|
|
19622
19689
|
return {
|
|
19623
|
-
|
|
19624
|
-
|
|
19690
|
+
xpos,
|
|
19691
|
+
ypos,
|
|
19692
|
+
dx,
|
|
19693
|
+
kx: xpos == 'right' && 1 || xpos == 'center' && 0.5 || 0,
|
|
19694
|
+
anchor: xpos == 'center' && 'middle' || xpos == 'left' && 'start' || 'end'
|
|
19625
19695
|
};
|
|
19626
19696
|
}
|
|
19627
19697
|
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
var opts = getScalebarOpts(d);
|
|
19638
|
-
var metersPerPx = getMapFrameMetersPerPixel(frame);
|
|
19639
|
-
var frameWidthPx = frame.width;
|
|
19640
|
-
var unit = d.label ? parseScalebarUnits(d.label) : 'mile';
|
|
19641
|
-
var number = d.label ? parseScalebarNumber(d.label) : null;
|
|
19642
|
-
var label = number && unit ? d.label : getAutoScalebarLabel(frameWidthPx, metersPerPx, unit);
|
|
19643
|
-
|
|
19644
|
-
var scalebarKm = parseScalebarLabelToKm(label);
|
|
19645
|
-
if (scalebarKm > 0 === false) {
|
|
19646
|
-
message('Unusable scalebar label:', label);
|
|
19647
|
-
return [];
|
|
19698
|
+
// length1: length of main bar
|
|
19699
|
+
// length2: length of optional second distance (assumes that length2 <= length1)
|
|
19700
|
+
function getStyleBCoords(length1, length2, opts) {
|
|
19701
|
+
var coords = [];
|
|
19702
|
+
var labelPos = getLabelPosition(opts);
|
|
19703
|
+
var y = opts.tic_length + opts.bar_width / 2;
|
|
19704
|
+
if (labelPos.ypos == "top") {
|
|
19705
|
+
y = -y;
|
|
19648
19706
|
}
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19707
|
+
coords.push([[0, y], [0, 0], [length1, 0], [length1, y]]);
|
|
19708
|
+
if (length2 > 0) {
|
|
19709
|
+
coords.push([[0, 0], [0, -y]]);
|
|
19710
|
+
coords.push([[length2, 0], [length2, -y]]);
|
|
19653
19711
|
}
|
|
19712
|
+
return coords;
|
|
19713
|
+
}
|
|
19654
19714
|
|
|
19655
|
-
|
|
19656
|
-
|
|
19657
|
-
|
|
19658
|
-
var
|
|
19659
|
-
if (opts.
|
|
19660
|
-
|
|
19715
|
+
// length: length of scale bar in px
|
|
19716
|
+
// length2: length of optional dual-units portion of the scalebar
|
|
19717
|
+
function renderBar(length, length2, opts) {
|
|
19718
|
+
var coords;
|
|
19719
|
+
if (opts.style == 'b') {
|
|
19720
|
+
coords = getStyleBCoords(length, length2, opts);
|
|
19661
19721
|
} else {
|
|
19662
|
-
|
|
19722
|
+
coords = [[[0, 0], [length, 0]]];
|
|
19663
19723
|
}
|
|
19664
|
-
|
|
19665
|
-
|
|
19666
|
-
|
|
19667
|
-
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
|
|
19724
|
+
var bar = importMultiLineString(coords);
|
|
19725
|
+
Object.assign(bar.properties, {
|
|
19726
|
+
stroke: 'black',
|
|
19727
|
+
fill: 'none',
|
|
19728
|
+
'stroke-width': opts.bar_width,
|
|
19729
|
+
'stroke-linecap': 'butt',
|
|
19730
|
+
'stroke-linejoin': 'miter'
|
|
19731
|
+
});
|
|
19732
|
+
return bar;
|
|
19671
19733
|
}
|
|
19672
19734
|
|
|
19673
19735
|
// unit: 'km' || 'mile'
|
|
@@ -19701,6 +19763,20 @@
|
|
|
19701
19763
|
return units == 'mile' ? value * 1.60934 : value;
|
|
19702
19764
|
}
|
|
19703
19765
|
|
|
19766
|
+
function parseScalebarLabel(label) {
|
|
19767
|
+
var num = label ? parseScalebarNumber(label) : null;
|
|
19768
|
+
var units = label ? parseScalebarUnits(label) : 'mile';
|
|
19769
|
+
var km = NaN;
|
|
19770
|
+
if (units && num) {
|
|
19771
|
+
km = units == 'mile' ? num * 1.60934 : num;
|
|
19772
|
+
}
|
|
19773
|
+
return {
|
|
19774
|
+
number: num,
|
|
19775
|
+
units: units,
|
|
19776
|
+
km: km
|
|
19777
|
+
};
|
|
19778
|
+
}
|
|
19779
|
+
|
|
19704
19780
|
function parseScalebarUnits(str) {
|
|
19705
19781
|
var isMiles = /miles?$/.test(str.toLowerCase());
|
|
19706
19782
|
var isKm = /(k\.m\.|km|kilometers?|kilometres?)$/.test(str.toLowerCase());
|
|
@@ -25821,7 +25897,11 @@ ${svg}
|
|
|
25821
25897
|
describe: 'e.g. bottom-right (default is top-left)'
|
|
25822
25898
|
})
|
|
25823
25899
|
.option('label-position', {
|
|
25824
|
-
describe: 'top
|
|
25900
|
+
describe: 'top, bottom, top-center (style a), etc'
|
|
25901
|
+
})
|
|
25902
|
+
.option('dual-units', {
|
|
25903
|
+
// describe: 'display both metric and imperial units',
|
|
25904
|
+
type: 'flag'
|
|
25825
25905
|
})
|
|
25826
25906
|
.option('margin', {
|
|
25827
25907
|
describe: 'offset in pixels from edge of map',
|
|
@@ -45224,7 +45304,7 @@ ${svg}
|
|
|
45224
45304
|
});
|
|
45225
45305
|
}
|
|
45226
45306
|
|
|
45227
|
-
var version = "0.6.
|
|
45307
|
+
var version = "0.6.68";
|
|
45228
45308
|
|
|
45229
45309
|
// Parse command line args into commands and run them
|
|
45230
45310
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -7820,6 +7820,7 @@
|
|
|
7820
7820
|
function onMouseUp(e) {
|
|
7821
7821
|
var evt = procMouseEvent(e),
|
|
7822
7822
|
elapsed, dx, dy;
|
|
7823
|
+
_self.dispatchEvent('mouseup', evt);
|
|
7823
7824
|
if (_dragging) {
|
|
7824
7825
|
stopDragging(evt);
|
|
7825
7826
|
}
|
|
@@ -7847,6 +7848,7 @@
|
|
|
7847
7848
|
|
|
7848
7849
|
function onMouseMove(e) {
|
|
7849
7850
|
var evt = procMouseEvent(e);
|
|
7851
|
+
_self.dispatchEvent('mousemove', evt);
|
|
7850
7852
|
if (!_dragging && _downEvt && _downEvt.hover) {
|
|
7851
7853
|
_dragging = true;
|
|
7852
7854
|
_self.dispatchEvent('dragstart', evt);
|
|
@@ -7969,37 +7971,21 @@
|
|
|
7969
7971
|
});
|
|
7970
7972
|
});
|
|
7971
7973
|
|
|
7972
|
-
|
|
7974
|
+
gui.map.getMouse().on('mousemove', function(e) {
|
|
7973
7975
|
if (!_on || !activeHandle || !prevXY || !boxCoords || !_visible) return;
|
|
7974
7976
|
var xy = {x: e.pageX, y: e.pageY};
|
|
7975
|
-
var
|
|
7976
|
-
|
|
7977
|
-
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
if (activeHandle.col == 'left' || shifting) {
|
|
7981
|
-
boxCoords[0] += dx;
|
|
7982
|
-
if (centered) boxCoords[2] -= dx;
|
|
7983
|
-
}
|
|
7984
|
-
if (activeHandle.col == 'right' || shifting) {
|
|
7985
|
-
boxCoords[2] += dx;
|
|
7986
|
-
if (centered) boxCoords[0] -= dx;
|
|
7987
|
-
}
|
|
7988
|
-
if (activeHandle.row == 'top' || shifting) {
|
|
7989
|
-
boxCoords[3] += dy;
|
|
7990
|
-
if (centered) boxCoords[1] -= dy;
|
|
7991
|
-
}
|
|
7992
|
-
if (activeHandle.row == 'bottom' || shifting) {
|
|
7993
|
-
boxCoords[1] += dy;
|
|
7994
|
-
if (centered) boxCoords[3] -= dy;
|
|
7977
|
+
var scaling = gui.keyboard.shiftIsPressed() && activeHandle.type == 'corner';
|
|
7978
|
+
if (scaling) {
|
|
7979
|
+
rescaleBox(e.x, e.y);
|
|
7980
|
+
} else {
|
|
7981
|
+
resizeBox(xy.x - prevXY.x, xy.y - prevXY.y, activeHandle);
|
|
7995
7982
|
}
|
|
7996
|
-
|
|
7997
7983
|
prevXY = xy;
|
|
7998
7984
|
redraw();
|
|
7999
7985
|
box.dispatchEvent('handle_drag');
|
|
8000
7986
|
});
|
|
8001
7987
|
|
|
8002
|
-
|
|
7988
|
+
gui.map.getMouse().on('mouseup', function(e) {
|
|
8003
7989
|
if (activeHandle && _on) {
|
|
8004
7990
|
activeHandle.el.css('background', null);
|
|
8005
7991
|
activeHandle = null;
|
|
@@ -8012,6 +7998,43 @@
|
|
|
8012
7998
|
});
|
|
8013
7999
|
}
|
|
8014
8000
|
|
|
8001
|
+
function resizeBox(dx, dy, activeHandle) {
|
|
8002
|
+
var shifting = activeHandle.type == 'center';
|
|
8003
|
+
var centered = gui.keyboard.shiftIsPressed() && activeHandle.type == 'edge';
|
|
8004
|
+
var scale = gui.map.getExtent().getPixelSize();
|
|
8005
|
+
dx *= scale;
|
|
8006
|
+
dy *= -scale;
|
|
8007
|
+
|
|
8008
|
+
if (activeHandle.col == 'left' || shifting) {
|
|
8009
|
+
boxCoords[0] += dx;
|
|
8010
|
+
if (centered) boxCoords[2] -= dx;
|
|
8011
|
+
}
|
|
8012
|
+
if (activeHandle.col == 'right' || shifting) {
|
|
8013
|
+
boxCoords[2] += dx;
|
|
8014
|
+
if (centered) boxCoords[0] -= dx;
|
|
8015
|
+
}
|
|
8016
|
+
if (activeHandle.row == 'top' || shifting) {
|
|
8017
|
+
boxCoords[3] += dy;
|
|
8018
|
+
if (centered) boxCoords[1] -= dy;
|
|
8019
|
+
}
|
|
8020
|
+
if (activeHandle.row == 'bottom' || shifting) {
|
|
8021
|
+
boxCoords[1] += dy;
|
|
8022
|
+
if (centered) boxCoords[3] -= dy;
|
|
8023
|
+
}
|
|
8024
|
+
}
|
|
8025
|
+
|
|
8026
|
+
function rescaleBox(x, y) {
|
|
8027
|
+
var p = gui.map.getExtent().translatePixelCoords(x, y);
|
|
8028
|
+
var cx = (boxCoords[0] + boxCoords[2])/2;
|
|
8029
|
+
var cy = (boxCoords[1] + boxCoords[3])/2;
|
|
8030
|
+
var dist2 = geom.distance2D(cx, cy, p[0], p[1]);
|
|
8031
|
+
var dist = geom.distance2D(cx, cy, boxCoords[0], boxCoords[1]);
|
|
8032
|
+
var k = dist2 / dist;
|
|
8033
|
+
var dx = (boxCoords[2] - cx) * k;
|
|
8034
|
+
var dy = (boxCoords[3] - cy) * k;
|
|
8035
|
+
boxCoords = [cx - dx, cy - dy, cx + dx, cy + dy];
|
|
8036
|
+
}
|
|
8037
|
+
|
|
8015
8038
|
box.setDataCoords = function(bbox) {
|
|
8016
8039
|
boxCoords = bbox;
|
|
8017
8040
|
redraw();
|
|
@@ -8107,8 +8130,10 @@
|
|
|
8107
8130
|
// if (i == 4) continue; // skip middle handle
|
|
8108
8131
|
var c = Math.floor(i / 3);
|
|
8109
8132
|
var r = i % 3;
|
|
8133
|
+
var type = i == 4 && 'center' || c != 1 && r != 1 && 'corner' || 'edge';
|
|
8110
8134
|
handles.push({
|
|
8111
8135
|
el: El('div').addClass('handle').appendTo(el),
|
|
8136
|
+
type: type,
|
|
8112
8137
|
col: c == 0 && 'left' || c == 1 && 'center' || 'right',
|
|
8113
8138
|
row: r == 0 && 'top' || r == 1 && 'center' || 'bottom'
|
|
8114
8139
|
});
|
|
@@ -9347,50 +9372,22 @@
|
|
|
9347
9372
|
dotColor: violet,
|
|
9348
9373
|
dotSize: 3
|
|
9349
9374
|
}, polyline: {
|
|
9350
|
-
strokeColor: black, // violet,
|
|
9375
|
+
strokeColor: violet, // black, // violet,
|
|
9351
9376
|
strokeWidth: 3
|
|
9352
9377
|
}
|
|
9353
9378
|
};
|
|
9354
9379
|
|
|
9355
|
-
function getIntersectionStyle(lyr) {
|
|
9380
|
+
function getIntersectionStyle(lyr, opts) {
|
|
9356
9381
|
return getDefaultStyle(lyr, intersectionStyle);
|
|
9357
9382
|
}
|
|
9358
9383
|
|
|
9359
|
-
function getDefaultStyle(lyr, baseStyle) {
|
|
9360
|
-
var style = utils$1.extend({}, baseStyle);
|
|
9361
|
-
// reduce the dot size of large point layers
|
|
9362
|
-
if (lyr.geometry_type == 'point' && style.dotSize > 0) {
|
|
9363
|
-
style.dotSize *= getDotScale$1(lyr);
|
|
9364
|
-
}
|
|
9365
|
-
return style;
|
|
9366
|
-
}
|
|
9367
|
-
|
|
9368
|
-
function getDotScale$1(lyr) {
|
|
9369
|
-
var topTier = 50000;
|
|
9370
|
-
var n = countPoints(lyr.shapes, topTier + 2); // short-circuit point counting above top threshold
|
|
9371
|
-
var k = n < 200 && 4 || n < 2500 && 3 || n < 10000 && 2 || 1;
|
|
9372
|
-
// var k = n >= topTier && 0.25 || n > 10000 && 0.45 || n > 2500 && 0.65 || n > 200 && 0.85 || 1;
|
|
9373
|
-
return k;
|
|
9374
|
-
}
|
|
9375
|
-
|
|
9376
|
-
function countPoints(shapes, max) {
|
|
9377
|
-
var count = 0;
|
|
9378
|
-
var i, n, shp;
|
|
9379
|
-
max = max || Infinity;
|
|
9380
|
-
for (i=0, n=shapes.length; i<n && count<=max; i++) {
|
|
9381
|
-
shp = shapes[i];
|
|
9382
|
-
count += shp ? shp.length : 0;
|
|
9383
|
-
}
|
|
9384
|
-
return count;
|
|
9385
|
-
}
|
|
9386
|
-
|
|
9387
9384
|
// Style for unselected layers with visibility turned on
|
|
9388
9385
|
// (styled layers have)
|
|
9389
|
-
function
|
|
9386
|
+
function getReferenceLayerStyle(lyr, opts) {
|
|
9390
9387
|
var style;
|
|
9391
|
-
if (layerHasCanvasDisplayStyle(lyr)) {
|
|
9388
|
+
if (layerHasCanvasDisplayStyle(lyr) && !opts.outlineMode) {
|
|
9392
9389
|
style = getCanvasDisplayStyle(lyr);
|
|
9393
|
-
} else if (internal.layerHasLabels(lyr)) {
|
|
9390
|
+
} else if (internal.layerHasLabels(lyr) && !opts.outlineMode) {
|
|
9394
9391
|
style = {dotSize: 0}; // no reference dots if labels are visible
|
|
9395
9392
|
} else {
|
|
9396
9393
|
style = getDefaultStyle(lyr, referenceStyle);
|
|
@@ -9398,13 +9395,13 @@
|
|
|
9398
9395
|
return style;
|
|
9399
9396
|
}
|
|
9400
9397
|
|
|
9401
|
-
function
|
|
9398
|
+
function getActiveLayerStyle(lyr, opts) {
|
|
9402
9399
|
var style;
|
|
9403
|
-
if (layerHasCanvasDisplayStyle(lyr)) {
|
|
9400
|
+
if (layerHasCanvasDisplayStyle(lyr) && !opts.outlineMode) {
|
|
9404
9401
|
style = getCanvasDisplayStyle(lyr);
|
|
9405
|
-
} else if (internal.layerHasLabels(lyr)) {
|
|
9402
|
+
} else if (internal.layerHasLabels(lyr) && !opts.outlineMode) {
|
|
9406
9403
|
style = getDefaultStyle(lyr, activeStyleForLabels);
|
|
9407
|
-
} else if (darkMode) {
|
|
9404
|
+
} else if (opts.darkMode) {
|
|
9408
9405
|
style = getDefaultStyle(lyr, activeStyleDarkMode);
|
|
9409
9406
|
} else {
|
|
9410
9407
|
style = getDefaultStyle(lyr, activeStyle);
|
|
@@ -9412,21 +9409,6 @@
|
|
|
9412
9409
|
return style;
|
|
9413
9410
|
}
|
|
9414
9411
|
|
|
9415
|
-
// style for vertex edit mode
|
|
9416
|
-
function getVertexStyle(lyr, o) {
|
|
9417
|
-
return {
|
|
9418
|
-
ids: o.ids,
|
|
9419
|
-
overlay: true,
|
|
9420
|
-
strokeColor: black,
|
|
9421
|
-
strokeWidth: 1.5,
|
|
9422
|
-
vertices: true,
|
|
9423
|
-
vertex_overlay_color: violet,
|
|
9424
|
-
vertex_overlay: o.hit_coordinates || null,
|
|
9425
|
-
selected_points: o.selected_points || null,
|
|
9426
|
-
fillColor: null
|
|
9427
|
-
};
|
|
9428
|
-
}
|
|
9429
|
-
|
|
9430
9412
|
// Returns a display style for the overlay layer.
|
|
9431
9413
|
// The overlay layer renders several kinds of feature, each of which is displayed
|
|
9432
9414
|
// with a different style.
|
|
@@ -9435,47 +9417,103 @@
|
|
|
9435
9417
|
// * selected shapes
|
|
9436
9418
|
// * pinned shapes
|
|
9437
9419
|
//
|
|
9438
|
-
function getOverlayStyle(
|
|
9439
|
-
if (
|
|
9440
|
-
return getVertexStyle(
|
|
9420
|
+
function getOverlayStyle(baseLyr, o, opts) {
|
|
9421
|
+
if (opts.interactionMode == 'vertices') {
|
|
9422
|
+
return getVertexStyle(baseLyr, o);
|
|
9441
9423
|
}
|
|
9442
|
-
var geomType =
|
|
9424
|
+
var geomType = baseLyr.geometry_type;
|
|
9443
9425
|
var topId = o.id; // pinned id (if pinned) or hover id
|
|
9444
9426
|
var topIdx = -1;
|
|
9445
9427
|
var styler = function(style, i) {
|
|
9446
|
-
|
|
9428
|
+
var defaultStyle = i === topIdx ? topStyle : outlineStyle;
|
|
9429
|
+
if (baseStyle.styler) {
|
|
9430
|
+
Object.assign(style, baseStyle);
|
|
9431
|
+
baseStyle.styler(style, i);
|
|
9432
|
+
style.strokeColor = defaultStyle.strokeColor;
|
|
9433
|
+
style.fillColor = defaultStyle.fillColor;
|
|
9434
|
+
} else {
|
|
9435
|
+
Object.assign(style, defaultStyle);
|
|
9436
|
+
}
|
|
9447
9437
|
};
|
|
9448
|
-
var baseStyle = getDefaultStyle(
|
|
9438
|
+
// var baseStyle = getDefaultStyle(baseLyr, selectionStyles[geomType]);
|
|
9439
|
+
var baseStyle = getActiveLayerStyle(baseLyr, opts);
|
|
9440
|
+
var outlineStyle = getDefaultStyle(baseLyr, selectionStyles[geomType]);
|
|
9449
9441
|
var topStyle;
|
|
9450
9442
|
var ids = o.ids.filter(function(i) {
|
|
9451
9443
|
return i != o.id; // move selected id to the end
|
|
9452
9444
|
});
|
|
9453
9445
|
if (o.id > -1) { // pinned or hover style
|
|
9454
|
-
topStyle = getSelectedFeatureStyle(
|
|
9446
|
+
topStyle = getSelectedFeatureStyle(baseLyr, o, opts);
|
|
9455
9447
|
topIdx = ids.length;
|
|
9456
9448
|
ids.push(o.id); // put the pinned/hover feature last in the render order
|
|
9457
9449
|
}
|
|
9458
9450
|
var style = {
|
|
9459
|
-
|
|
9460
|
-
|
|
9451
|
+
baseStyle: baseStyle,
|
|
9452
|
+
styler,
|
|
9453
|
+
ids,
|
|
9461
9454
|
overlay: true
|
|
9462
9455
|
};
|
|
9463
9456
|
|
|
9464
|
-
if (layerHasCanvasDisplayStyle(
|
|
9457
|
+
if (layerHasCanvasDisplayStyle(baseLyr) && !opts.outlineMode) {
|
|
9465
9458
|
if (geomType == 'point') {
|
|
9466
|
-
style.styler = getOverlayPointStyler(getCanvasDisplayStyle(
|
|
9459
|
+
style.styler = getOverlayPointStyler(getCanvasDisplayStyle(baseLyr).styler, styler);
|
|
9467
9460
|
}
|
|
9468
9461
|
style.type = 'styled';
|
|
9469
9462
|
}
|
|
9470
9463
|
return ids.length > 0 ? style : null;
|
|
9471
9464
|
}
|
|
9472
9465
|
|
|
9473
|
-
|
|
9466
|
+
|
|
9467
|
+
function getDefaultStyle(lyr, baseStyle) {
|
|
9468
|
+
var style = Object.assign({}, baseStyle);
|
|
9469
|
+
// reduce the dot size of large point layers
|
|
9470
|
+
if (lyr.geometry_type == 'point' && style.dotSize > 0) {
|
|
9471
|
+
style.dotSize *= getDotScale$1(lyr);
|
|
9472
|
+
}
|
|
9473
|
+
return style;
|
|
9474
|
+
}
|
|
9475
|
+
|
|
9476
|
+
function getDotScale$1(lyr) {
|
|
9477
|
+
var topTier = 10000;
|
|
9478
|
+
var n = countPoints(lyr.shapes, topTier); // short-circuit point counting above top threshold
|
|
9479
|
+
var k = n < 200 && 4 || n < 2500 && 3 || n < topTier && 2 || 1;
|
|
9480
|
+
return k;
|
|
9481
|
+
}
|
|
9482
|
+
|
|
9483
|
+
function countPoints(shapes, max) {
|
|
9484
|
+
var count = 0;
|
|
9485
|
+
var i, n, shp;
|
|
9486
|
+
max = max || Infinity;
|
|
9487
|
+
for (i=0, n=shapes.length; i<n && count<max; i++) {
|
|
9488
|
+
shp = shapes[i];
|
|
9489
|
+
count += shp ? shp.length : 0;
|
|
9490
|
+
}
|
|
9491
|
+
return count;
|
|
9492
|
+
}
|
|
9493
|
+
|
|
9494
|
+
|
|
9495
|
+
// style for vertex edit mode
|
|
9496
|
+
function getVertexStyle(lyr, o) {
|
|
9497
|
+
return {
|
|
9498
|
+
ids: o.ids,
|
|
9499
|
+
overlay: true,
|
|
9500
|
+
strokeColor: black,
|
|
9501
|
+
strokeWidth: 1.5,
|
|
9502
|
+
vertices: true,
|
|
9503
|
+
vertex_overlay_color: violet,
|
|
9504
|
+
vertex_overlay: o.hit_coordinates || null,
|
|
9505
|
+
selected_points: o.selected_points || null,
|
|
9506
|
+
fillColor: null
|
|
9507
|
+
};
|
|
9508
|
+
}
|
|
9509
|
+
|
|
9510
|
+
|
|
9511
|
+
function getSelectedFeatureStyle(lyr, o, opts) {
|
|
9474
9512
|
var isPinned = o.pinned;
|
|
9475
9513
|
var inSelection = o.ids.indexOf(o.id) > -1;
|
|
9476
9514
|
var geomType = lyr.geometry_type;
|
|
9477
9515
|
var style;
|
|
9478
|
-
if (isPinned &&
|
|
9516
|
+
if (isPinned && opts.interactionMode == 'rectangles') {
|
|
9479
9517
|
// kludge for rectangle editing mode
|
|
9480
9518
|
style = selectionStyles[geomType];
|
|
9481
9519
|
} else if (isPinned) {
|
|
@@ -9903,19 +9941,13 @@
|
|
|
9903
9941
|
}
|
|
9904
9942
|
|
|
9905
9943
|
function calcBounds(cx, cy, scale) {
|
|
9906
|
-
var full
|
|
9907
|
-
if (_frame) {
|
|
9908
|
-
full = fillOutFrameBounds(_frame);
|
|
9909
|
-
} else {
|
|
9910
|
-
full = fillOut(_fullBounds);
|
|
9911
|
-
}
|
|
9944
|
+
var full = fillOut(_fullBounds);
|
|
9912
9945
|
if (_strictBounds) {
|
|
9913
9946
|
full = fitIn(full, _strictBounds);
|
|
9914
9947
|
}
|
|
9915
|
-
w = full.width() / scale;
|
|
9916
|
-
h = full.height() / scale;
|
|
9917
|
-
|
|
9918
|
-
return bounds;
|
|
9948
|
+
var w = full.width() / scale;
|
|
9949
|
+
var h = full.height() / scale;
|
|
9950
|
+
return new Bounds(cx - w/2, cy - h/2, cx + w/2, cy + h/2);
|
|
9919
9951
|
}
|
|
9920
9952
|
|
|
9921
9953
|
// Calculate viewport bounds from frame data
|
|
@@ -10235,7 +10267,7 @@
|
|
|
10235
10267
|
var iter = new internal.ShapeIter(arcs);
|
|
10236
10268
|
var t = getScaledTransform(_ext);
|
|
10237
10269
|
var bounds = _ext.getBounds();
|
|
10238
|
-
var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
|
|
10270
|
+
var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext, style);
|
|
10239
10271
|
var color = style.strokeColor || 'black';
|
|
10240
10272
|
|
|
10241
10273
|
var i, j, p;
|
|
@@ -10269,7 +10301,7 @@
|
|
|
10269
10301
|
_self.drawStyledPaths = function(shapes, arcs, style, filter) {
|
|
10270
10302
|
var styleIndex = {};
|
|
10271
10303
|
var batchSize = 1500;
|
|
10272
|
-
var startPath = getPathStart(_ext, getScaledLineScale(_ext));
|
|
10304
|
+
var startPath = getPathStart(_ext, getScaledLineScale(_ext, style));
|
|
10273
10305
|
var draw = getShapePencil(arcs, _ext);
|
|
10274
10306
|
var key, item, shp;
|
|
10275
10307
|
var styler = style.styler || null;
|
|
@@ -10445,7 +10477,7 @@
|
|
|
10445
10477
|
return (style.strokeWidth > 0 ? style.strokeColor + '~' + style.strokeWidth +
|
|
10446
10478
|
'~' + (style.lineDash ? style.lineDash + '~' : '') : '') +
|
|
10447
10479
|
(style.fillColor || '') +
|
|
10448
|
-
// styles with <1 opacity are no longer batch-rendered
|
|
10480
|
+
// styles with <1 opacity are no longer batch-rendered, not relevent to key
|
|
10449
10481
|
// (style.strokeOpacity >= 0 ? style.strokeOpacity + '~' : '') : '') +
|
|
10450
10482
|
// (style.fillOpacity ? '~' + style.fillOpacity : '') +
|
|
10451
10483
|
// (style.opacity < 1 ? '~' + style.opacity : '') +
|
|
@@ -10454,9 +10486,17 @@
|
|
|
10454
10486
|
return _self;
|
|
10455
10487
|
}
|
|
10456
10488
|
|
|
10457
|
-
function getScaledLineScale(ext) {
|
|
10489
|
+
function getScaledLineScale(ext, style) {
|
|
10458
10490
|
var previewScale = ext.getSymbolScale();
|
|
10459
|
-
|
|
10491
|
+
var k = 1;
|
|
10492
|
+
if (previewScale == 1 || style.type != 'styled' || style.baseStyle && style.baseStyle.type != 'styled') {
|
|
10493
|
+
return getLineScale(ext);
|
|
10494
|
+
}
|
|
10495
|
+
if (style.baseStyle?.type == 'styled') {
|
|
10496
|
+
// bump up overlay line width in preview mode
|
|
10497
|
+
k = previewScale < 2 && 2 || previewScale < 5 && 1.5 || previewScale < 10 && 1.25 || 1.1;
|
|
10498
|
+
}
|
|
10499
|
+
return previewScale * k;
|
|
10460
10500
|
}
|
|
10461
10501
|
|
|
10462
10502
|
// Vary line width according to zoom ratio.
|
|
@@ -10626,9 +10666,6 @@
|
|
|
10626
10666
|
return function(ctx, style) {
|
|
10627
10667
|
var strokeWidth;
|
|
10628
10668
|
ctx.beginPath();
|
|
10629
|
-
// if (style.opacity >= 0) {
|
|
10630
|
-
// ctx.globalAlpha = style.opacity;
|
|
10631
|
-
// }
|
|
10632
10669
|
if (style.strokeWidth > 0) {
|
|
10633
10670
|
strokeWidth = style.strokeWidth;
|
|
10634
10671
|
if (pixRatio > 1) {
|
|
@@ -11587,7 +11624,7 @@
|
|
|
11587
11624
|
if (lyr == _intersectionLyr) return; // no change
|
|
11588
11625
|
if (lyr) {
|
|
11589
11626
|
_intersectionLyr = getDisplayLayer(lyr, dataset, getDisplayOptions());
|
|
11590
|
-
_intersectionLyr.style = getIntersectionStyle(_intersectionLyr.layer);
|
|
11627
|
+
_intersectionLyr.style = getIntersectionStyle(_intersectionLyr.layer, getGlobalStyleOptions());
|
|
11591
11628
|
} else {
|
|
11592
11629
|
_intersectionLyr = null;
|
|
11593
11630
|
}
|
|
@@ -11623,6 +11660,7 @@
|
|
|
11623
11660
|
};
|
|
11624
11661
|
|
|
11625
11662
|
this.getExtent = function() {return _ext;};
|
|
11663
|
+
this.getMouse = function() {return _mouse;};
|
|
11626
11664
|
this.isActiveLayer = isActiveLayer;
|
|
11627
11665
|
this.isVisibleLayer = isVisibleLayer;
|
|
11628
11666
|
this.getActiveLayer = function() { return _activeLyr; };
|
|
@@ -11659,6 +11697,15 @@
|
|
|
11659
11697
|
updateFullBounds();
|
|
11660
11698
|
};
|
|
11661
11699
|
|
|
11700
|
+
function getGlobalStyleOptions() {
|
|
11701
|
+
var mode = gui.state.interaction_mode;
|
|
11702
|
+
return {
|
|
11703
|
+
darkMode: !!gui.state.dark_basemap,
|
|
11704
|
+
outlineMode: mode == 'vertices',
|
|
11705
|
+
interactionMode: mode
|
|
11706
|
+
};
|
|
11707
|
+
}
|
|
11708
|
+
|
|
11662
11709
|
// Refresh map display in response to data changes, layer selection, etc.
|
|
11663
11710
|
function onUpdate(e) {
|
|
11664
11711
|
var prevLyr = _activeLyr || null;
|
|
@@ -11691,7 +11738,6 @@
|
|
|
11691
11738
|
}
|
|
11692
11739
|
|
|
11693
11740
|
_activeLyr = getDisplayLayer(e.layer, e.dataset, getDisplayOptions());
|
|
11694
|
-
_activeLyr.style = getActiveStyle(_activeLyr.layer, gui.state.dark_basemap);
|
|
11695
11741
|
_activeLyr.active = true;
|
|
11696
11742
|
|
|
11697
11743
|
if (popupCanStayOpen(e.flags)) {
|
|
@@ -11749,7 +11795,7 @@
|
|
|
11749
11795
|
}
|
|
11750
11796
|
|
|
11751
11797
|
function updateOverlayLayer(e) {
|
|
11752
|
-
var style = getOverlayStyle(_activeLyr.layer, e);
|
|
11798
|
+
var style = getOverlayStyle(_activeLyr.layer, e, getGlobalStyleOptions());
|
|
11753
11799
|
if (style) {
|
|
11754
11800
|
_overlayLyr = utils$1.defaults({
|
|
11755
11801
|
layer: filterLayerByIds(_activeLyr.layer, style.ids),
|
|
@@ -11896,9 +11942,10 @@
|
|
|
11896
11942
|
function updateLayerStyles(layers) {
|
|
11897
11943
|
layers.forEach(function(mapLayer, i) {
|
|
11898
11944
|
if (mapLayer.active) {
|
|
11899
|
-
//
|
|
11945
|
+
// regenerating active style everytime, to support style change when
|
|
11946
|
+
// switching between outline and preview modes.
|
|
11947
|
+
mapLayer.style = getActiveLayerStyle(mapLayer.layer, getGlobalStyleOptions());
|
|
11900
11948
|
if (mapLayer.style.type != 'styled' && layers.length > 1 && mapLayer.style.strokeColors) {
|
|
11901
|
-
// if (false) { // always show ghosted arcs
|
|
11902
11949
|
// kludge to hide ghosted layers when reference layers are present
|
|
11903
11950
|
// TODO: consider never showing ghosted layers (which appear after
|
|
11904
11951
|
// commands like dissolve and filter).
|
|
@@ -11910,7 +11957,7 @@
|
|
|
11910
11957
|
if (mapLayer.layer == _activeLyr.layer) {
|
|
11911
11958
|
console.error("Error: shared map layer");
|
|
11912
11959
|
}
|
|
11913
|
-
mapLayer.style =
|
|
11960
|
+
mapLayer.style = getReferenceLayerStyle(mapLayer.layer, getGlobalStyleOptions());
|
|
11914
11961
|
}
|
|
11915
11962
|
});
|
|
11916
11963
|
}
|
package/www/mapshaper.js
CHANGED
|
@@ -14726,6 +14726,9 @@
|
|
|
14726
14726
|
bounds: function() {
|
|
14727
14727
|
return shapeBounds().toArray();
|
|
14728
14728
|
},
|
|
14729
|
+
bbox: function() {
|
|
14730
|
+
return shapeBounds().toArray();
|
|
14731
|
+
},
|
|
14729
14732
|
height: function() {
|
|
14730
14733
|
return shapeBounds().height();
|
|
14731
14734
|
},
|
|
@@ -17323,9 +17326,10 @@
|
|
|
17323
17326
|
}
|
|
17324
17327
|
|
|
17325
17328
|
function getGapRemovalMessage(removed, retained, areaLabel) {
|
|
17329
|
+
var tot = removed + retained;
|
|
17326
17330
|
if (removed > 0 === false) return '';
|
|
17327
|
-
return utils.format('Removed %,d
|
|
17328
|
-
removed,
|
|
17331
|
+
return utils.format('Removed %,d of %,d sliver%s using %s',
|
|
17332
|
+
removed, tot, utils.pluralSuffix(tot), areaLabel);
|
|
17329
17333
|
}
|
|
17330
17334
|
|
|
17331
17335
|
function dissolvePolygonGroups2(groups, lyr, dataset, opts) {
|
|
@@ -19274,12 +19278,12 @@
|
|
|
19274
19278
|
// Kludge for applying fill and other styles to a <text> element
|
|
19275
19279
|
// (for rendering labels in the GUI with the dot in Canvas, not SVG)
|
|
19276
19280
|
function renderStyledLabel(rec) {
|
|
19277
|
-
var o = renderLabel(rec);
|
|
19281
|
+
var o = renderLabel$1(rec);
|
|
19278
19282
|
applyStyleAttributes(o, 'label', rec);
|
|
19279
19283
|
return o;
|
|
19280
19284
|
}
|
|
19281
19285
|
|
|
19282
|
-
function renderLabel(rec) {
|
|
19286
|
+
function renderLabel$1(rec) {
|
|
19283
19287
|
var line = toLabelString(rec['label-text']);
|
|
19284
19288
|
var morelines, obj;
|
|
19285
19289
|
// Accepting \n (two chars) as an alternative to the newline character
|
|
@@ -19324,7 +19328,7 @@
|
|
|
19324
19328
|
var SvgLabels = /*#__PURE__*/Object.freeze({
|
|
19325
19329
|
__proto__: null,
|
|
19326
19330
|
renderStyledLabel: renderStyledLabel,
|
|
19327
|
-
renderLabel: renderLabel
|
|
19331
|
+
renderLabel: renderLabel$1
|
|
19328
19332
|
});
|
|
19329
19333
|
|
|
19330
19334
|
// convert data records (properties like svg-symbol, label-text, fill, r) to svg symbols
|
|
@@ -19536,13 +19540,64 @@
|
|
|
19536
19540
|
};
|
|
19537
19541
|
}
|
|
19538
19542
|
|
|
19539
|
-
|
|
19540
|
-
|
|
19541
|
-
|
|
19542
|
-
|
|
19543
|
-
|
|
19544
|
-
|
|
19543
|
+
function renderScalebar(d, frame) {
|
|
19544
|
+
if (!frame.crs) {
|
|
19545
|
+
message('Unable to render scalebar: unknown CRS.');
|
|
19546
|
+
return [];
|
|
19547
|
+
}
|
|
19548
|
+
if (frame.width > 0 === false) {
|
|
19549
|
+
return [];
|
|
19550
|
+
}
|
|
19551
|
+
|
|
19552
|
+
var opts = getScalebarOpts(d);
|
|
19553
|
+
var metersPerPx = getMapFrameMetersPerPixel(frame);
|
|
19554
|
+
var frameWidthPx = frame.width;
|
|
19555
|
+
var labels = d.label ? d.label.split(',') : null;
|
|
19556
|
+
var label1 = labels && labels[0] || null;
|
|
19557
|
+
var props1 = parseScalebarLabel(label1 || getAutoScalebarLabel(frameWidthPx, metersPerPx, 'mile'));
|
|
19558
|
+
var label2 = opts.style == 'b' && labels && labels[1] || null;
|
|
19559
|
+
var props2, length2;
|
|
19560
|
+
|
|
19561
|
+
if (props1.km > 0 === false) {
|
|
19562
|
+
message('Unusable scalebar label:', label1);
|
|
19563
|
+
return [];
|
|
19564
|
+
}
|
|
19565
|
+
|
|
19566
|
+
var length1 = Math.round(props1.km / metersPerPx * 1000);
|
|
19567
|
+
if (length1 > 0 === false) {
|
|
19568
|
+
stop("Null scalebar length");
|
|
19569
|
+
}
|
|
19570
|
+
|
|
19571
|
+
if (label2) {
|
|
19572
|
+
props2 = parseScalebarLabel(label2);
|
|
19573
|
+
length2 = Math.round(props2.km / metersPerPx * 1000);
|
|
19574
|
+
if (length2 > length1) {
|
|
19575
|
+
stop("First part of a dual-unit scalebar must be longer than the second part.");
|
|
19576
|
+
}
|
|
19577
|
+
}
|
|
19578
|
+
|
|
19579
|
+
var barPos = getScalebarPosition(opts);
|
|
19580
|
+
var labelPos = getLabelPosition(opts);
|
|
19581
|
+
var dx = barPos.xpos == 'right' ? frameWidthPx - length1 - opts.margin : opts.margin;
|
|
19582
|
+
var dy = barPos.ypos == 'bottom' ? frame.height - opts.margin : opts.margin;
|
|
19583
|
+
|
|
19584
|
+
// vshift to adjust for height above or below the baseline
|
|
19585
|
+
var labelHeight = Math.round(opts.label_offset + opts.tic_length + opts.font_size * 0.8 + opts.bar_width / 2);
|
|
19586
|
+
var bareHeight = Math.round(opts.bar_width / 2);
|
|
19587
|
+
var topHeight = labelPos.ypos == 'top' || label2 ? labelHeight : bareHeight;
|
|
19588
|
+
var bottomHeight = labelPos.ypos == 'bottom' || label2 ? labelHeight : bareHeight;
|
|
19589
|
+
if (barPos.ypos == 'top') {
|
|
19590
|
+
dy += topHeight;
|
|
19591
|
+
} else {
|
|
19592
|
+
dy -= bottomHeight;
|
|
19593
|
+
}
|
|
19594
|
+
|
|
19595
|
+
var g = renderAsSvg(length1, label1, length2, label2, opts);
|
|
19596
|
+
g.properties = {
|
|
19597
|
+
transform: 'translate(' + dx + ' ' + dy + ')'
|
|
19545
19598
|
};
|
|
19599
|
+
|
|
19600
|
+
return [g];
|
|
19546
19601
|
}
|
|
19547
19602
|
|
|
19548
19603
|
var styleOpts = {
|
|
@@ -19569,105 +19624,112 @@
|
|
|
19569
19624
|
return Object.assign({}, defaultOpts, styleOpts[style], d, {style: style});
|
|
19570
19625
|
}
|
|
19571
19626
|
|
|
19572
|
-
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
|
|
19627
|
+
function renderAsSvg(length, text, length2, text2, opts) {
|
|
19628
|
+
var labelPart = renderLabel(text, length, opts);
|
|
19629
|
+
var zeroLabelPart = renderLabel('0', length, Object.assign({flipx: true}, opts));
|
|
19630
|
+
var barPart = renderBar(length, length2, opts);
|
|
19631
|
+
var parts = opts.style == 'b' ? [zeroLabelPart, labelPart, barPart] : [labelPart, barPart];
|
|
19632
|
+
if (text2) {
|
|
19633
|
+
parts.push(renderLabel(text2, length2, Object.assign({flipy: true}, opts)));
|
|
19634
|
+
parts.push(renderLabel('0', length2, Object.assign({flipx: true, flipy: true}, opts)));
|
|
19635
|
+
}
|
|
19636
|
+
return {
|
|
19637
|
+
tag: 'g',
|
|
19638
|
+
children: parts
|
|
19639
|
+
};
|
|
19576
19640
|
}
|
|
19577
19641
|
|
|
19578
|
-
|
|
19579
|
-
|
|
19580
|
-
var
|
|
19581
|
-
|
|
19582
|
-
|
|
19583
|
-
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
19642
|
+
// TODO: generalize to other kinds of furniture as they are developed
|
|
19643
|
+
function getScalebarPosition(opts) {
|
|
19644
|
+
var pos = opts.position || 'top-left';
|
|
19645
|
+
return {
|
|
19646
|
+
ypos: pos.includes('top') ? 'top' : 'bottom',
|
|
19647
|
+
xpos: pos.includes('left') ? 'left' : 'right'
|
|
19648
|
+
};
|
|
19649
|
+
}
|
|
19650
|
+
|
|
19651
|
+
function renderLabel(text, length, opts) {
|
|
19652
|
+
var labelPos = getLabelPosition(opts);
|
|
19653
|
+
var anchorX = length * labelPos.kx + labelPos.dx;
|
|
19654
|
+
var bottomLabelY = opts.bar_width + opts.tic_length + opts.label_offset;
|
|
19655
|
+
var topLabelY = -opts.label_offset - opts.tic_length;
|
|
19656
|
+
var anchorY = labelPos.ypos == 'top' ? topLabelY : bottomLabelY;
|
|
19587
19657
|
var labelOpts = {
|
|
19588
19658
|
'label-text': text,
|
|
19589
19659
|
'font-size': opts.font_size,
|
|
19590
|
-
'text-anchor':
|
|
19591
|
-
'dominant-baseline':
|
|
19660
|
+
'text-anchor': labelPos.anchor,
|
|
19661
|
+
'dominant-baseline': labelPos.ypos == 'top' ? 'auto' : 'hanging'
|
|
19592
19662
|
//// 'dominant-baseline': labelPos == 'top' ? 'text-after-edge' : 'text-before-edge'
|
|
19593
19663
|
// 'text-after-edge' is buggy in Safari and unsupported by Illustrator,
|
|
19594
19664
|
// so I'm using 'hanging' and 'auto', which seem to be well supported.
|
|
19595
19665
|
// downside: requires a kludgy multiplier to calculate scalebar height (see above)
|
|
19596
19666
|
};
|
|
19597
|
-
|
|
19598
|
-
|
|
19599
|
-
var zeroLabel = symbolRenderers.label(zeroOpts, -xOff, anchorY);
|
|
19667
|
+
return symbolRenderers.label(labelOpts, anchorX, anchorY);
|
|
19668
|
+
}
|
|
19600
19669
|
|
|
19601
|
-
|
|
19602
|
-
var
|
|
19603
|
-
var
|
|
19604
|
-
var
|
|
19605
|
-
|
|
19606
|
-
|
|
19607
|
-
|
|
19608
|
-
if (opts.tic_length > 0) {
|
|
19609
|
-
coords = [[0, y2], [0, y], [length, y], [length, y2]];
|
|
19670
|
+
function getLabelPosition(opts) {
|
|
19671
|
+
var pos = opts.label_position;
|
|
19672
|
+
var ypos = pos.includes('bottom') && 'bottom' || 'top';
|
|
19673
|
+
var dx = 0;
|
|
19674
|
+
var xpos;
|
|
19675
|
+
if (opts.style == 'a') {
|
|
19676
|
+
xpos = pos.includes('center') && 'center' || pos.includes('right') && 'right' || 'left';
|
|
19610
19677
|
} else {
|
|
19611
|
-
|
|
19678
|
+
xpos = 'right'; // style b
|
|
19679
|
+
}
|
|
19680
|
+
if (opts.flipx) {
|
|
19681
|
+
xpos = xpos == 'left' && 'right' || xpos == 'right' && 'left' || xpos;
|
|
19682
|
+
}
|
|
19683
|
+
if (opts.flipy) {
|
|
19684
|
+
ypos = ypos == 'top' && 'bottom' || ypos == 'bottom' && 'top' || ypos;
|
|
19685
|
+
}
|
|
19686
|
+
if (opts.style == 'b') {
|
|
19687
|
+
dx = xpos == 'left' && -opts.font_size / 4 || xpos == 'right' && opts.font_size / 4 || 0;
|
|
19612
19688
|
}
|
|
19613
|
-
var barPart = importLineString(coords);
|
|
19614
|
-
Object.assign(barPart.properties, {
|
|
19615
|
-
stroke: 'black',
|
|
19616
|
-
fill: 'none',
|
|
19617
|
-
'stroke-width': opts.bar_width,
|
|
19618
|
-
'stroke-linecap': 'butt',
|
|
19619
|
-
'stroke-linejoin': 'miter'
|
|
19620
|
-
});
|
|
19621
|
-
var parts = opts.style == 'b' ? [zeroLabel, labelPart, barPart] : [labelPart, barPart];
|
|
19622
19689
|
return {
|
|
19623
|
-
|
|
19624
|
-
|
|
19690
|
+
xpos,
|
|
19691
|
+
ypos,
|
|
19692
|
+
dx,
|
|
19693
|
+
kx: xpos == 'right' && 1 || xpos == 'center' && 0.5 || 0,
|
|
19694
|
+
anchor: xpos == 'center' && 'middle' || xpos == 'left' && 'start' || 'end'
|
|
19625
19695
|
};
|
|
19626
19696
|
}
|
|
19627
19697
|
|
|
19628
|
-
|
|
19629
|
-
|
|
19630
|
-
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
|
|
19635
|
-
|
|
19636
|
-
|
|
19637
|
-
var opts = getScalebarOpts(d);
|
|
19638
|
-
var metersPerPx = getMapFrameMetersPerPixel(frame);
|
|
19639
|
-
var frameWidthPx = frame.width;
|
|
19640
|
-
var unit = d.label ? parseScalebarUnits(d.label) : 'mile';
|
|
19641
|
-
var number = d.label ? parseScalebarNumber(d.label) : null;
|
|
19642
|
-
var label = number && unit ? d.label : getAutoScalebarLabel(frameWidthPx, metersPerPx, unit);
|
|
19643
|
-
|
|
19644
|
-
var scalebarKm = parseScalebarLabelToKm(label);
|
|
19645
|
-
if (scalebarKm > 0 === false) {
|
|
19646
|
-
message('Unusable scalebar label:', label);
|
|
19647
|
-
return [];
|
|
19698
|
+
// length1: length of main bar
|
|
19699
|
+
// length2: length of optional second distance (assumes that length2 <= length1)
|
|
19700
|
+
function getStyleBCoords(length1, length2, opts) {
|
|
19701
|
+
var coords = [];
|
|
19702
|
+
var labelPos = getLabelPosition(opts);
|
|
19703
|
+
var y = opts.tic_length + opts.bar_width / 2;
|
|
19704
|
+
if (labelPos.ypos == "top") {
|
|
19705
|
+
y = -y;
|
|
19648
19706
|
}
|
|
19649
|
-
|
|
19650
|
-
|
|
19651
|
-
|
|
19652
|
-
|
|
19707
|
+
coords.push([[0, y], [0, 0], [length1, 0], [length1, y]]);
|
|
19708
|
+
if (length2 > 0) {
|
|
19709
|
+
coords.push([[0, 0], [0, -y]]);
|
|
19710
|
+
coords.push([[length2, 0], [length2, -y]]);
|
|
19653
19711
|
}
|
|
19712
|
+
return coords;
|
|
19713
|
+
}
|
|
19654
19714
|
|
|
19655
|
-
|
|
19656
|
-
|
|
19657
|
-
|
|
19658
|
-
var
|
|
19659
|
-
if (opts.
|
|
19660
|
-
|
|
19715
|
+
// length: length of scale bar in px
|
|
19716
|
+
// length2: length of optional dual-units portion of the scalebar
|
|
19717
|
+
function renderBar(length, length2, opts) {
|
|
19718
|
+
var coords;
|
|
19719
|
+
if (opts.style == 'b') {
|
|
19720
|
+
coords = getStyleBCoords(length, length2, opts);
|
|
19661
19721
|
} else {
|
|
19662
|
-
|
|
19722
|
+
coords = [[[0, 0], [length, 0]]];
|
|
19663
19723
|
}
|
|
19664
|
-
|
|
19665
|
-
|
|
19666
|
-
|
|
19667
|
-
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
|
|
19724
|
+
var bar = importMultiLineString(coords);
|
|
19725
|
+
Object.assign(bar.properties, {
|
|
19726
|
+
stroke: 'black',
|
|
19727
|
+
fill: 'none',
|
|
19728
|
+
'stroke-width': opts.bar_width,
|
|
19729
|
+
'stroke-linecap': 'butt',
|
|
19730
|
+
'stroke-linejoin': 'miter'
|
|
19731
|
+
});
|
|
19732
|
+
return bar;
|
|
19671
19733
|
}
|
|
19672
19734
|
|
|
19673
19735
|
// unit: 'km' || 'mile'
|
|
@@ -19701,6 +19763,20 @@
|
|
|
19701
19763
|
return units == 'mile' ? value * 1.60934 : value;
|
|
19702
19764
|
}
|
|
19703
19765
|
|
|
19766
|
+
function parseScalebarLabel(label) {
|
|
19767
|
+
var num = label ? parseScalebarNumber(label) : null;
|
|
19768
|
+
var units = label ? parseScalebarUnits(label) : 'mile';
|
|
19769
|
+
var km = NaN;
|
|
19770
|
+
if (units && num) {
|
|
19771
|
+
km = units == 'mile' ? num * 1.60934 : num;
|
|
19772
|
+
}
|
|
19773
|
+
return {
|
|
19774
|
+
number: num,
|
|
19775
|
+
units: units,
|
|
19776
|
+
km: km
|
|
19777
|
+
};
|
|
19778
|
+
}
|
|
19779
|
+
|
|
19704
19780
|
function parseScalebarUnits(str) {
|
|
19705
19781
|
var isMiles = /miles?$/.test(str.toLowerCase());
|
|
19706
19782
|
var isKm = /(k\.m\.|km|kilometers?|kilometres?)$/.test(str.toLowerCase());
|
|
@@ -25821,7 +25897,11 @@ ${svg}
|
|
|
25821
25897
|
describe: 'e.g. bottom-right (default is top-left)'
|
|
25822
25898
|
})
|
|
25823
25899
|
.option('label-position', {
|
|
25824
|
-
describe: 'top
|
|
25900
|
+
describe: 'top, bottom, top-center (style a), etc'
|
|
25901
|
+
})
|
|
25902
|
+
.option('dual-units', {
|
|
25903
|
+
// describe: 'display both metric and imperial units',
|
|
25904
|
+
type: 'flag'
|
|
25825
25905
|
})
|
|
25826
25906
|
.option('margin', {
|
|
25827
25907
|
describe: 'offset in pixels from edge of map',
|
|
@@ -45224,7 +45304,7 @@ ${svg}
|
|
|
45224
45304
|
});
|
|
45225
45305
|
}
|
|
45226
45306
|
|
|
45227
|
-
var version = "0.6.
|
|
45307
|
+
var version = "0.6.68";
|
|
45228
45308
|
|
|
45229
45309
|
// Parse command line args into commands and run them
|
|
45230
45310
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|