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