Commit ae0aa7d28cb17e91bc39216bf40b6392aac5b3f8
1 parent
ebf98c26
Exists in
master
and in
3 other branches
Add an x axis label for the orbits graph.
Showing
3 changed files
with
173 additions
and
23 deletions
Show diff stats
web/static/js/swapp.js
1 | 1 | // Generated by LiveScript 1.5.0 |
2 | 2 | (function(){ |
3 | - var GOLDEN_RATIO, TimeSeries, Orbits, out$ = typeof exports != 'undefined' && exports || this; | |
3 | + var GOLDEN_RATIO, SpaceWeather, Source, TimeSeries, Orbits, out$ = typeof exports != 'undefined' && exports || this; | |
4 | 4 | GOLDEN_RATIO = 2 / (1 + Math.sqrt(5)); |
5 | + out$.SpaceWeather = SpaceWeather = (function(){ | |
6 | + SpaceWeather.displayName = 'SpaceWeather'; | |
7 | + var prototype = SpaceWeather.prototype, constructor = SpaceWeather; | |
8 | + function SpaceWeather(configuration){ | |
9 | + console.info("Creating Space Weather app...", configuration); | |
10 | + } | |
11 | + return SpaceWeather; | |
12 | + }()); | |
13 | + Source = (function(){ | |
14 | + Source.displayName = 'Source'; | |
15 | + var prototype = Source.prototype, constructor = Source; | |
16 | + function Source(slug){ | |
17 | + this.slug = slug; | |
18 | + this.time_series = {}; | |
19 | + } | |
20 | + Source.prototype.addTimeSeries = function(ts){ | |
21 | + return this.time_series[ts.slug] = ts; | |
22 | + }; | |
23 | + Source.prototype.show = function(){ | |
24 | + var slug, ref$, ts, results$ = []; | |
25 | + for (slug in ref$ = this.time_series) { | |
26 | + ts = ref$[slug]; | |
27 | + results$.push($(ts.svg).show()); | |
28 | + } | |
29 | + return results$; | |
30 | + }; | |
31 | + Source.prototype.hide = function(){ | |
32 | + var slug, ref$, ts, results$ = []; | |
33 | + for (slug in ref$ = this.time_series) { | |
34 | + ts = ref$[slug]; | |
35 | + results$.push($(ts.svg).hide()); | |
36 | + } | |
37 | + return results$; | |
38 | + }; | |
39 | + return Source; | |
40 | + }()); | |
5 | 41 | out$.TimeSeries = TimeSeries = (function(){ |
6 | 42 | TimeSeries.displayName = 'TimeSeries'; |
7 | 43 | var prototype = TimeSeries.prototype, constructor = TimeSeries; |
... | ... | @@ -16,12 +52,12 @@ |
16 | 52 | this.onMouseOut = bind$(this, 'onMouseOut', prototype); |
17 | 53 | this.onMouseOver = bind$(this, 'onMouseOver', prototype); |
18 | 54 | this.onMouseMove = bind$(this, 'onMouseMove', prototype); |
19 | - console.log("Create time series '" + this.title + "'"); | |
55 | + console.info("Creating time series '" + this.title + "'..."); | |
20 | 56 | this.init(); |
21 | 57 | } |
22 | 58 | TimeSeries.prototype.init = function(){ |
23 | 59 | var dx, this$ = this; |
24 | - console.log("Initialize time series '" + this.title + "'", this.data, this.options); | |
60 | + console.info("Initializing time series '" + this.title + "'...", this.data, this.options); | |
25 | 61 | this.margin = { |
26 | 62 | top: 30, |
27 | 63 | right: 20, |
... | ... | @@ -159,7 +195,7 @@ |
159 | 195 | this.margin = { |
160 | 196 | top: 30, |
161 | 197 | right: 20, |
162 | - bottom: 30, | |
198 | + bottom: 40, | |
163 | 199 | left: 60 |
164 | 200 | }; |
165 | 201 | this.extremum = 1.11 * d3.max(this.data, function(d){ |
... | ... | @@ -172,8 +208,13 @@ |
172 | 208 | this.svg = d3.select(this.container).append('svg'); |
173 | 209 | this.plotWrapper = this.svg.append('g'); |
174 | 210 | this.plotWrapper.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); |
175 | - this.plotWrapper.append('g').classed('x axis', true); | |
176 | - this.plotWrapper.append('g').classed('y axis', true); | |
211 | + this.xAxisLine = this.plotWrapper.append('g').classed('x axis', true); | |
212 | + this.yAxisLine = this.plotWrapper.append('g').classed('y axis', true); | |
213 | + this.xAxisTitle = this.xAxisLine.append('text').attr('fill', '#000'); | |
214 | + this.xAxisTitle.style("text-anchor", "middle"); | |
215 | + this.xAxisTitle.append('tspan').text('X'); | |
216 | + this.xAxisTitle.append('tspan').attr('dy', '3px').text('HEE').attr('font-size', '0.618em'); | |
217 | + this.xAxisTitle.append('tspan').attr('dy', '-3px').text(' (AU)'); | |
177 | 218 | this.sun = this.plotWrapper.append("svg:circle"); |
178 | 219 | this.sun.append('svg:title').text("Sol"); |
179 | 220 | this.sun.attr("r", 17).style("fill", "yellow"); |
... | ... | @@ -222,6 +263,8 @@ |
222 | 263 | this.yAxis.scale(this.yScale); |
223 | 264 | this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')').call(this.xAxis); |
224 | 265 | this.svg.select('.y.axis').call(this.yAxis); |
266 | + this.xAxisTitle.attr("x", width / 2); | |
267 | + this.xAxisTitle.attr("y", 30); | |
225 | 268 | return this; |
226 | 269 | }; |
227 | 270 | Orbits.prototype.resizeOrbiter = function(slug, config){ |
... | ... | @@ -244,6 +287,34 @@ |
244 | 287 | el['orbiter'].attr('y', this.yScale(data[data.length - 1].y) - 16); |
245 | 288 | return this; |
246 | 289 | }; |
290 | + Orbits.prototype.repositionOrbiter = function(slug, datum){ | |
291 | + var data, el; | |
292 | + data = this.data; | |
293 | + datum == null && (datum = data[data.length - 1]); | |
294 | + el = this.orbitersElements[slug]; | |
295 | + el['orbiter'].attr('x', this.xScale(datum.x) - 16); | |
296 | + el['orbiter'].attr('y', this.yScale(datum.y) - 16); | |
297 | + return this; | |
298 | + }; | |
299 | + Orbits.prototype.bisectDate = d3.bisector(function(d){ | |
300 | + return d.t; | |
301 | + }).left; | |
302 | + Orbits.prototype.moveToDate = function(t){ | |
303 | + var slug, ref$, el, data, i, d0, d1, d, results$ = []; | |
304 | + for (slug in ref$ = this.orbitersElements) { | |
305 | + el = ref$[slug]; | |
306 | + data = this.data; | |
307 | + i = this.bisectDate(data, t, 1); | |
308 | + d0 = data[i - 1]; | |
309 | + d1 = data[i]; | |
310 | + if (!(d1 && d0)) { | |
311 | + continue; | |
312 | + } | |
313 | + d = t - d0.t > d1.t - t ? d1 : d0; | |
314 | + results$.push(this.repositionOrbiter(slug, d)); | |
315 | + } | |
316 | + return results$; | |
317 | + }; | |
247 | 318 | return Orbits; |
248 | 319 | }()); |
249 | 320 | function bind$(obj, key, target){ | ... | ... |
web/static/js/swapp.ls
... | ... | @@ -3,6 +3,38 @@ |
3 | 3 | |
4 | 4 | const GOLDEN_RATIO = 2 / (1 + Math.sqrt(5)) |
5 | 5 | |
6 | +############################################################################### | |
7 | + | |
8 | +export class SpaceWeather | |
9 | + | |
10 | + (configuration) -> | |
11 | + console.info "Creating Space Weather app...", configuration | |
12 | + | |
13 | + # fixme | |
14 | + | |
15 | + | |
16 | + | |
17 | + | |
18 | +class Source | |
19 | + (@slug) -> | |
20 | + @time_series = {} | |
21 | + | |
22 | + addTimeSeries: (ts) -> | |
23 | + @time_series[ts.slug] = ts | |
24 | + | |
25 | + show: -> | |
26 | + for slug, ts of @time_series | |
27 | + $(ts.svg).show() | |
28 | + hide: -> | |
29 | + for slug, ts of @time_series | |
30 | + $(ts.svg).hide() | |
31 | + | |
32 | + | |
33 | + | |
34 | + | |
35 | +############################################################################### | |
36 | +############################################################################### | |
37 | + | |
6 | 38 | export class TimeSeries |
7 | 39 | # Time in x-axis |
8 | 40 | # Data in y-axis |
... | ... | @@ -10,11 +42,11 @@ export class TimeSeries |
10 | 42 | (@slug, @title, @data, @container, @options = {}) -> |
11 | 43 | # title : string |
12 | 44 | # data : list of {x: <datetime>, y: <float>} |
13 | - console.log "Create time series '#{@title}'" | |
45 | + console.info "Creating time series '#{@title}'..." | |
14 | 46 | @init() |
15 | 47 | |
16 | 48 | init: -> |
17 | - console.log "Initialize time series '#{@title}'", @data, @options | |
49 | + console.info "Initializing time series '#{@title}'...", @data, @options | |
18 | 50 | |
19 | 51 | @margin = { |
20 | 52 | top: 30, |
... | ... | @@ -195,8 +227,13 @@ export class TimeSeries |
195 | 227 | |
196 | 228 | this |
197 | 229 | |
230 | + | |
231 | +############################################################################### | |
232 | +############################################################################### | |
233 | + | |
198 | 234 | export class Orbits |
199 | - # View of the solar system from above | |
235 | + # View of the solar system from above, with orbits segments for selected time | |
236 | + # interval, from real data. | |
200 | 237 | |
201 | 238 | (@orbiters, @data, @container, @options = {}) -> |
202 | 239 | console.log "Create orbits" |
... | ... | @@ -208,7 +245,7 @@ export class Orbits |
208 | 245 | @margin = { |
209 | 246 | top: 30, |
210 | 247 | right: 20, |
211 | - bottom: 30, | |
248 | + bottom: 40, | |
212 | 249 | left: 60 |
213 | 250 | } |
214 | 251 | |
... | ... | @@ -227,8 +264,17 @@ export class Orbits |
227 | 264 | @plotWrapper = @svg.append('g') |
228 | 265 | @plotWrapper.attr('transform', 'translate(' + @margin.left + ',' + @margin.top + ')') |
229 | 266 | |
230 | - @plotWrapper.append('g').classed('x axis', true) | |
231 | - @plotWrapper.append('g').classed('y axis', true) | |
267 | + @xAxisLine = @plotWrapper.append('g').classed('x axis', true) | |
268 | + @yAxisLine = @plotWrapper.append('g').classed('y axis', true) | |
269 | + | |
270 | + @xAxisTitle = @xAxisLine.append('text').attr('fill', '#000') | |
271 | + @xAxisTitle.style("text-anchor", "middle") | |
272 | + @xAxisTitle.append('tspan').text('X') | |
273 | + # No : https://bugzilla.mozilla.org/show_bug.cgi?id=308338 | |
274 | + # @xAxisTitle.append('tspan').attr('baseline-shift', 'sub').text('HEE') | |
275 | + # Also, don't use em as dy units | |
276 | + @xAxisTitle.append('tspan').attr('dy', '3px').text('HEE').attr('font-size', '0.618em') | |
277 | + @xAxisTitle.append('tspan').attr('dy', '-3px').text(' (AU)') | |
232 | 278 | |
233 | 279 | @sun = @plotWrapper.append("svg:circle") |
234 | 280 | @sun.append('svg:title').text("Sol") |
... | ... | @@ -293,6 +339,9 @@ export class Orbits |
293 | 339 | @svg.select('.y.axis') |
294 | 340 | .call(@yAxis) |
295 | 341 | |
342 | + @xAxisTitle.attr("x", width / 2) | |
343 | + @xAxisTitle.attr("y", 30) | |
344 | + | |
296 | 345 | this |
297 | 346 | |
298 | 347 | resizeOrbiter: (slug, config) -> |
... | ... | @@ -316,10 +365,32 @@ export class Orbits |
316 | 365 | .attr('transform', 'rotate(66,'+(cx+c)+', '+cy+')') |
317 | 366 | @yScale.range([height, 0]) |
318 | 367 | |
319 | - data = @data | |
368 | + data = @data # todo: multiple orbiters | |
320 | 369 | |
321 | 370 | el['orbiter'].attr('x', @xScale(data[data.length - 1].x) - 16) |
322 | 371 | el['orbiter'].attr('y', @yScale(data[data.length - 1].y) - 16) |
323 | 372 | |
324 | 373 | this |
325 | 374 | |
375 | + repositionOrbiter: (slug, datum) -> | |
376 | + data = @data # todo | |
377 | + datum ?= data[data.length - 1] | |
378 | + el = @orbitersElements[slug] | |
379 | + el['orbiter'].attr('x', @xScale(datum.x) - 16) | |
380 | + el['orbiter'].attr('y', @yScale(datum.y) - 16) | |
381 | + | |
382 | + this | |
383 | + | |
384 | + bisectDate: d3.bisector((d) -> d.t).left | |
385 | + | |
386 | + moveToDate: (t) -> | |
387 | + for slug, el of @orbitersElements | |
388 | + data = @data # todo: multiple orbiters | |
389 | + i = @bisectDate(data, t, 1) | |
390 | + d0 = data[i - 1] | |
391 | + d1 = data[i] | |
392 | + continue unless d1 and d0 | |
393 | + d = if t - d0.t > d1.t - t then d1 else d0 | |
394 | + @repositionOrbiter(slug, d) # fixme | |
395 | + | |
396 | + | ... | ... |
web/view/home.html.jinja2
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | |
9 | 9 | |
10 | 10 | <div class="mdl-layout__drawer"> |
11 | - <span class="mdl-layout-title">Orbiters</span> | |
11 | + <span class="mdl-layout-title">Planets</span> | |
12 | 12 | |
13 | 13 | <section id="orbiters_filters"> |
14 | 14 | <img title="Jupiter" src="{{ static('img/planet/jupiter_128.png') }}" width="64px" height="64px" alt="Jupiter"> |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | </div> |
46 | 46 | </div> |
47 | 47 | |
48 | - <div class="loader"><div class="hole"></div></div> | |
48 | +{# <div class="loader"><div class="hole"></div></div>#} | |
49 | 49 | </main> |
50 | 50 | </div> |
51 | 51 | |
... | ... | @@ -131,13 +131,19 @@ |
131 | 131 | <script type="application/javascript" src="{{ static('js/swapp.js') }}"></script> |
132 | 132 | <script type="application/javascript"> |
133 | 133 | |
134 | -// Sorry, no ES6. Feel free to refactor. | |
135 | - | |
136 | -var orbiters = { | |
137 | - jupiter: { | |
138 | - name: 'Jupiter', | |
139 | - orbit: { a: 5.45516759, b: 4.95155843 }, | |
140 | - img: '{{ static('img/planet/jupiter_128.png') }}' | |
134 | +var configuration = { | |
135 | + time_series_container: '#time_series', | |
136 | + orbits_container: '#orbits', | |
137 | + sources : { | |
138 | + jupiter: { | |
139 | + slug: 'jupiter', | |
140 | + name: 'Jupiter', | |
141 | + active: true, | |
142 | + minDate: '1990-01-01T01:30:00', | |
143 | + maxDate: '2017-02-19T00:00:00', | |
144 | + orbit: { a: 5.45516759, b: 4.95155843 }, | |
145 | + img: '{{ static('img/planet/jupiter_128.png') }}' | |
146 | + } | |
141 | 147 | } |
142 | 148 | }; |
143 | 149 | |
... | ... | @@ -145,6 +151,8 @@ jQuery().ready(function($){ |
145 | 151 | var timeSeries = []; |
146 | 152 | var orbits; |
147 | 153 | |
154 | + var sw = new SpaceWeather(configuration); | |
155 | + | |
148 | 156 | d3.csv('{{ url_for('get_csv') }}', function(csv){ |
149 | 157 | var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); |
150 | 158 | var data = {'pdyn': [], 'magn': [], 'vlen': []}; |
... | ... | @@ -188,7 +196,7 @@ jQuery().ready(function($){ |
188 | 196 | data.push({t: timeFormat(d['time']), x: parseFloat(d['x_hci']), y: parseFloat(d['y_hci'])}); |
189 | 197 | }); |
190 | 198 | |
191 | - orbits = new Orbits(orbiters, data, '#orbits'); | |
199 | + orbits = new Orbits(configuration.sources, data, '#orbits'); | |
192 | 200 | }); |
193 | 201 | |
194 | 202 | var toggleTimeSeries = function(slug) { | ... | ... |