Commit 9c0c450920ae3ef86ff609af6ddf86a8266d449f
1 parent
93ee5563
Exists in
master
and in
2 other branches
Add a loader to the whole page.
Showing
4 changed files
with
154 additions
and
21 deletions
Show diff stats
CHANGELOG.md
1 | -## TODO | |
1 | +## Misc | |
2 | 2 | |
3 | -- Support multiple models for each target | |
4 | -- Play button to start time dimension | |
3 | +- [ ] Support multiple models for each target | |
4 | +- [ ] Play button to start time dimension (not very useful?) | |
5 | 5 | |
6 | 6 | ## 1.0.0 |
7 | 7 | |
8 | 8 | - [x] Cache generated CSVs on the server side |
9 | 9 | - [x] Cache generated CSVs on the client side |
10 | -- [x] Visits counter | |
10 | +- [x] Count visits | |
11 | 11 | - [x] Zoom in on time series |
12 | +- [x] Loader and targets loading animation | |
12 | 13 | - [ ] Start/Stop datetime fields |
13 | -- [ ] Loader | |
14 | 14 | - [ ] Download raw data (as CSV) for current time interval and targets |
15 | 15 | - [ ] Same via SAMP |
16 | 16 | - [ ] Credit the author of the pixel art planets | ... | ... |
web/static/js/swapp.js
... | ... | @@ -60,7 +60,8 @@ |
60 | 60 | console.info("Loaded CSV data of " + target.name + "."); |
61 | 61 | this$.createTimeSeries(target, data); |
62 | 62 | this$.orbits.initOrbiter(target.slug, target.config, data['hci']); |
63 | - return targetButton.removeClass('loading'); | |
63 | + targetButton.removeClass('loading'); | |
64 | + return this$.hideLoader(); | |
64 | 65 | }, function(error){ |
65 | 66 | return console.error('Failed to load CSV data.', error); |
66 | 67 | }); |
... | ... | @@ -117,6 +118,9 @@ |
117 | 118 | return ts.resize(); |
118 | 119 | }); |
119 | 120 | }; |
121 | + SpaceWeather.prototype.hideLoader = function(){ | |
122 | + return $("#plots_loader").hide(); | |
123 | + }; | |
120 | 124 | SpaceWeather.prototype.loadData = function(target_slug, started_at, stopped_at){ |
121 | 125 | "Load the data as CSV for the specified target and interval,\nand return it in a Promise."; |
122 | 126 | var sw, promise; |
... | ... | @@ -172,27 +176,38 @@ |
172 | 176 | }); |
173 | 177 | return timeSeries.forEach(function(ts){ |
174 | 178 | ts.options['onMouseOver'] = function(){ |
175 | - return timeSeries.forEach(function(ts2){ | |
179 | + timeSeries.forEach(function(ts2){ | |
176 | 180 | return ts2.showCursor(); |
177 | 181 | }); |
182 | + return true; | |
178 | 183 | }; |
179 | 184 | ts.options['onMouseOut'] = function(){ |
180 | - return timeSeries.forEach(function(ts2){ | |
185 | + timeSeries.forEach(function(ts2){ | |
181 | 186 | return ts2.hideCursor(); |
182 | 187 | }); |
188 | + return true; | |
183 | 189 | }; |
184 | 190 | ts.options['onMouseMove'] = function(t){ |
185 | 191 | var ref$; |
186 | 192 | timeSeries.forEach(function(ts2){ |
187 | 193 | return ts2.moveCursor(t); |
188 | 194 | }); |
189 | - return (ref$ = this$.orbits) != null ? ref$.moveToDate(t) : void 8; | |
195 | + if ((ref$ = this$.orbits) != null) { | |
196 | + ref$.moveToDate(t); | |
197 | + } | |
198 | + return true; | |
190 | 199 | }; |
191 | 200 | ts.options['onBrushEnd'] = function(sta, sto){ |
192 | - return this$.resizeDomain(sta, sto); | |
201 | + this$.resizeDomain(sta, sto); | |
202 | + return true; | |
193 | 203 | }; |
194 | 204 | return ts.options['onDblClick'] = function(){ |
195 | - return this$.resetZoom(); | |
205 | + var ref$; | |
206 | + this$.resetZoom(); | |
207 | + if ((ref$ = $("#zoom_controls_help")) != null) { | |
208 | + ref$.remove(); | |
209 | + } | |
210 | + return true; | |
196 | 211 | }; |
197 | 212 | }); |
198 | 213 | }; | ... | ... |
web/static/js/swapp.ls
... | ... | @@ -11,6 +11,10 @@ |
11 | 11 | # templates, such as `home.html.jinja2`. |
12 | 12 | |
13 | 13 | # Note: We use Promises and ES6 whenever relevant. |
14 | +# You also will need d3js v4 documentation : https://d3js.org/ | |
15 | +# We're using a custom build of 4.9.1, one line changed, see d3-custom.js | |
16 | +# Event bubbling cannot trigger two rects unless we make an event dispatcher, | |
17 | +# and d3's brush is stopping propagation, as it should by default. | |
14 | 18 | |
15 | 19 | ############################################################################### |
16 | 20 | |
... | ... | @@ -81,6 +85,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE |
81 | 85 | @createTimeSeries(target, data) |
82 | 86 | @orbits.initOrbiter(target.slug, target.config, data['hci']) |
83 | 87 | targetButton.removeClass('loading') |
88 | + @hideLoader() | |
84 | 89 | , |
85 | 90 | (error) -> console.error('Failed to load CSV data.', error) |
86 | 91 | ) |
... | ... | @@ -117,6 +122,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE |
117 | 122 | @orbits?.resize(); |
118 | 123 | timeSeries.forEach((ts) -> ts.resize()) |
119 | 124 | |
125 | + hideLoader: -> | |
126 | + $("\#plots_loader").hide(); | |
127 | + | |
120 | 128 | loadData: (target_slug, started_at, stopped_at) -> |
121 | 129 | """ |
122 | 130 | Load the data as CSV for the specified target and interval, |
... | ... | @@ -145,7 +153,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE |
145 | 153 | ) |
146 | 154 | promise |
147 | 155 | |
148 | - timeSeries = [] # Not sure why this ain't an instance prop. Probably should. | |
156 | + timeSeries = [] # deprecated (was for scoping) ; use @property with ~> | |
149 | 157 | createTimeSeries: (target, data) -> |
150 | 158 | @configuration['parameters'].forEach((parameter) ~> |
151 | 159 | container = @configuration['time_series_container'] |
... | ... | @@ -155,18 +163,18 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE |
155 | 163 | id, title, target, data[id], @parameters[id].active, container |
156 | 164 | )) |
157 | 165 | ) |
158 | - timeSeries.forEach((ts) ~> | |
166 | + timeSeries.forEach((ts) ~> # returning true may be faster | |
159 | 167 | ts.options['onMouseOver'] = -> |
160 | - timeSeries.forEach((ts2) -> ts2.showCursor()) | |
168 | + timeSeries.forEach((ts2) -> ts2.showCursor()) ; true | |
161 | 169 | ts.options['onMouseOut'] = -> |
162 | - timeSeries.forEach((ts2) -> ts2.hideCursor()) | |
170 | + timeSeries.forEach((ts2) -> ts2.hideCursor()) ; true | |
163 | 171 | ts.options['onMouseMove'] = (t) ~> |
164 | 172 | timeSeries.forEach((ts2) -> ts2.moveCursor(t)) |
165 | - @orbits?.moveToDate(t) | |
173 | + @orbits?.moveToDate(t) ; true | |
166 | 174 | ts.options['onBrushEnd'] = (sta, sto) ~> |
167 | - @resizeDomain(sta, sto) | |
175 | + @resizeDomain(sta, sto) ; true | |
168 | 176 | ts.options['onDblClick'] = ~> |
169 | - @resetZoom() | |
177 | + @resetZoom() ; $("\#zoom_controls_help")?.remove() ; true | |
170 | 178 | ) |
171 | 179 | |
172 | 180 | enableParameter: (parameter_slug) -> | ... | ... |
web/view/home.html.jinja2
... | ... | @@ -14,6 +14,16 @@ |
14 | 14 | > |
15 | 15 | {%- endmacro %} |
16 | 16 | |
17 | + | |
18 | +<div id="plots_loader"> | |
19 | + <p class="loader-text">Loading Heliopropa…<br>This might take a while.</p> | |
20 | + <div id="plots_loader_img1" class="img"></div> | |
21 | + <div id="plots_loader_img2" class="img"></div> | |
22 | + <div id="plots_loader_img3" class="img"></div> | |
23 | + <div id="plots_loader_img4" class="img"></div> | |
24 | + <div id="plots_loader_img5" class="img"></div> | |
25 | +</div> | |
26 | + | |
17 | 27 | <div class="mdl-layout mdl-js-layout mdl-layout--fixed-drawer"> |
18 | 28 | |
19 | 29 | <div class="mdl-layout__drawer"> |
... | ... | @@ -72,7 +82,9 @@ |
72 | 82 | <section id="orbits"></section> |
73 | 83 | </div> |
74 | 84 | <div class="mdl-cell mdl-cell--8-col"> |
75 | - <section id="time_series"></section> | |
85 | + <section id="time_series"> | |
86 | + <p id="zoom_controls_help" class="help mdl-cell--8-col">Drag to zoom in, double click to zoom out.</p> | |
87 | + </section> | |
76 | 88 | </div> |
77 | 89 | </div> |
78 | 90 | |
... | ... | @@ -89,6 +101,103 @@ |
89 | 101 | {# background-color: #322e3f;#} |
90 | 102 | {# color: #e3e3e3;#} |
91 | 103 | } |
104 | + #plots_wrapper { | |
105 | +{# position: relative;#} | |
106 | + } | |
107 | + #plots_loader { | |
108 | + position: absolute; | |
109 | + top: 0; left: 0; bottom: 0; right: 0; | |
110 | + height: 100%; | |
111 | + width: 100%; | |
112 | + background-color: #fff; | |
113 | + z-index: 1000; | |
114 | + } | |
115 | + | |
116 | + #plots_loader .loader-text { | |
117 | + width: 200px; | |
118 | + height: 30px; | |
119 | + position: absolute; | |
120 | + top: -240px; left: -32px; bottom: 0; right: 0; | |
121 | + margin: auto; | |
122 | + text-align: center; | |
123 | + font-size: 1.0em; | |
124 | + font-style: italic; | |
125 | + color: darkgrey; | |
126 | + } | |
127 | + | |
128 | + #plots_loader .img { | |
129 | + width: 100px; | |
130 | + height: 100px; | |
131 | + border-radius: 100%; | |
132 | + position: absolute; | |
133 | + border: 1px solid #6978ff; | |
134 | + animation: up 1s; | |
135 | + animation-iteration-count: infinite; | |
136 | + transition: 2s; | |
137 | + border-bottom: none; | |
138 | + border-right: none; | |
139 | + animation-timing-function: linear; | |
140 | + margin-left: -70px; | |
141 | + margin-top: -70px; | |
142 | + left: 50%; | |
143 | + top: 50%; | |
144 | + } | |
145 | + | |
146 | + @keyframes up { | |
147 | + from { | |
148 | + transform: rotate(0deg); | |
149 | + } | |
150 | + 50% { | |
151 | + transform: rotate(180deg); | |
152 | + } | |
153 | + 100% { | |
154 | + transform: rotate(360deg); | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + #plots_loader #plots_loader_img2 { | |
159 | + width: 90px; | |
160 | + height: 90px; | |
161 | + left: 50.35%; | |
162 | + top: 50.7%; | |
163 | + animation-delay: .2s; | |
164 | + } | |
165 | + | |
166 | + #plots_loader #plots_loader_img3 { | |
167 | + width: 80px; | |
168 | + height: 80px; | |
169 | + left: 50.70%; | |
170 | + top: 51.4%; | |
171 | + animation-delay: .4s; | |
172 | + } | |
173 | + | |
174 | + #plots_loader #plots_loader_img4 { | |
175 | + width: 70px; | |
176 | + height: 70px; | |
177 | + left: 51.05%; | |
178 | + top: 52.1%; | |
179 | + animation-delay: .6s; | |
180 | + } | |
181 | + | |
182 | + #plots_loader #plots_loader_img5 { | |
183 | + width: 60px; | |
184 | + height: 60px; | |
185 | + left: 51.40%; | |
186 | + top: 52.8%; | |
187 | + animation-delay: .8s; | |
188 | + } | |
189 | + | |
190 | + #time_series .help { | |
191 | + position: absolute; | |
192 | + text-align: center; | |
193 | + font-size: 0.9em; | |
194 | + font-style: italic; | |
195 | + color: darkgrey; | |
196 | + display: none; | |
197 | + } | |
198 | + #time_series:hover .help { | |
199 | + display: block; | |
200 | + } | |
92 | 201 | .axis path, .axis line { |
93 | 202 | fill: none; |
94 | 203 | {# stroke: #f4f4f4;#} |
... | ... | @@ -288,7 +397,7 @@ jQuery().ready(function($){ |
288 | 397 | var isLastTargetEnabled = function(target_slug) { |
289 | 398 | var s = 0; |
290 | 399 | $(".orbiters_filters .target:not(.locked)").each(function(i,p) { |
291 | - if ($(p).hasClass('active')) s++; | |
400 | + if ($(p).hasClass('active') && ! $(p).hasClass('loading')) s++; | |
292 | 401 | }); |
293 | 402 | return s < 2; |
294 | 403 | }; |
... | ... | @@ -304,7 +413,8 @@ jQuery().ready(function($){ |
304 | 413 | } |
305 | 414 | return false; |
306 | 415 | }); |
307 | - $(".orbiters_filters .target:not(.locked)").click(function(e){ | |
416 | + $(".orbiters_filters .target:not(.locked)").on("click", function(e){ | |
417 | + if ($(this).hasClass('loading')) return false; | |
308 | 418 | var switch_on = ! $(this).hasClass('active'); |
309 | 419 | var target_slug = $(this).attr('data-target-slug'); |
310 | 420 | if (switch_on) { | ... | ... |