From 0a2049563884a504113af59a094042bbf4c75d6d Mon Sep 17 00:00:00 2001 From: Matthew Bloch Date: Mon, 1 Apr 2024 15:52:09 -0400 Subject: [PATCH] Update website --- mapshaper-gui.js | 214 +++++++++++++++++++++++++++++++++-------------- mapshaper.js | 3 +- 2 files changed, 152 insertions(+), 65 deletions(-) diff --git a/mapshaper-gui.js b/mapshaper-gui.js index 47382f5a..c588825d 100644 --- a/mapshaper-gui.js +++ b/mapshaper-gui.js @@ -2778,30 +2778,7 @@ function getDefaultStyle(lyr, baseStyle) { - var style = Object.assign({}, baseStyle); - // reduce the dot size of large point layers - if (lyr.geometry_type == 'point' && style.dotSize > 0) { - style.dotSize *= getDotScale$1(lyr); - } - return style; - } - - function getDotScale$1(lyr) { - var topTier = 10000; - var n = countPoints(lyr.shapes, topTier); // short-circuit point counting above top threshold - var k = n < 200 && 4 || n < 2500 && 3 || n < topTier && 2 || 1; - return k; - } - - function countPoints(shapes, max) { - var count = 0; - var i, n, shp; - max = max || Infinity; - for (i=0, n=shapes.length; i bbox[0] && p[0] < bbox[2] && p[1] > bbox[1] && p[1] < bbox[3]; + }; + var topTier = 50000; + var count = 0; + layers = layers.filter(function(lyr) { + return lyr.geometry_type == 'point' && lyr.gui.style.dotSize > 0; + }); + layers.forEach(function(lyr) { + // short-circuit point counting above top threshold + count += countPoints(lyr.gui.displayLayer.shapes, topTier, testInBounds); + }); + count = Math.min(topTier, count) || 1; + var k = Math.pow(6 - utils$1.clamp(Math.log10(count), 1, 5), 1.3); + + // zoom adjustments + var mapScale = ext.scale(); + if (mapScale < 0.5) { + k *= Math.pow(mapScale + 0.5, 0.35); + } else if (mapScale > 1) { + // scale faster at first + k *= Math.pow(Math.min(mapScale, 4), 0.15); + k *= Math.pow(mapScale, 0.05); + } + + // scale down when map is small + var smallSide = Math.min(ext.width(), ext.height()); + k *= utils$1.clamp(smallSide / 500, 0.5, 1); + + layers.forEach(function(lyr) { + lyr.gui.style.dotScale = k; + }); + if (overlayLyr && overlayLyr.geometry_type == 'point' && overlayLyr.gui.style.dotSize > 0) { + overlayLyr.gui.style.dotScale = k; + } + } + + function countPoints(shapes, max, filter) { + var count = 0; + var i, j, n, m, shp; + for (i=0, n=shapes.length; i 1.5) return false; + } + return true; + } + function setZ(lyr, z) { lyr.gui.source.dataset.arcs.setRetainedInterval(z); if (isProjectedLayer(lyr)) { @@ -5755,29 +5802,37 @@ var self = this; var shiftDown = false; var ctrlDown = false; + var metaDown = false; + var altDown = false; + + function updateControlKeys(e) { + shiftDown = e.shiftKey; + ctrlDown = e.ctrlKey; + metaDown = e.metaKey; + altDown = e.altKey; + } document.addEventListener('keyup', function(e) { if (!GUI.isActiveInstance(gui)) return; // this can fail to fire if keyup occurs over a context menu - shiftDown = e.shiftKey; - ctrlDown = e.ctrlKey; + updateControlKeys(e); self.dispatchEvent('keyup', getEventData(e)); }); document.addEventListener('keydown', function(e) { if (!GUI.isActiveInstance(gui)) return; - shiftDown = e.shiftKey; - ctrlDown = e.ctrlKey; + updateControlKeys(e); self.dispatchEvent('keydown', getEventData(e)); }); document.addEventListener('mousemove', function(e) { // refreshing these here to prevent problems when context menu opens - shiftDown = e.shiftKey; - ctrlDown = e.ctrlKey; + updateControlKeys(e); }); this.shiftIsPressed = function() { return shiftDown; }; this.ctrlIsPressed = function() { return ctrlDown; }; + this.altIsPressed = function() { return altDown; }; + this.metaIsPressed = function() { return metaDown; }; this.onMenuSubmit = function(menuEl, cb) { gui.on('enter_key', function(e) { @@ -9317,8 +9372,7 @@ function useBoxZoom() { var mode = gui.getMode(); - var disabled = ['selection_tool', 'box_tool', 'rectangle_tool'].includes(mode); - return !disabled; + return !'selection_tool,box_tool,rectangle_tool,drawing_tool'.includes(mode); } function getBoxData(e) { @@ -10278,6 +10332,7 @@ var drawingId = -1; // feature id of path being drawn var sessionCount = 0; var alert; + var pencilPoints; var _dragging = false; function active() { @@ -10292,6 +10347,10 @@ return drawingId > -1; } + function usingPencil() { + return (gui.keyboard.altIsPressed() || gui.keyboard.metaIsPressed()) && active() && !dragging(); + } + function polygonMode() { return active() && hit.getHitTarget().geometry_type == 'polygon'; } @@ -10373,11 +10432,12 @@ function showInstructions() { var isMac = navigator.userAgent.includes('Mac'); - var symbol = isMac ? '⌘' : '^'; + var undoKey = isMac ? '⌘' : '^'; + var drawKey = isMac ? '⌘' : 'Alt'; var pathStr = polygonMode() ? 'closed paths' : 'paths'; - var msg = `Instructions: Click on the map to draw ${pathStr}. Drag vertices to reshape a path. Type ${symbol}Z/${symbol}Y to undo/redo.`; + var msg = `Instructions: Click to start a path or add a point. ${drawKey}-drag draws a path. Drag points to reshape. Type ${undoKey}Z/${undoKey}Y to undo/redo.`; alert = showPopupAlert(msg, null, { - non_blocking: true, max_width: '360px'}); + non_blocking: true, max_width: '388px'}); } function hideInstructions() { @@ -10462,9 +10522,28 @@ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type); }); + gui.map.getMouse().on('drag', function(e) { + if (!usingPencil()) return; + e.stopPropagation(); + var xy = [e.x, e.y]; + var p = pixToDataCoords(e.x, e.y); + if (!drawing()) { + pencilPoints = [xy]; + startNewPath(p); + } else if (!pencilPoints || !pencilPointIsSkippable(xy, pencilPoints)) { + pencilPoints = [xy]; + extendCurrentPath(p); + } else { + // skip this point, update the hover line + pencilPoints.push(xy); + updatePathEndpoint(p); + } + }, null, 3); // higher priority than hit control + hit.on('drag', function(e) { if (!dragging() || drawing()) return; e.originalEvent.stopPropagation(); + // dragging a vertex var target = hit.getHitTarget(); var p = ext.translatePixelCoords(e.x, e.y); if (gui.keyboard.shiftIsPressed()) { @@ -10543,8 +10622,6 @@ deleteActiveVertex(e); } else { startNewPath(p); - hideInstructions(); - updateCursor(); } prevClickEvent = e; }); @@ -10655,6 +10732,14 @@ gui.dispatchEvent('path_add', {target, p1, p2}); drawingId = target.shapes.length - 1; hit.setDrawingId(drawingId); + hideInstructions(); + updateCursor(); + } + + function pencilDraw(e) { + var p = pixToDataCoords(e.x, e.y); + extendCurrentPath(p); + } // p: [x, y] source data coordinates of new point on path @@ -11442,8 +11527,7 @@ _self.drawSquareDots = function(shapes, style) { var t = getScaledTransform(_ext), - scaleRatio = getDotScale(_ext), - size = Math.round((style.dotSize || 1) * scaleRatio), + size = getDotSize(style), styler = style.styler || null, xmax = _canvas.width + size, ymax = _canvas.height + size, @@ -11463,7 +11547,7 @@ for (i=0, n=shapes.length; i 1) { - // scale faster at first, so small dots in large datasets - // become easily visible and clickable after zooming in a bit - k *= Math.pow(Math.min(mapScale, 10), 0.3); - k *= Math.pow(mapScale, 0.1); - } - // grow pixels more slowly on retina displays (to reduce number of pixels to - // draw for large point datasets when slightly zoomed in) - var l = Math.pow(GUI.getPixelRatio(), 0.8); - return j * k * l; + function getDotSize(style) { + var size = style.dotSize || 1; + // TODO: improve + var scale = style.dotScale || 1; + size += (scale - 1) / 2; + size *= Math.pow(scale, 0.3); + + // shrink dots slightly on retina displays, to adjust for greater clarity + // and reduce number of pixels to draw on large datasets. + return Math.round(Math.pow(GUI.getPixelRatio(), 0.8) * size); } function getScaledTransform(ext) { @@ -12698,10 +12773,7 @@ GUI and setting the size and crop of SVG output.