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 @@
+