From d348cc5741803f607c9b058efad92f0e6a2fc7b0 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 1 Mar 2013 13:06:44 -0800 Subject: [PATCH 1/2] Add loading indicator --- css/app.css | 4 +++ index.html | 1 + js/id/connection.js | 65 ++++++++++++++++++++------------------------- js/id/ui.js | 4 +++ js/id/ui/spinner.js | 19 +++++++++++++ 5 files changed, 57 insertions(+), 36 deletions(-) create mode 100644 js/id/ui/spinner.js diff --git a/css/app.css b/css/app.css index 558d85599..ead4f71a2 100644 --- a/css/app.css +++ b/css/app.css @@ -24,6 +24,10 @@ body { max-width: 1200px; } +.spinner { + float: right; +} + div, textarea, input, form, span, ul, li, ol, a, button { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; diff --git a/index.html b/index.html index 06d3fa16c..246e57e21 100644 --- a/index.html +++ b/index.html @@ -79,6 +79,7 @@ + diff --git a/js/id/connection.js b/js/id/connection.js index 380c24b02..ccfb451f7 100644 --- a/js/id/connection.js +++ b/js/id/connection.js @@ -1,6 +1,6 @@ iD.Connection = function(context) { - var event = d3.dispatch('auth', 'load'), + var event = d3.dispatch('auth', 'loading', 'load', 'loaded'), url = 'http://api06.dev.openstreetmap.org', connection = {}, user = {}, @@ -19,19 +19,6 @@ iD.Connection = function(context) { return url + '/browse/changeset/' + changesetId; }; - function bboxUrl(b) { - return url + '/api/0.6/map?bbox=' + [b[0][0],b[1][1],b[1][0],b[0][1]]; - } - - function bboxFromAPI(box, tile, callback) { - function done(err, parsed) { - loadedTiles[tile.toString()] = true; - delete inflight[tile.toString()]; - callback(err, parsed); - } - inflight[tile.toString()] = connection.loadFromURL(bboxUrl(box), done); - } - connection.loadFromURL = function(url, callback) { function done(dom) { return callback(null, parse(dom)); @@ -237,17 +224,8 @@ iD.Connection = function(context) { oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done); }; - function tileAlreadyLoaded(c) { return !loadedTiles[c.toString()] && !inflight[c.toString()]; } - function abortRequest(i) { i.abort(); } - function loadTile(e) { - function done(err, g) { - event.load(err, g); - } - bboxFromAPI(e.box, e.tile, done); - } - connection.loadTiles = function(projection, dimensions) { var scaleExtent = [16, 16], s = projection.scale(), @@ -263,15 +241,14 @@ iD.Connection = function(context) { s / 2 - projection.translate()[0], s / 2 - projection.translate()[1]]; - function apiExtentBox(c) { - var x = (c[0] * ts) - tile_origin[0]; - var y = (c[1] * ts) - tile_origin[1]; - return { - box: [ - projection.invert([x, y]), - projection.invert([x + ts, y + ts])], - tile: c - }; + function bboxUrl(tile) { + var x = (tile[0] * ts) - tile_origin[0]; + var y = (tile[1] * ts) - tile_origin[1]; + var b = [ + projection.invert([x, y]), + projection.invert([x + ts, y + ts])]; + + return url + '/api/0.6/map?bbox=' + [b[0][0], b[1][1], b[1][0], b[0][1]]; } _.filter(inflight, function(v, i) { @@ -282,10 +259,26 @@ iD.Connection = function(context) { return !wanted; }).map(abortRequest); - tiles - .filter(tileAlreadyLoaded) - .map(apiExtentBox) - .forEach(loadTile); + tiles.forEach(function(tile) { + var id = tile.toString(); + + if (loadedTiles[id] || inflight[id]) return; + + if (_.isEmpty(inflight)) { + event.loading(); + } + + inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) { + loadedTiles[id] = true; + delete inflight[id]; + + event.load(err, parsed); + + if (_.isEmpty(inflight)) { + event.loaded(); + } + }); + }); }; connection.userUrl = function(username) { diff --git a/js/id/ui.js b/js/id/ui.js index 1cb7bdd22..df9c23eaa 100644 --- a/js/id/ui.js +++ b/js/id/ui.js @@ -48,6 +48,10 @@ iD.ui = function(context) { .attr('class', 'button-wrap col1') .call(iD.ui.Save(context)); + bar.append('div') + .attr('class', 'spinner') + .call(iD.ui.Spinner(context)); + container.append('div') .attr('class', 'map-control zoombuttons') .call(iD.ui.Zoom(context)); diff --git a/js/id/ui/spinner.js b/js/id/ui/spinner.js new file mode 100644 index 000000000..733df565b --- /dev/null +++ b/js/id/ui/spinner.js @@ -0,0 +1,19 @@ +iD.ui.Spinner = function(context) { + var connection = context.connection(); + + return function(selection) { + var img = selection.append('img') + .attr('src', 'img/loader.gif') + .style('opacity', 0); + + connection.on('loading.spinner', function() { + img.transition() + .style('opacity', 1); + }); + + connection.on('loaded.spinner', function() { + img.transition() + .style('opacity', 0); + }); + } +}; From 8d911a4a9dfa586ba2ff724e48dbc92851e26ba9 Mon Sep 17 00:00:00 2001 From: Saman Bemel-Benrud Date: Thu, 7 Mar 2013 13:14:16 -0500 Subject: [PATCH 2/2] styling loading state. --- css/app.css | 21 ++++++++++++++++++--- img/loader-black.gif | Bin 0 -> 1715 bytes js/id/ui/spinner.js | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 img/loader-black.gif diff --git a/css/app.css b/css/app.css index ead4f71a2..c11b105f3 100644 --- a/css/app.css +++ b/css/app.css @@ -25,7 +25,22 @@ body { } .spinner { - float: right; + opacity: .5; +} + +.spinner img { + position: fixed; + padding: 5px; + height: 40px; + width: 40px; + left: 0; + right: 0; + bottom: 0; + top: 0; + margin: auto; + border-radius: 5px; + background: black; + pointer-events:none; } div, textarea, input, form, span, ul, li, ol, a, button { @@ -1172,7 +1187,7 @@ img.tile { opacity: 1; } -#about { +#about { height: 20px; text-align: right; } @@ -1252,7 +1267,7 @@ div.typeahead a:first-child { z-index: 3; } -.modal .loader { +.modal .loader { margin-bottom: 10px; } diff --git a/img/loader-black.gif b/img/loader-black.gif new file mode 100644 index 0000000000000000000000000000000000000000..08f0d7e346c26196d1dbdec9cb52fcf95951afb9 GIT binary patch literal 1715 zcmZ|PeNfV80KoCzkKYdjL_l5?5s^0m6-}IM=~icm2m*ylrKPuJ9(v8QqBJxtHMB%3 zw9+zP@}+`aOjFlDgZ>UQgPw|1+wI|r++_Q#&TpXcuLe4m#jrF?Ph zIw2qgzLNm%v2^Luyu3WC)%xJU1F=}VWXTc=g+d?@@OXS&TpW=|gdiw1G&CY2A~iKN zGBWb+-Ma+^1xlsTVzG2}b#XWxyt5aWFvlJ?5?%Z3~J95W}iZ7}%0 z6%4=t10cCuHF{d{3_Q~E&CbkZ6r|iTX_h)}w-wr`eEFGK!;rce`Yp0g$8wLikqSqnhS? znu>SQk>(eMAgBYyFuzA9II9Wdg=Ae)p^>0-5{b^3m;^7orZT3dW^Sg>I7rhhTz6fbzB)b&Pklfoxv3;~TL5(+Ue;D-57@8BVH1VC)+9a|dkAG; z@l)>@J;b)A^C^dD9Z3}rT#>HW`}q9B>D1`ve&g$GCAL~32s4<{{Il!Ynmb znxL+}ia~;oHjx;*#-?`CvGxw#krPl$LzTN@gC{Dvo(B*5UZ@G-55mKBWZ#RUHDeQ@ zm&OM<^^-8GA(X?4RQ$(@e&@7#l4dTZ2ej9D-oW0c=U?L%cdCD!=^nv4?(MoTuGRU> zZJujl-ok>3_p($`&t8e=+0Wht)6z{l%!CSaW%~9#h_d2>VBvmuE}}6QYNRx%=u|4* zU9=HuQc+=;DkV}**kz|rC!FhH_V&pxGzJa!4|hZC5m?0xVn>Y^_e~g2ohfc@EB*la zmgu>r4IZQj?^{`B$cU%4jy*A~DO>a9wBvk9DW|_&zs(d;`>__7m$e*5i?{mzLbQt> zD9s~+05PK6->5Ay!Tb;jgG6Gu+m<7Ct*A2jlBFaFB1!%H4;+$(Za>^8ZEj9z>xhtX zb{~34rWI(&^QdCR0pTAg}ol`(|T|FGL={iBR*73WBdDc;~18`p+=q1SUpKDpv3 z+y;dUB{TwoCc$A%;EuHNZ4{!CfItwGUZ{OG6|?BTA?4x2$xSWZs-TL4suKv6!-Q9{ zJJdbuJ|9&SJBXCw876G(MoG-X$=!d&`2aYxw#eL?Iz~i hzX6rp*3sl~C59UvqqYe*u|SOke;2 literal 0 HcmV?d00001 diff --git a/js/id/ui/spinner.js b/js/id/ui/spinner.js index 733df565b..c567dd257 100644 --- a/js/id/ui/spinner.js +++ b/js/id/ui/spinner.js @@ -3,7 +3,7 @@ iD.ui.Spinner = function(context) { return function(selection) { var img = selection.append('img') - .attr('src', 'img/loader.gif') + .attr('src', 'img/loader-black.gif') .style('opacity', 0); connection.on('loading.spinner', function() {