From c595fdbf57fd72cc270564c643dc27f27a3e2e71 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 24 Feb 2016 12:04:44 -0500 Subject: [PATCH] Avoid calling getComputedStyle and triggering reflows --- css/app.css | 2 +- js/id/ui.js | 6 +--- js/id/ui/contributors.js | 43 ++++++++++++++++------------ js/id/ui/info.js | 56 ++++++++++++++++++++---------------- js/id/ui/map_in_map.js | 61 +++++++++++++++++++--------------------- 5 files changed, 87 insertions(+), 81 deletions(-) diff --git a/css/app.css b/css/app.css index 79b45a37a..52122e1d2 100644 --- a/css/app.css +++ b/css/app.css @@ -2208,7 +2208,7 @@ div.full-screen > button:hover { border-bottom: 1px solid black; } -.infobox .selection-heading { +.infobox .infobox-heading { display: block; border-radius: 4px 0 0 0; padding: 5px 10px; diff --git a/js/id/ui.js b/js/id/ui.js index 403e92aee..3c7a51b90 100644 --- a/js/id/ui.js +++ b/js/id/ui.js @@ -32,14 +32,10 @@ iD.ui = function(context) { .attr('id', 'map') .call(map); - content.append('div') - .attr('class', 'map-in-map') - .style('display', 'none') + content .call(iD.ui.MapInMap(context)); content.append('div') - .attr('class', 'infobox fillD2') - .style('display', 'none') .call(iD.ui.Info(context)); bar.append('div') diff --git a/js/id/ui/contributors.js b/js/id/ui/contributors.js index 86a38c067..8bf709e71 100644 --- a/js/id/ui/contributors.js +++ b/js/id/ui/contributors.js @@ -1,7 +1,11 @@ iD.ui.Contributors = function(context) { - function update(selection) { + var debouncedUpdate = _.debounce(function() { update(); }, 1000), + limit = 4, + hidden = false, + wrap = d3.select(null); + + function update() { var users = {}, - limit = 4, entities = context.intersects(context.map().extent()); entities.forEach(function(entity) { @@ -11,7 +15,7 @@ iD.ui.Contributors = function(context) { var u = Object.keys(users), subset = u.slice(0, u.length > limit ? limit - 1 : limit); - selection.html('') + wrap.html('') .call(iD.svg.Icon('#icon-nearby', 'pre-text light')); var userList = d3.select(document.createElement('span')); @@ -37,29 +41,32 @@ iD.ui.Contributors = function(context) { }) .text(u.length - limit + 1); - selection.append('span') - .html(t('contributors.truncated_list', {users: userList.html(), count: count.html()})); + wrap.append('span') + .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() })); + } else { - selection.append('span') - .html(t('contributors.list', {users: userList.html()})); + wrap.append('span') + .html(t('contributors.list', { users: userList.html() })); } if (!u.length) { - selection.transition().style('opacity', 0); - } else if (selection.style('opacity') === '0') { - selection.transition().style('opacity', 1); + hidden = true; + wrap + .transition() + .style('opacity', 0); + + } else if (hidden) { + wrap + .transition() + .style('opacity', 1); } } return function(selection) { - update(selection); + wrap = selection; + update(); - context.connection().on('loaded.contributors', function() { - update(selection); - }); - - context.map().on('move.contributors', _.debounce(function() { - update(selection); - }, 500)); + context.connection().on('loaded.contributors', debouncedUpdate); + context.map().on('move.contributors', debouncedUpdate); }; }; diff --git a/js/id/ui/info.js b/js/id/ui/info.js index fee64d1ba..948d08f19 100644 --- a/js/id/ui/info.js +++ b/js/id/ui/info.js @@ -1,6 +1,7 @@ iD.ui.Info = function(context) { var key = iD.ui.cmd('⌘I'), - imperial = (iD.detect().locale.toLowerCase() === 'en-us'); + imperial = (iD.detect().locale.toLowerCase() === 'en-us'), + hidden = true; function info(selection) { function radiansToMeters(r) { @@ -95,7 +96,7 @@ iD.ui.Info = function(context) { function redraw() { - if (hidden()) return; + if (hidden) return; var resolver = context.graph(), selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }), @@ -103,9 +104,9 @@ iD.ui.Info = function(context) { extent = iD.geo.Extent(), entity; - selection.html(''); - selection.append('h4') - .attr('class', 'selection-heading fillD') + wrap.html(''); + wrap.append('h4') + .attr('class', 'infobox-heading fillD') .text(singular || t('infobox.selected', { n: selected.length })); if (!selected.length) return; @@ -118,16 +119,16 @@ iD.ui.Info = function(context) { center = extent.center(); - var list = selection.append('ul'); + var list = wrap.append('ul'); - // multiple selection, just display extent center.. + // multiple wrap, just display extent center.. if (!singular) { list.append('li') .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5)); return; } - // single selection, display details.. + // single wrap, display details.. if (!entity) return; var geometry = entity.geometry(resolver); @@ -156,7 +157,7 @@ iD.ui.Info = function(context) { var toggle = imperial ? 'imperial' : 'metric'; - selection.append('a') + wrap.append('a') .text(t('infobox.' + toggle)) .attr('href', '#') .attr('class', 'button') @@ -178,26 +179,13 @@ iD.ui.Info = function(context) { } - 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); + hidden = !hidden; - redraw(); - - } else { - selection + if (hidden) { + wrap .style('display', 'block') .style('opacity', 1) .transition() @@ -206,9 +194,27 @@ iD.ui.Info = function(context) { .each('end', function() { d3.select(this).style('display', 'none'); }); + } else { + wrap + .style('display', 'block') + .style('opacity', 0) + .transition() + .duration(200) + .style('opacity', 1); + + redraw(); } } + + var wrap = selection.selectAll('.infobox') + .data([0]); + + wrap.enter() + .append('div') + .attr('class', 'infobox fillD2') + .style('display', (hidden ? 'none' : 'block')); + context.map() .on('drawn.info', redraw); diff --git a/js/id/ui/map_in_map.js b/js/id/ui/map_in_map.js index 07a7e4cf6..f0a5ead02 100644 --- a/js/id/ui/map_in_map.js +++ b/js/id/ui/map_in_map.js @@ -11,6 +11,7 @@ iD.ui.MapInMap = function(context) { .on('zoom', zoomPan), transformed = false, panning = false, + hidden = true, zDiff = 6, // by default, minimap renders at (main zoom - 6) tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId; @@ -68,7 +69,7 @@ iD.ui.MapInMap = function(context) { panning = false; if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) { - var dMini = selection.dimensions(), + var dMini = wrap.dimensions(), cMini = [ dMini[0] / 2, dMini[1] / 2 ]; context.map().center(projection.invert(cMini)); @@ -78,7 +79,7 @@ iD.ui.MapInMap = function(context) { function updateProjection() { var loc = context.map().center(), - dMini = selection.dimensions(), + dMini = wrap.dimensions(), cMini = [ dMini[0] / 2, dMini[1] / 2 ], tMain = context.projection.translate(), kMain = context.projection.scale(), @@ -118,15 +119,15 @@ iD.ui.MapInMap = function(context) { function redraw() { - if (hidden()) return; + if (hidden) return; updateProjection(); - var dMini = selection.dimensions(), + var dMini = wrap.dimensions(), zMini = ktoz(projection.scale() * 2 * Math.PI); // setup tile container - tiles = selection + tiles = wrap .selectAll('.map-in-map-tiles') .data([0]); @@ -206,7 +207,7 @@ iD.ui.MapInMap = function(context) { var getPath = d3.geo.path().projection(projection), bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; - svg = selection.selectAll('.map-in-map-svg') + svg = wrap.selectAll('.map-in-map-svg') .data([0]); svg.enter() @@ -233,31 +234,17 @@ iD.ui.MapInMap = function(context) { } - function hidden() { - return selection.style('display') === 'none'; - } - - function toggle() { if (d3.event) d3.event.preventDefault(); + hidden = !hidden; + var label = d3.select('.minimap-toggle'); + label.classed('active', !hidden) + .select('input').property('checked', !hidden); - if (hidden()) { - selection - .style('display', 'block') - .style('opacity', 0) - .transition() - .duration(200) - .style('opacity', 1); - - label.classed('active', true) - .select('input').property('checked', true); - - redraw(); - - } else { - selection + if (hidden) { + wrap .style('display', 'block') .style('opacity', 1) .transition() @@ -266,19 +253,29 @@ iD.ui.MapInMap = function(context) { .each('end', function() { d3.select(this).style('display', 'none'); }); + } else { + wrap + .style('display', 'block') + .style('opacity', 0) + .transition() + .duration(200) + .style('opacity', 1); - label.classed('active', false) - .select('input').property('checked', false); + redraw(); } } iD.ui.MapInMap.toggle = toggle; - selection - .on('mousedown.map-in-map', startMouse) - .on('mouseup.map-in-map', endMouse); + var wrap = selection.selectAll('.map-in-map') + .data([0]); - selection + wrap.enter() + .append('div') + .attr('class', 'map-in-map') + .style('display', (hidden ? 'none' : 'block')) + .on('mousedown.map-in-map', startMouse) + .on('mouseup.map-in-map', endMouse) .call(zoom) .on('dblclick.zoom', null);