mapshaper 0.6.119 → 0.6.120
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/README.md +1 -1
- package/mapshaper.js +1 -1
- package/package.json +1 -1
- package/www/index.html +1 -1
- package/www/mapshaper-gui.js +202 -22
- package/www/mapshaper.js +1 -1
- package/www/page.css +8 -1
- package/www/{donate.html → sponsor.html} +8 -8
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ Run `npm test` to run mapshaper's tests.
|
|
|
98
98
|
|
|
99
99
|
Mapshaper is free and open source. If it's useful to you or your organization, please consider supporting its continued development:
|
|
100
100
|
|
|
101
|
-
* [Ko-fi](https://ko-fi.com/mapshaper) — one-time or recurring
|
|
101
|
+
* [Ko-fi](https://ko-fi.com/mapshaper) — one-time or recurring contributions, no account required.
|
|
102
102
|
* [GitHub Sponsors](https://github.com/sponsors/mbloch) — recurring sponsorship.
|
|
103
103
|
|
|
104
104
|
You can also help by [reporting bugs](https://github.com/mbloch/mapshaper/issues) or [telling me what you'd like to see improved](https://tally.so/r/44Njok).
|
package/mapshaper.js
CHANGED
|
@@ -51131,7 +51131,7 @@ ${svg}
|
|
|
51131
51131
|
});
|
|
51132
51132
|
}
|
|
51133
51133
|
|
|
51134
|
-
var version = "0.6.
|
|
51134
|
+
var version = "0.6.120";
|
|
51135
51135
|
|
|
51136
51136
|
// Parse command line args into commands and run them
|
|
51137
51137
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
<span class="console-btn header-btn btn">Console</span><span class="display-btn header-btn btn">Display</span><span class="separator"></span><span class="separator"></span></span><span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
|
|
64
64
|
</div>
|
|
65
65
|
<div id="splash-buttons" class="page-header-buttons">
|
|
66
|
-
<a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a><span class="separator"></span><a href="
|
|
66
|
+
<a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a><span class="separator"></span><a href="sponsor.html"><span id="sponsor-btn" class="header-btn btn"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg> Sponsor</span></a>
|
|
67
67
|
</div>
|
|
68
68
|
</div>
|
|
69
69
|
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -3079,13 +3079,12 @@
|
|
|
3079
3079
|
throw Error('Internal error');
|
|
3080
3080
|
}
|
|
3081
3081
|
}
|
|
3082
|
+
// switch to filtered version of arcs at small scales
|
|
3083
|
+
var useFiltering = filteredArcs && 1/ext.getTransform().mx > filteredSegLen * 1.5;
|
|
3082
3084
|
if (filteredArcs) {
|
|
3083
3085
|
// match simplification of unfiltered arcs
|
|
3084
3086
|
filteredArcs.setRetainedInterval(unfilteredArcs.getRetainedInterval());
|
|
3085
3087
|
}
|
|
3086
|
-
// switch to filtered version of arcs at small scales
|
|
3087
|
-
var unitsPerPixel = 1/ext.getTransform().mx,
|
|
3088
|
-
useFiltering = filteredArcs && unitsPerPixel > filteredSegLen * 1.5;
|
|
3089
3088
|
return useFiltering ? filteredArcs : unfilteredArcs;
|
|
3090
3089
|
};
|
|
3091
3090
|
}
|
|
@@ -8931,6 +8930,9 @@
|
|
|
8931
8930
|
var pct = ease ? ease(e.pct) : e.pct,
|
|
8932
8931
|
val = end * pct + start * (1 - pct);
|
|
8933
8932
|
self.dispatchEvent('change', {value: val});
|
|
8933
|
+
if (e.done) {
|
|
8934
|
+
self.dispatchEvent('done');
|
|
8935
|
+
}
|
|
8934
8936
|
}
|
|
8935
8937
|
}
|
|
8936
8938
|
|
|
@@ -9095,6 +9097,7 @@
|
|
|
9095
9097
|
}
|
|
9096
9098
|
if (evt.done) {
|
|
9097
9099
|
active = false;
|
|
9100
|
+
self.dispatchEvent('mousewheelend');
|
|
9098
9101
|
} else {
|
|
9099
9102
|
if (fadeFactor > 0) {
|
|
9100
9103
|
// Decelerate towards the end of the sustain interval (for smoother zooming)
|
|
@@ -9688,12 +9691,26 @@
|
|
|
9688
9691
|
|
|
9689
9692
|
gui.on('map_reset', function() {
|
|
9690
9693
|
ext.reset(true);
|
|
9694
|
+
// ext.reset() synchronously triggers a 'nav' draw; signal end-of-
|
|
9695
|
+
// interaction so the LayerRenderer settles on a sharp frame
|
|
9696
|
+
// immediately instead of waiting on the fallback timer.
|
|
9697
|
+
gui.dispatchEvent('map_interaction_end');
|
|
9691
9698
|
});
|
|
9692
9699
|
|
|
9693
9700
|
zoomTween.on('change', function(e) {
|
|
9694
9701
|
ext.zoomToExtent(e.value, _fx, _fy);
|
|
9695
9702
|
});
|
|
9696
9703
|
|
|
9704
|
+
// Signal end-of-interaction so downstream modules (e.g. LayerRenderer) can
|
|
9705
|
+
// trigger a settle/redraw immediately, instead of waiting on a debounce.
|
|
9706
|
+
zoomTween.on('done', function() {
|
|
9707
|
+
gui.dispatchEvent('map_interaction_end');
|
|
9708
|
+
});
|
|
9709
|
+
|
|
9710
|
+
wheel.on('mousewheelend', function() {
|
|
9711
|
+
gui.dispatchEvent('map_interaction_end');
|
|
9712
|
+
});
|
|
9713
|
+
|
|
9697
9714
|
mouse.on('click', function(e) {
|
|
9698
9715
|
gui.dispatchEvent('map_click', e);
|
|
9699
9716
|
});
|
|
@@ -9744,6 +9761,7 @@
|
|
|
9744
9761
|
zoomBox.turnOff();
|
|
9745
9762
|
} else {
|
|
9746
9763
|
El('body').removeClass('panning').removeClass('pan');
|
|
9764
|
+
gui.dispatchEvent('map_interaction_end');
|
|
9747
9765
|
}
|
|
9748
9766
|
});
|
|
9749
9767
|
|
|
@@ -12279,7 +12297,6 @@
|
|
|
12279
12297
|
}
|
|
12280
12298
|
|
|
12281
12299
|
function drawStyledLayerToCanvas(lyr, canv, ext) {
|
|
12282
|
-
// TODO: add filter for out-of-view shapes
|
|
12283
12300
|
var style = lyr.gui.style;
|
|
12284
12301
|
var layer = lyr.gui.displayLayer;
|
|
12285
12302
|
var arcs, filter;
|
|
@@ -12291,7 +12308,7 @@
|
|
|
12291
12308
|
}
|
|
12292
12309
|
} else {
|
|
12293
12310
|
arcs = getArcsForRendering(lyr, ext);
|
|
12294
|
-
filter = getShapeFilter(arcs, ext);
|
|
12311
|
+
filter = getShapeFilter(arcs, layer.shapes, ext);
|
|
12295
12312
|
canv.drawStyledPaths(layer.shapes, arcs, style, filter);
|
|
12296
12313
|
if (style.vertices) {
|
|
12297
12314
|
canv.drawVertices(layer.shapes, arcs, style, filter);
|
|
@@ -12300,11 +12317,12 @@
|
|
|
12300
12317
|
canv.clearStyles();
|
|
12301
12318
|
}
|
|
12302
12319
|
|
|
12303
|
-
|
|
12304
12320
|
// Return a function for testing if an arc should be drawn in the current view
|
|
12305
12321
|
function getArcFilter(arcs, ext, usedFlag, arcCounts) {
|
|
12306
|
-
|
|
12307
|
-
|
|
12322
|
+
// Arcs whose bbox is smaller than this pixel threshold collapse to a dot
|
|
12323
|
+
// under roundToPix anyway; skipping them saves per-arc iteration.
|
|
12324
|
+
var MIN_PATH_LEN = 0.35;
|
|
12325
|
+
var minPathLen = ext.getPixelSize() * MIN_PATH_LEN,
|
|
12308
12326
|
geoBounds = ext.getBounds(),
|
|
12309
12327
|
geoBBox = geoBounds.toArray(),
|
|
12310
12328
|
allIn = geoBounds.contains(arcs.getBounds()),
|
|
@@ -12324,15 +12342,20 @@
|
|
|
12324
12342
|
};
|
|
12325
12343
|
}
|
|
12326
12344
|
|
|
12327
|
-
// Return a function for testing if a shape should be drawn in the current
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12345
|
+
// Return a function for testing if a shape should be drawn in the current
|
|
12346
|
+
// view. The filter takes a shape index and tests the shape's bbox against
|
|
12347
|
+
// the viewport. At nearly full extent the test is a no-op, so we return
|
|
12348
|
+
// null to let the caller skip it entirely.
|
|
12349
|
+
function getShapeFilter(arcs, shapes, ext) {
|
|
12350
|
+
if (ext.scale() < 1.1) return null;
|
|
12351
|
+
var view = ext.getBounds();
|
|
12352
|
+
var b = new Bounds();
|
|
12353
|
+
return function(i) {
|
|
12354
|
+
var shp = shapes[i];
|
|
12355
|
+
if (!shp) return false;
|
|
12356
|
+
b.empty();
|
|
12357
|
+
arcs.getMultiShapeBounds(shp, b);
|
|
12358
|
+
return view.intersects(b);
|
|
12336
12359
|
};
|
|
12337
12360
|
}
|
|
12338
12361
|
|
|
@@ -12405,7 +12428,7 @@
|
|
|
12405
12428
|
_ctx.fillStyle = color;
|
|
12406
12429
|
for (i=0; i<shapes.length; i++) {
|
|
12407
12430
|
var shp = shapes[i];
|
|
12408
|
-
if (!shp || filter && !filter(
|
|
12431
|
+
if (!shp || filter && !filter(i)) continue;
|
|
12409
12432
|
for (j=0; j<shp.length; j++) {
|
|
12410
12433
|
iter.init(shp[j]);
|
|
12411
12434
|
while (iter.hasNext()) {
|
|
@@ -12431,14 +12454,14 @@
|
|
|
12431
12454
|
// Optimized to draw paths in same-style batches (faster Canvas drawing)
|
|
12432
12455
|
_self.drawStyledPaths = function(shapes, arcs, style, filter) {
|
|
12433
12456
|
var styleIndex = {};
|
|
12434
|
-
var batchSize =
|
|
12457
|
+
var batchSize = 100;
|
|
12435
12458
|
var startPath = getPathStart(_ext, getScaledLineScale(_ext, style));
|
|
12436
12459
|
var draw = getShapePencil(arcs, _ext);
|
|
12437
12460
|
var key, item, shp;
|
|
12438
12461
|
var styler = style.styler || null;
|
|
12439
12462
|
for (var i=0; i<shapes.length; i++) {
|
|
12440
12463
|
shp = shapes[i];
|
|
12441
|
-
if (!shp || filter && !filter(
|
|
12464
|
+
if (!shp || filter && !filter(i)) continue;
|
|
12442
12465
|
if (styler) {
|
|
12443
12466
|
styler(style, i);
|
|
12444
12467
|
}
|
|
@@ -12606,7 +12629,8 @@
|
|
|
12606
12629
|
var startPath = getPathStart(_ext, getLineScale(_ext)),
|
|
12607
12630
|
t = getScaledTransform(_ext),
|
|
12608
12631
|
ctx = _ctx,
|
|
12609
|
-
|
|
12632
|
+
// Larger batches reduce the number of stroke() flushes.
|
|
12633
|
+
batch = 100,
|
|
12610
12634
|
count = 0,
|
|
12611
12635
|
n = arcs.size(),
|
|
12612
12636
|
i, iter;
|
|
@@ -12963,12 +12987,68 @@
|
|
|
12963
12987
|
_furniture = new SvgDisplayLayer(gui, ext, null).appendTo(el),
|
|
12964
12988
|
_ext = ext;
|
|
12965
12989
|
|
|
12990
|
+
// Fast-nav config: when the most recent render cycle exceeded SLOW_FRAME_MS,
|
|
12991
|
+
// subsequent 'nav' actions transform the previously rendered bitmap via CSS
|
|
12992
|
+
// instead of re-drawing vector content. This trades visible scaling/edge
|
|
12993
|
+
// artifacts for smoother panning and zooming on large datasets.
|
|
12994
|
+
//
|
|
12995
|
+
// Canvas 2D paint ops are normally rasterized asynchronously, so JS usually
|
|
12996
|
+
// returns long before the pixels are committed to the compositor. We force
|
|
12997
|
+
// a synchronous flush at the end of a full render (see flushCanvas) so that
|
|
12998
|
+
// (a) the elapsed time reflects the *true* frame cost (JS + rasterization)
|
|
12999
|
+
// rather than just the JS portion, and
|
|
13000
|
+
// (b) subsequent fast-nav CSS transforms composite cleanly rather than on
|
|
13001
|
+
// top of a still-committing bitmap.
|
|
13002
|
+
// We use only the most recent sample because previous renders may have
|
|
13003
|
+
// drawn a different scene (e.g. a simpler layer that is no longer active).
|
|
13004
|
+
var SLOW_FRAME_MS = 100;
|
|
13005
|
+
// Fallback delay before triggering a redraw if no explicit end-of-interaction
|
|
13006
|
+
// event arrives. The primary trigger is gui 'map_interaction_end' (mouse
|
|
13007
|
+
// release, wheel timeout, zoom tween done); this timer only fires if that
|
|
13008
|
+
// signal is somehow missed, so it's set generously.
|
|
13009
|
+
var FAST_SETTLE_FALLBACK_MS = 2000;
|
|
13010
|
+
var _lastFrameMs = 0; // duration of the most recent full render cycle
|
|
13011
|
+
var _snapshot = null; // {bounds, width, height, pixRatio}
|
|
13012
|
+
var _fastActive = false;
|
|
13013
|
+
var _settleTimer = null;
|
|
13014
|
+
var _redrawPending = false;
|
|
13015
|
+
var _settleRequested = false;
|
|
13016
|
+
|
|
13017
|
+
// 'map_interaction_end' may arrive before the in-flight 'nav' draw runs,
|
|
13018
|
+
// because drawLayers() schedules its work via requestAnimationFrame.
|
|
13019
|
+
// We latch the intent so that whichever order things happen in, the
|
|
13020
|
+
// settle fires immediately rather than waiting on the fallback timer.
|
|
13021
|
+
gui.on('map_interaction_end', function() {
|
|
13022
|
+
if (_redrawPending) {
|
|
13023
|
+
settleNow();
|
|
13024
|
+
} else {
|
|
13025
|
+
_settleRequested = true;
|
|
13026
|
+
}
|
|
13027
|
+
});
|
|
13028
|
+
|
|
12966
13029
|
// don't let furniture container block events to symbol layers
|
|
12967
13030
|
_furniture.css('pointer-events', 'none');
|
|
12968
13031
|
|
|
12969
13032
|
this.drawMainLayers = function(layers, action) {
|
|
12970
|
-
var needSvgRedraw = action != 'nav' && action != 'hover';
|
|
12971
13033
|
if (skipMainLayerRedraw(action)) return;
|
|
13034
|
+
if (action == 'nav' && shouldUseFastNav()) {
|
|
13035
|
+
applyFastTransform();
|
|
13036
|
+
// SVG symbol reposition is already cheap; keep labels/symbols accurate
|
|
13037
|
+
// while the canvas is being transformed.
|
|
13038
|
+
layers.forEach(function(lyr) {
|
|
13039
|
+
if (internal.layerHasSvgSymbols(lyr) || internal.layerHasLabels(lyr)) {
|
|
13040
|
+
_svg.reposition(lyr, 'symbol');
|
|
13041
|
+
}
|
|
13042
|
+
});
|
|
13043
|
+
markRedrawPending();
|
|
13044
|
+
return;
|
|
13045
|
+
}
|
|
13046
|
+
var startTime = performance.now();
|
|
13047
|
+
var needSvgRedraw = action != 'nav' && action != 'hover';
|
|
13048
|
+
cancelSettle();
|
|
13049
|
+
_redrawPending = false;
|
|
13050
|
+
_settleRequested = false; // a full render satisfies any pending settle
|
|
13051
|
+
clearFastTransform();
|
|
12972
13052
|
_mainCanv.prep(_ext);
|
|
12973
13053
|
if (needSvgRedraw) {
|
|
12974
13054
|
_svg.clear();
|
|
@@ -12983,6 +13063,12 @@
|
|
|
12983
13063
|
drawCanvasLayer(lyr, _mainCanv);
|
|
12984
13064
|
}
|
|
12985
13065
|
});
|
|
13066
|
+
// Force synchronous rasterization so performance.now() reflects the true
|
|
13067
|
+
// frame cost (including GPU paint-op commit), and so subsequent fast-nav
|
|
13068
|
+
// CSS transforms don't composite over a still-pending canvas commit.
|
|
13069
|
+
flushCanvas(_mainCanv);
|
|
13070
|
+
_lastFrameMs = performance.now() - startTime;
|
|
13071
|
+
captureSnapshot();
|
|
12986
13072
|
};
|
|
12987
13073
|
|
|
12988
13074
|
// Draw highlight effect for hover and selection
|
|
@@ -13034,6 +13120,18 @@
|
|
|
13034
13120
|
}
|
|
13035
13121
|
}
|
|
13036
13122
|
|
|
13123
|
+
// Reading back a single pixel forces Chrome/Firefox to synchronously complete
|
|
13124
|
+
// any queued paint operations before returning. This converts an unbounded
|
|
13125
|
+
// deferred "Commit" phase into in-line wall time we can measure, and ensures
|
|
13126
|
+
// the canvas pixels are actually on screen before the caller returns.
|
|
13127
|
+
function flushCanvas(canv) {
|
|
13128
|
+
try {
|
|
13129
|
+
canv.node().getContext('2d').getImageData(0, 0, 1, 1);
|
|
13130
|
+
} catch (e) {
|
|
13131
|
+
// e.g. cross-origin-tainted canvas (shouldn't happen here, but safe)
|
|
13132
|
+
}
|
|
13133
|
+
}
|
|
13134
|
+
|
|
13037
13135
|
function getSvgLayerType(layer) {
|
|
13038
13136
|
var type = null;
|
|
13039
13137
|
if (internal.layerHasSvgSymbols(layer)) {
|
|
@@ -13043,6 +13141,87 @@
|
|
|
13043
13141
|
}
|
|
13044
13142
|
return type;
|
|
13045
13143
|
}
|
|
13144
|
+
|
|
13145
|
+
function captureSnapshot() {
|
|
13146
|
+
_snapshot = {
|
|
13147
|
+
bounds: _ext.getBounds(),
|
|
13148
|
+
width: _ext.width(),
|
|
13149
|
+
height: _ext.height(),
|
|
13150
|
+
pixRatio: GUI.getPixelRatio()
|
|
13151
|
+
};
|
|
13152
|
+
}
|
|
13153
|
+
|
|
13154
|
+
function shouldUseFastNav() {
|
|
13155
|
+
if (!_snapshot) return false;
|
|
13156
|
+
if (_lastFrameMs <= SLOW_FRAME_MS) return false;
|
|
13157
|
+
if (_snapshot.width != _ext.width() || _snapshot.height != _ext.height()) return false;
|
|
13158
|
+
if (_snapshot.pixRatio != GUI.getPixelRatio()) return false;
|
|
13159
|
+
return true;
|
|
13160
|
+
}
|
|
13161
|
+
|
|
13162
|
+
// Apply a CSS transform to the main canvas so its previously rendered
|
|
13163
|
+
// contents line up with the current map extent. The canvas bitmap is not
|
|
13164
|
+
// redrawn.
|
|
13165
|
+
function applyFastTransform() {
|
|
13166
|
+
var t = _ext.getTransform();
|
|
13167
|
+
var b = _snapshot.bounds;
|
|
13168
|
+
var tl = t.transform(b.xmin, b.ymax);
|
|
13169
|
+
var br = t.transform(b.xmax, b.ymin);
|
|
13170
|
+
var sx = (br[0] - tl[0]) / _snapshot.width;
|
|
13171
|
+
var sy = (br[1] - tl[1]) / _snapshot.height;
|
|
13172
|
+
// On retina the canvas bitmap is already scaled down to CSS pixels via a
|
|
13173
|
+
// CSS transform from the .retina class; overriding `transform` here
|
|
13174
|
+
// replaces that rule so we must bake the pixRatio scale back in.
|
|
13175
|
+
var k = 1 / _snapshot.pixRatio;
|
|
13176
|
+
setFastTransform(_mainCanv.node(), tl[0], tl[1], sx * k, sy * k);
|
|
13177
|
+
_fastActive = true;
|
|
13178
|
+
}
|
|
13179
|
+
|
|
13180
|
+
function clearFastTransform() {
|
|
13181
|
+
if (!_fastActive) return;
|
|
13182
|
+
var node = _mainCanv.node();
|
|
13183
|
+
node.style.transform = '';
|
|
13184
|
+
node.style.transformOrigin = '';
|
|
13185
|
+
_fastActive = false;
|
|
13186
|
+
}
|
|
13187
|
+
|
|
13188
|
+
function setFastTransform(node, tx, ty, sx, sy) {
|
|
13189
|
+
node.style.transformOrigin = 'top left';
|
|
13190
|
+
node.style.transform = 'translate(' + tx + 'px,' + ty + 'px) scale(' + sx + ',' + sy + ')';
|
|
13191
|
+
}
|
|
13192
|
+
|
|
13193
|
+
// Record that a fast-nav frame is showing so that the next end-of-interaction
|
|
13194
|
+
// event (or the fallback timer) can trigger a real redraw. Each fast-nav
|
|
13195
|
+
// frame resets the fallback timer so it only fires after the user truly
|
|
13196
|
+
// stops interacting, as a backstop for any interaction path that doesn't
|
|
13197
|
+
// emit 'map_interaction_end'. If 'map_interaction_end' was already
|
|
13198
|
+
// received before this frame ran (e.g. the home button reset, which
|
|
13199
|
+
// dispatches synchronously while the nav draw is still queued in rAF),
|
|
13200
|
+
// settle right now instead of waiting.
|
|
13201
|
+
function markRedrawPending() {
|
|
13202
|
+
_redrawPending = true;
|
|
13203
|
+
cancelSettle();
|
|
13204
|
+
if (_settleRequested) {
|
|
13205
|
+
_settleRequested = false;
|
|
13206
|
+
settleNow();
|
|
13207
|
+
} else {
|
|
13208
|
+
_settleTimer = setTimeout(settleNow, FAST_SETTLE_FALLBACK_MS);
|
|
13209
|
+
}
|
|
13210
|
+
}
|
|
13211
|
+
|
|
13212
|
+
function settleNow() {
|
|
13213
|
+
cancelSettle();
|
|
13214
|
+
if (!_redrawPending) return;
|
|
13215
|
+
_redrawPending = false;
|
|
13216
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
13217
|
+
}
|
|
13218
|
+
|
|
13219
|
+
function cancelSettle() {
|
|
13220
|
+
if (_settleTimer) {
|
|
13221
|
+
clearTimeout(_settleTimer);
|
|
13222
|
+
_settleTimer = null;
|
|
13223
|
+
}
|
|
13224
|
+
}
|
|
13046
13225
|
}
|
|
13047
13226
|
|
|
13048
13227
|
// Controls the shift-drag box editing tool
|
|
@@ -13778,6 +13957,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13778
13957
|
|
|
13779
13958
|
// RENDERING
|
|
13780
13959
|
// draw main content layers
|
|
13960
|
+
|
|
13781
13961
|
_renderer.drawMainLayers(contentLayers, action);
|
|
13782
13962
|
|
|
13783
13963
|
// draw hover & selection overlay
|
package/www/mapshaper.js
CHANGED
|
@@ -51131,7 +51131,7 @@ ${svg}
|
|
|
51131
51131
|
});
|
|
51132
51132
|
}
|
|
51133
51133
|
|
|
51134
|
-
var version = "0.6.
|
|
51134
|
+
var version = "0.6.120";
|
|
51135
51135
|
|
|
51136
51136
|
// Parse command line args into commands and run them
|
|
51137
51137
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|
package/www/page.css
CHANGED
|
@@ -196,10 +196,17 @@ body.map-view {
|
|
|
196
196
|
background-color: black;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
#
|
|
199
|
+
#sponsor-btn {
|
|
200
200
|
color: #ffa;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
#sponsor-btn svg {
|
|
204
|
+
width: 12px;
|
|
205
|
+
height: 12px;
|
|
206
|
+
fill: currentColor;
|
|
207
|
+
vertical-align: -1px;
|
|
208
|
+
}
|
|
209
|
+
|
|
203
210
|
.separator {
|
|
204
211
|
border-left: 1px solid white;
|
|
205
212
|
height: 10px;
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
margin: 0 0 32px;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
.
|
|
84
|
+
.sponsor-buttons {
|
|
85
85
|
display: flex;
|
|
86
86
|
gap: 12px;
|
|
87
87
|
flex-wrap: wrap;
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
background-color: #222;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
.
|
|
116
|
+
.sponsor-note {
|
|
117
117
|
font-size: 14px;
|
|
118
118
|
color: #666;
|
|
119
119
|
margin: 0 0 32px;
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
@media (max-width: 480px) {
|
|
160
160
|
main { padding: 24px 18px 60px; }
|
|
161
161
|
h1 { font-size: 26px; }
|
|
162
|
-
.
|
|
162
|
+
.sponsor-buttons { flex-direction: column; align-items: stretch; }
|
|
163
163
|
.btn { text-align: center; }
|
|
164
164
|
}
|
|
165
165
|
</style>
|
|
@@ -177,20 +177,20 @@
|
|
|
177
177
|
|
|
178
178
|
<p class="tagline">Mapshaper is free, open-source software for editing geographic data — used worldwide for everything from classroom exercises to professional map work.</p>
|
|
179
179
|
|
|
180
|
-
<div class="
|
|
181
|
-
<a href="https://ko-fi.com/mapshaper" class="btn">
|
|
180
|
+
<div class="sponsor-buttons">
|
|
181
|
+
<a href="https://ko-fi.com/mapshaper" class="btn">Support via Ko-fi</a>
|
|
182
182
|
<a href="https://github.com/sponsors/mbloch" class="btn btn-secondary">Sponsor on GitHub</a>
|
|
183
183
|
</div>
|
|
184
184
|
|
|
185
|
-
<p class="
|
|
185
|
+
<p class="sponsor-note">Ko-fi accepts one-time or recurring contributions — no account required. GitHub Sponsors offers recurring sponsorship.</p>
|
|
186
186
|
|
|
187
|
-
<h2>What your
|
|
187
|
+
<h2>What your contribution supports</h2>
|
|
188
188
|
<ul class="support-list">
|
|
189
189
|
<li>Development time — bug fixes, new features, performance improvements</li>
|
|
190
190
|
<li>Responding to user issues and requests</li>
|
|
191
191
|
</ul>
|
|
192
192
|
|
|
193
|
-
<h2>Recent
|
|
193
|
+
<h2>Recent work</h2>
|
|
194
194
|
<ul class="support-list">
|
|
195
195
|
<li><strong>GeoPackage</strong> import and export</li>
|
|
196
196
|
<li><strong>FlatGeobuf</strong> import and export</li>
|