From d216afd59f9721d4c47b0254151dc787db2ed719 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 12 Mar 2015 00:30:34 -0400 Subject: [PATCH 1/8] Map-in-Map overview * press 'M' to toggle * shows current zoom-6 * with locator overlay and bounding box --- css/app.css | 31 ++++++++- index.html | 1 + js/id/ui.js | 5 ++ js/id/ui/map_in_map.js | 142 +++++++++++++++++++++++++++++++++++++++++ test/index.html | 1 + 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 js/id/ui/map_in_map.js diff --git a/css/app.css b/css/app.css index 8b9e5e6ec..aa1d38082 100644 --- a/css/app.css +++ b/css/app.css @@ -683,7 +683,7 @@ a:hover .icon.out-link { background-position: -500px -14px;} float: left; height: 100%; overflow: hidden; - z-index: 2; + z-index: 10; background: #f6f6f6; } @@ -2104,6 +2104,35 @@ img.wiki-image { bottom: 0; } +/* Map-In-Map +------------------------------------------------------- */ + +.map-in-map-wrap { + position: absolute; + overflow: hidden; + top: 60px; + width: 200px; + height: 150px; + z-index: 9; + background: #000; + border: #aaa 1px solid; + box-shadow: 0 0 2em black; + pointer-events: none; +} + +.map-in-map-wrap svg { + position: relative; + overflow: hidden; + height: 100%; +} + +.map-in-map-bbox { + fill: none; + stroke: rgba(255, 255, 0, 0.75); + stroke-width: 1; + shape-rendering: crispEdges; +} + /* About Section ------------------------------------------------------- */ diff --git a/index.html b/index.html index 3e71faba6..fd5e3aeba 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,7 @@ + diff --git a/js/id/ui.js b/js/id/ui.js index 35ed98bbe..ebe689a88 100644 --- a/js/id/ui.js +++ b/js/id/ui.js @@ -32,6 +32,11 @@ iD.ui = function(context) { .attr('id', 'map') .call(map); + content.append('div') + .attr('class', 'map-in-map-wrap') + .style('display', 'none') + .call(iD.ui.MapInMap(context)); + bar.append('div') .attr('class', 'spacer col4'); diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js new file mode 100644 index 000000000..577470a32 --- /dev/null +++ b/js/id/ui/map_in_map.js @@ -0,0 +1,142 @@ +iD.ui.MapInMap = function(context) { + var key = 'M', + backgroundLayer = iD.TileLayer(), + overlayLayer = iD.TileLayer(); + + function map_in_map(selection) { + + function render() { + if (hidden()) return; + + var loc = context.map().center(), + d = selection.dimensions(), + c = [d[0] / 2, d[1] / 2], + k1 = context.projection.scale(), + z1 = Math.log(k1 * 2 * Math.PI) / Math.LN2 - 8, + z = Math.max(z1 - 6, 2); + + var projection = iD.geo.RawMercator() + .scale(256 * Math.pow(2, z) / (2 * Math.PI)); + + var s = projection(loc); + + projection + .translate([c[0] - s[0], c[1] - s[1]]) + .clipExtent([[0, 0], d]); + + + // render background + backgroundLayer + .source(context.background().baseLayerSource()) + .projection(projection) + .dimensions(d); + + var background = selection + .selectAll('.map-in-map-background') + .data([0]); + + background.enter() + .append('div') + .attr('class', 'map-in-map-background'); + + background + .call(backgroundLayer); + + + // render overlay + var overlaySources = context.background().overlayLayerSources(), + hasOverlay = false; + + for (var i = 0; i < overlaySources.length; i++) { + if (overlaySources[i].validZoom(z)) { + overlayLayer + .source(overlaySources[i]) + .projection(projection) + .dimensions(d); + + hasOverlay = true; + break; + } + } + + var overlay = selection + .selectAll('.map-in-map-overlay') + .data(hasOverlay ? [0] : []); + + overlay.enter() + .append('div') + .attr('class', 'map-in-map-overlay'); + + overlay.exit() + .remove(); + + overlay + .call(overlayLayer); + + + // render bounding box + var getPath = d3.geo.path().projection(projection), + bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; + + var svg = selection.selectAll('svg') + .data([0]); + + svg.enter() + .append('svg'); + + var path = svg.selectAll('path') + .data([bbox]); + + path.enter() + .append('path') + .attr('class', 'map-in-map-bbox'); + + path + .attr('d', getPath); + } + + + function hidden() { + return selection.style('display') === 'none'; + } + + + function toggle() { + if (d3.event) d3.event.preventDefault(); + + if (hidden()) { + selection + .style('display', 'block') + .style('opacity', 0) + .transition() + .duration(200) + .style('opacity', 1); + + render(); + + } else { + selection + .style('display', 'block') + .style('opacity', 1) + .transition() + .duration(200) + .style('opacity', 0) + .each('end', function() { + d3.select(this).style('display', 'none'); + }); + } + } + + + context.map().on('drawn.map-in-map', render); + render(); + + var keybinding = d3.keybinding('map-in-map') + .on(key, toggle); + + d3.select(document) + .call(keybinding); + } + + return map_in_map; +}; diff --git a/test/index.html b/test/index.html index 4f4f6510c..ae6159606 100644 --- a/test/index.html +++ b/test/index.html @@ -84,6 +84,7 @@ + From 2ad69870e79525b28ef25f5cb12752dd33ce3980 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 13 Mar 2015 19:47:11 -0400 Subject: [PATCH 2/8] Panning map-in-map now recenters main map --- css/app.css | 18 +++- css/map.css | 1 + js/id/ui.js | 2 +- js/id/ui/map_in_map.js | 187 ++++++++++++++++++++++++++++++++--------- 4 files changed, 162 insertions(+), 46 deletions(-) diff --git a/css/app.css b/css/app.css index aa1d38082..d41276d04 100644 --- a/css/app.css +++ b/css/app.css @@ -2107,7 +2107,7 @@ img.wiki-image { /* Map-In-Map ------------------------------------------------------- */ -.map-in-map-wrap { +.map-in-map { position: absolute; overflow: hidden; top: 60px; @@ -2117,13 +2117,25 @@ img.wiki-image { background: #000; border: #aaa 1px solid; box-shadow: 0 0 2em black; - pointer-events: none; } -.map-in-map-wrap svg { +.map-in-map-tiles { + transform-origin:0 0; + -ms-transform-origin:0 0; + -webkit-transform-origin:0 0; + -moz-transform-origin:0 0; + -o-transform-origin:0 0; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.map-in-map-svg { position: relative; overflow: hidden; height: 100%; + width: 100%; } .map-in-map-bbox { diff --git a/css/map.css b/css/map.css index b3ec162e5..c3edae105 100644 --- a/css/map.css +++ b/css/map.css @@ -1032,6 +1032,7 @@ g.turn circle { /* Cursors */ +.map-in-map, #map { cursor: auto; /* Opera */ cursor: url(img/cursor-grab.png) 9 9, auto; /* FF */ diff --git a/js/id/ui.js b/js/id/ui.js index ebe689a88..e61c3160d 100644 --- a/js/id/ui.js +++ b/js/id/ui.js @@ -33,7 +33,7 @@ iD.ui = function(context) { .call(map); content.append('div') - .attr('class', 'map-in-map-wrap') + .attr('class', 'map-in-map') .style('display', 'none') .call(iD.ui.MapInMap(context)); diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index 577470a32..e93282ed4 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -1,37 +1,121 @@ iD.ui.MapInMap = function(context) { - var key = 'M', - backgroundLayer = iD.TileLayer(), - overlayLayer = iD.TileLayer(); + var key = 'M'; function map_in_map(selection) { + var backgroundLayer = iD.TileLayer(), + overlayLayer = iD.TileLayer(), + projection = iD.geo.RawMercator(), + zoom = d3.behavior.zoom() + // .scaleExtent([1024, 256 * Math.pow(2, 24)]) + .on('zoom', zoomPan), + transformed = false, + panning = false, + tLast = [0, 0], + tCurr = [0, 0], + tiles, + timeoutId; - function render() { - if (hidden()) return; + function startZoomPan() { + context.surface().on('mouseup.map-in-map-outside', endZoomPan); + context.container().on('mouseup.map-in-map-outside', endZoomPan); + } + + + function zoomPan() { + var t = d3.event.translate, + e = d3.event.sourceEvent; + + if (e.type === 'wheel') { + // for now, throw out wheel events + zoom.translate(tCurr).scale(1); + + } else if (e.type === 'mousemove') { + var tDiff = [ t[0] - tLast[0], t[1] - tLast[1] ]; + tCurr = t; + + iD.util.setTransform(tiles, tDiff[0], tDiff[1]); + transformed = true; + panning = true; + queueRedraw(); + } + + e.preventDefault(); + e.stopPropagation(); + } + + + function endZoomPan() { + context.surface().on('mouseup.map-in-map-outside', null); + context.container().on('mouseup.map-in-map-outside', null); + + updateProjection(); + + tLast = [0, 0]; + tCurr = [0, 0]; + zoom.translate([0, 0]).scale(1); + panning = false; + + var d = selection.dimensions(), + c = [ d[0] / 2, d[1] / 2 ]; + + context.map().center(projection.invert(c)); + } + + + function updateProjection() { var loc = context.map().center(), d = selection.dimensions(), - c = [d[0] / 2, d[1] / 2], + c = [ d[0] / 2, d[1] / 2 ], k1 = context.projection.scale(), z1 = Math.log(k1 * 2 * Math.PI) / Math.LN2 - 8, - z = Math.max(z1 - 6, 2); - - var projection = iD.geo.RawMercator() - .scale(256 * Math.pow(2, z) / (2 * Math.PI)); - - var s = projection(loc); + z = Math.max(z1 - 6, 0.5); projection - .translate([c[0] - s[0], c[1] - s[1]]) + .translate([0,0]) + .scale(256 * Math.pow(2, z) / (2 * Math.PI)); + + var s = projection(loc), + t = [c[0] - s[0] + tCurr[0], + c[1] - s[1] + tCurr[1] ]; + + projection + .translate(t) .clipExtent([[0, 0], d]); + } - // render background + function redraw() { + if (hidden()) return; + + updateProjection(); + + var d = selection.dimensions(), + z = Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8; + + // setup tile container + tiles = selection + .selectAll('.map-in-map-tiles') + .data([0]); + + tiles + .enter() + .append('div') + .attr('class', 'map-in-map-tiles'); + + if (transformed) { + tLast = tCurr; + iD.util.setTransform(tiles, 0, 0); + transformed = false; + } + + // redraw background backgroundLayer .source(context.background().baseLayerSource()) .projection(projection) .dimensions(d); - var background = selection + var background = tiles .selectAll('.map-in-map-background') .data([0]); @@ -42,8 +126,7 @@ iD.ui.MapInMap = function(context) { background .call(backgroundLayer); - - // render overlay + // redraw overlay var overlaySources = context.background().overlayLayerSources(), hasOverlay = false; @@ -59,7 +142,7 @@ iD.ui.MapInMap = function(context) { } } - var overlay = selection + var overlay = tiles .selectAll('.map-in-map-overlay') .data(hasOverlay ? [0] : []); @@ -70,29 +153,39 @@ iD.ui.MapInMap = function(context) { overlay.exit() .remove(); - overlay - .call(overlayLayer); + if (hasOverlay) { + overlay + .call(overlayLayer); + } + + // redraw bounding box + if (!panning) { + var getPath = d3.geo.path().projection(projection), + bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; + + var svg = selection.selectAll('.map-in-map-svg') + .data([0]); + + svg.enter() + .append('svg') + .attr('class', 'map-in-map-svg'); + + var path = svg.selectAll('.map-in-map-bbox') + .data([bbox]); + + path.enter() + .append('path') + .attr('class', 'map-in-map-bbox'); + + path + .attr('d', getPath); + } + } - // render bounding box - var getPath = d3.geo.path().projection(projection), - bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; - - var svg = selection.selectAll('svg') - .data([0]); - - svg.enter() - .append('svg'); - - var path = svg.selectAll('path') - .data([bbox]); - - path.enter() - .append('path') - .attr('class', 'map-in-map-bbox'); - - path - .attr('d', getPath); + function queueRedraw() { + clearTimeout(timeoutId); + timeoutId = setTimeout(function() { redraw(); }, 300); } @@ -112,7 +205,7 @@ iD.ui.MapInMap = function(context) { .duration(200) .style('opacity', 1); - render(); + redraw(); } else { selection @@ -128,8 +221,18 @@ iD.ui.MapInMap = function(context) { } - context.map().on('drawn.map-in-map', render); - render(); + selection + .on('mousedown.map-in-map', startZoomPan) + .on('mouseup.map-in-map', endZoomPan); + + selection + .call(zoom) + .on('dblclick.zoom', null); + + context.map() + .on('drawn.map-in-map', redraw); + + redraw(); var keybinding = d3.keybinding('map-in-map') .on(key, toggle); From b6136b9a7c7e08ea36b60475cabc1d41449ae1ba Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 15 Mar 2015 22:58:25 -0400 Subject: [PATCH 3/8] fix z-index for modals to be above sidebar, map-in-map --- css/app.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/css/app.css b/css/app.css index d41276d04..a92b75a82 100644 --- a/css/app.css +++ b/css/app.css @@ -655,7 +655,7 @@ a:hover .icon.out-link { background-position: -500px -14px;} right: 0; top: 0; height: 59px; - z-index: 3; + z-index: 50; } .footer { @@ -2295,7 +2295,7 @@ img.wiki-image { left: 0; right: 0; margin: auto; - z-index: 3; + z-index: 50; } .modal .loader { @@ -2307,7 +2307,7 @@ img.wiki-image { } .shaded { - z-index: 2; + z-index: 49; position: absolute; top: 0; bottom: 0; From ba12127e8a16a1d28b524bd566c933a4923630e2 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Sun, 15 Mar 2015 23:13:27 -0400 Subject: [PATCH 4/8] Use '/' key for map-in-map (because 'M' = Move) --- js/id/ui/map_in_map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index e93282ed4..a0e012306 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -1,5 +1,5 @@ iD.ui.MapInMap = function(context) { - var key = 'M'; + var key = '/'; function map_in_map(selection) { var backgroundLayer = iD.TileLayer(), From ea0bca9914670a2b4d77622dd809a321748644c4 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Mar 2015 16:35:58 -0400 Subject: [PATCH 5/8] setup zoom behavior to use Mercator space Also, a few optimizations: * don't redraw the minimap unless mainmap dispatched a full redraw event * don't recenter mainmap on zoomend unless minimap actually got panned --- js/id/ui/map_in_map.js | 80 +++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index a0e012306..defce61f8 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -6,40 +6,50 @@ iD.ui.MapInMap = function(context) { overlayLayer = iD.TileLayer(), projection = iD.geo.RawMercator(), zoom = d3.behavior.zoom() - // .scaleExtent([1024, 256 * Math.pow(2, 24)]) + .scaleExtent([ztok(0.5), ztok(24)]) .on('zoom', zoomPan), transformed = false, panning = false, + tStart = [0, 0], tLast = [0, 0], tCurr = [0, 0], + kLast = 1, + kCurr = 1, tiles, timeoutId; + function ztok(z) { return 256 * Math.pow(2, z); } + function ktoz(k) { return Math.log(k) / Math.LN2 - 8; } + function startZoomPan() { context.surface().on('mouseup.map-in-map-outside', endZoomPan); context.container().on('mouseup.map-in-map-outside', endZoomPan); + tStart = tLast = tCurr = projection.translate(); + panning = true; } function zoomPan() { var t = d3.event.translate, + k = d3.event.scale, e = d3.event.sourceEvent; if (e.type === 'wheel') { - // for now, throw out wheel events - zoom.translate(tCurr).scale(1); + // for now, ignore wheel events + kCurr = k; + zoom.translate(tCurr).scale(kCurr); } else if (e.type === 'mousemove') { - var tDiff = [ t[0] - tLast[0], t[1] - tLast[1] ]; tCurr = t; - - iD.util.setTransform(tiles, tDiff[0], tDiff[1]); - transformed = true; - panning = true; - queueRedraw(); } + var tTiles = [ tCurr[0] - tLast[0], tCurr[1] - tLast[1] ]; + iD.util.setTransform(tiles, tTiles[0], tTiles[1]); + + transformed = true; + queueRedraw(); + e.preventDefault(); e.stopPropagation(); } @@ -50,16 +60,14 @@ iD.ui.MapInMap = function(context) { context.container().on('mouseup.map-in-map-outside', null); updateProjection(); - - tLast = [0, 0]; - tCurr = [0, 0]; - zoom.translate([0, 0]).scale(1); panning = false; - var d = selection.dimensions(), - c = [ d[0] / 2, d[1] / 2 ]; + if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) { + var d = selection.dimensions(), + c = [ d[0] / 2, d[1] / 2 ]; - context.map().center(projection.invert(c)); + context.map().center(projection.invert(c)); + } } @@ -67,21 +75,38 @@ iD.ui.MapInMap = function(context) { var loc = context.map().center(), d = selection.dimensions(), c = [ d[0] / 2, d[1] / 2 ], + t1 = context.projection.translate(), k1 = context.projection.scale(), - z1 = Math.log(k1 * 2 * Math.PI) / Math.LN2 - 8, - z = Math.max(z1 - 6, 0.5); + z1 = ktoz(k1 * 2 * Math.PI), + z = Math.max(z1 - 6, 0.5), + k = ztok(z); projection - .translate([0,0]) - .scale(256 * Math.pow(2, z) / (2 * Math.PI)); + .translate(t1) + .scale(k / (2 * Math.PI)); var s = projection(loc), - t = [c[0] - s[0] + tCurr[0], - c[1] - s[1] + tCurr[1] ]; + mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0], + t = [ + c[0] - s[0] + t1[0] + mouse[0], + c[1] - s[1] + t1[1] + mouse[1] + ]; projection .translate(t) .clipExtent([[0, 0], d]); + + zoom + .translate(t) + .scale(k); + + tLast = tCurr = t; + kLast = kCurr = k; + + if (transformed) { + iD.util.setTransform(tiles, 0, 0); + transformed = false; + } } @@ -91,7 +116,7 @@ iD.ui.MapInMap = function(context) { updateProjection(); var d = selection.dimensions(), - z = Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8; + z = ktoz(projection.scale() * 2 * Math.PI); // setup tile container tiles = selection @@ -103,11 +128,6 @@ iD.ui.MapInMap = function(context) { .append('div') .attr('class', 'map-in-map-tiles'); - if (transformed) { - tLast = tCurr; - iD.util.setTransform(tiles, 0, 0); - transformed = false; - } // redraw background backgroundLayer @@ -230,7 +250,9 @@ iD.ui.MapInMap = function(context) { .on('dblclick.zoom', null); context.map() - .on('drawn.map-in-map', redraw); + .on('drawn.map-in-map', function(drawn) { + if (drawn.full === true) redraw(); + }); redraw(); From 5190c0b85787397431c80b711a853d2e897480f4 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 16 Mar 2015 23:03:25 -0400 Subject: [PATCH 6/8] Minimap can now zoom/unzoom --- js/id/ui/map_in_map.js | 108 ++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 51 deletions(-) diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index defce61f8..c1de16401 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -10,44 +10,48 @@ iD.ui.MapInMap = function(context) { .on('zoom', zoomPan), transformed = false, panning = false, - tStart = [0, 0], - tLast = [0, 0], - tCurr = [0, 0], - kLast = 1, - kCurr = 1, - tiles, - timeoutId; + zDiff = 6, // by default, minimap renders at (main zoom - 6) + tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId; function ztok(z) { return 256 * Math.pow(2, z); } function ktoz(k) { return Math.log(k) / Math.LN2 - 8; } - function startZoomPan() { - context.surface().on('mouseup.map-in-map-outside', endZoomPan); - context.container().on('mouseup.map-in-map-outside', endZoomPan); + function startMouse() { + context.surface().on('mouseup.map-in-map-outside', endMouse); + context.container().on('mouseup.map-in-map-outside', endMouse); + tStart = tLast = tCurr = projection.translate(); panning = true; } function zoomPan() { - var t = d3.event.translate, + var e = d3.event.sourceEvent, + t = d3.event.translate, k = d3.event.scale, - e = d3.event.sourceEvent; + zMain = ktoz(context.projection.scale() * 2 * Math.PI), + zMini = ktoz(k); - if (e.type === 'wheel') { - // for now, ignore wheel events - kCurr = k; - zoom.translate(tCurr).scale(kCurr); - - } else if (e.type === 'mousemove') { - tCurr = t; + // restrict minimap zoom to < (main zoom - 3) + if (zMini > zMain - 3) { + zMini = zMain - 3; + zoom.scale(kCurr).translate(tCurr); // restore last good values + return; } - var tTiles = [ tCurr[0] - tLast[0], tCurr[1] - tLast[1] ]; - iD.util.setTransform(tiles, tTiles[0], tTiles[1]); + tCurr = t; + kCurr = k; + zDiff = zMain - zMini; + var scale = kCurr / kLast, + tX = Math.round((tCurr[0] / scale - tLast[0]) * scale), + tY = Math.round((tCurr[1] / scale - tLast[1]) * scale); + + iD.util.setTransform(tiles, tX, tY, scale); + iD.util.setTransform(svg, 0, 0, scale); transformed = true; + queueRedraw(); e.preventDefault(); @@ -55,7 +59,7 @@ iD.ui.MapInMap = function(context) { } - function endZoomPan() { + function endMouse() { context.surface().on('mouseup.map-in-map-outside', null); context.container().on('mouseup.map-in-map-outside', null); @@ -63,48 +67,50 @@ iD.ui.MapInMap = function(context) { panning = false; if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) { - var d = selection.dimensions(), - c = [ d[0] / 2, d[1] / 2 ]; + var dMini = selection.dimensions(), + cMini = [ dMini[0] / 2, dMini[1] / 2 ]; - context.map().center(projection.invert(c)); + context.map().center(projection.invert(cMini)); } } function updateProjection() { var loc = context.map().center(), - d = selection.dimensions(), - c = [ d[0] / 2, d[1] / 2 ], - t1 = context.projection.translate(), - k1 = context.projection.scale(), - z1 = ktoz(k1 * 2 * Math.PI), - z = Math.max(z1 - 6, 0.5), - k = ztok(z); + dMini = selection.dimensions(), + cMini = [ dMini[0] / 2, dMini[1] / 2 ], + tMain = context.projection.translate(), + kMain = context.projection.scale(), + zMain = ktoz(kMain * 2 * Math.PI), + zMini = Math.max(zMain - zDiff, 0.5), + kMini = ztok(zMini); projection - .translate(t1) - .scale(k / (2 * Math.PI)); + .translate(tMain) + .scale(kMini / (2 * Math.PI)); var s = projection(loc), mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0], - t = [ - c[0] - s[0] + t1[0] + mouse[0], - c[1] - s[1] + t1[1] + mouse[1] + tMini = [ + cMini[0] - s[0] + tMain[0] + mouse[0], + cMini[1] - s[1] + tMain[1] + mouse[1] ]; projection - .translate(t) - .clipExtent([[0, 0], d]); + .translate(tMini) + .clipExtent([[0, 0], dMini]); zoom - .translate(t) - .scale(k); + .center(cMini) + .translate(tMini) + .scale(kMini); - tLast = tCurr = t; - kLast = kCurr = k; + tLast = tCurr = tMini; + kLast = kCurr = kMini; if (transformed) { iD.util.setTransform(tiles, 0, 0); + iD.util.setTransform(svg, 0, 0); transformed = false; } } @@ -115,8 +121,8 @@ iD.ui.MapInMap = function(context) { updateProjection(); - var d = selection.dimensions(), - z = ktoz(projection.scale() * 2 * Math.PI); + var dMini = selection.dimensions(), + zMini = ktoz(projection.scale() * 2 * Math.PI); // setup tile container tiles = selection @@ -133,7 +139,7 @@ iD.ui.MapInMap = function(context) { backgroundLayer .source(context.background().baseLayerSource()) .projection(projection) - .dimensions(d); + .dimensions(dMini); var background = tiles .selectAll('.map-in-map-background') @@ -151,11 +157,11 @@ iD.ui.MapInMap = function(context) { hasOverlay = false; for (var i = 0; i < overlaySources.length; i++) { - if (overlaySources[i].validZoom(z)) { + if (overlaySources[i].validZoom(zMini)) { overlayLayer .source(overlaySources[i]) .projection(projection) - .dimensions(d); + .dimensions(dMini); hasOverlay = true; break; @@ -183,7 +189,7 @@ iD.ui.MapInMap = function(context) { var getPath = d3.geo.path().projection(projection), bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; - var svg = selection.selectAll('.map-in-map-svg') + svg = selection.selectAll('.map-in-map-svg') .data([0]); svg.enter() @@ -242,8 +248,8 @@ iD.ui.MapInMap = function(context) { selection - .on('mousedown.map-in-map', startZoomPan) - .on('mouseup.map-in-map', endZoomPan); + .on('mousedown.map-in-map', startMouse) + .on('mouseup.map-in-map', endMouse); selection .call(zoom) From bf3d5d838661d9e5951b976090f0f624a17b4638 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 17 Mar 2015 00:51:48 -0400 Subject: [PATCH 7/8] Show solid marker when bbox is too small to see --- css/app.css | 4 ++++ js/id/ui/map_in_map.js | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/css/app.css b/css/app.css index a92b75a82..97e90f76a 100644 --- a/css/app.css +++ b/css/app.css @@ -2145,6 +2145,10 @@ img.wiki-image { shape-rendering: crispEdges; } +.map-in-map-bbox.thick { + stroke-width: 5; +} + /* About Section ------------------------------------------------------- */ diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index c1de16401..385807854 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -204,7 +204,8 @@ iD.ui.MapInMap = function(context) { .attr('class', 'map-in-map-bbox'); path - .attr('d', getPath); + .attr('d', getPath) + .classed('thick', function(d) { return getPath.area(d) < 30; }); } } From 7a3e4b05fcec0bd5dbb5cfaf0f2654e00b8f8d4b Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 17 Mar 2015 01:08:50 -0400 Subject: [PATCH 8/8] move minimap z-index below #bar (and its tooltips) --- css/app.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/css/app.css b/css/app.css index 97e90f76a..2eccfbe2d 100644 --- a/css/app.css +++ b/css/app.css @@ -609,7 +609,7 @@ a:hover .icon.out-link { background-position: -500px -14px;} top:0; right:0; height:60px; - z-index: 1; + z-index: 9; min-width: 768px; } @@ -2113,7 +2113,7 @@ img.wiki-image { top: 60px; width: 200px; height: 150px; - z-index: 9; + z-index: 5; background: #000; border: #aaa 1px solid; box-shadow: 0 0 2em black;