Commit cad44b6d55940ae698ee8784942558100af12b88
1 parent
6491a1f1
Exists in
master
and in
2 other branches
Finish adding the SAMP button (finally!)
Showing
3 changed files
with
165 additions
and
17 deletions
Show diff stats
web/static/js/swapp.js
@@ -30,7 +30,7 @@ | @@ -30,7 +30,7 @@ | ||
30 | } | 30 | } |
31 | configs = res$; | 31 | configs = res$; |
32 | configs.forEach(function(target_config){ | 32 | configs.forEach(function(target_config){ |
33 | - return this$.targets[target_config.slug] = new Target(target_config.slug, target_config.name, target_config); | 33 | + return this$.addTarget(new Target(target_config.slug, target_config.name, target_config)); |
34 | }); | 34 | }); |
35 | this.parameters = {}; | 35 | this.parameters = {}; |
36 | this.configuration['parameters'].forEach(function(p){ | 36 | this.configuration['parameters'].forEach(function(p){ |
@@ -42,7 +42,7 @@ | @@ -42,7 +42,7 @@ | ||
42 | SpaceWeather.prototype.init = function(){ | 42 | SpaceWeather.prototype.init = function(){ |
43 | "This is called by the inline bootstrap javascript code.\nThis ain't in the constructor because it might return a Promise later on.\n(for the loader, for example)"; | 43 | "This is called by the inline bootstrap javascript code.\nThis ain't in the constructor because it might return a Promise later on.\n(for the loader, for example)"; |
44 | var started_at, stopped_at, this$ = this; | 44 | var started_at, stopped_at, this$ = this; |
45 | - started_at = moment().subtract(6, 'month').hours(0).minutes(0).seconds(0); | 45 | + started_at = moment().subtract(1, 'year').hours(0).minutes(0).seconds(0); |
46 | stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0); | 46 | stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0); |
47 | this.setStartAndStop(started_at, stopped_at); | 47 | this.setStartAndStop(started_at, stopped_at); |
48 | this.loadAndCreatePlots(started_at, stopped_at); | 48 | this.loadAndCreatePlots(started_at, stopped_at); |
@@ -76,10 +76,61 @@ | @@ -76,10 +76,61 @@ | ||
76 | url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)); | 76 | url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)); |
77 | return url; | 77 | return url; |
78 | }; | 78 | }; |
79 | + SpaceWeather.prototype.buildSampUrl = function(){ | ||
80 | + var ref$, started_at, stopped_at, targets, t, parameters, p, url; | ||
81 | + ref$ = this.getDomain(), started_at = ref$[0], stopped_at = ref$[1]; | ||
82 | + targets = (function(){ | ||
83 | + var results$ = []; | ||
84 | + for (t in this.targets) { | ||
85 | + if (this.targets[t].active) { | ||
86 | + results$.push(t); | ||
87 | + } | ||
88 | + } | ||
89 | + return results$; | ||
90 | + }.call(this)).sort().join('-'); | ||
91 | + parameters = (function(){ | ||
92 | + var results$ = []; | ||
93 | + for (p in this.parameters) { | ||
94 | + if (this.parameters[p].active) { | ||
95 | + results$.push(p); | ||
96 | + } | ||
97 | + } | ||
98 | + return results$; | ||
99 | + }.call(this)).sort().join('-'); | ||
100 | + url = this.configuration['api']['samp']; | ||
101 | + url = url.replace('<targets>', targets); | ||
102 | + url = url.replace('<params>', parameters); | ||
103 | + url = url.replace('<started_at>', started_at.format(API_TIME_FORMAT)); | ||
104 | + url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)); | ||
105 | + return url; | ||
106 | + }; | ||
107 | + SpaceWeather.prototype.buildSampName = function(){ | ||
108 | + var ref$, started_at, stopped_at, targets, t; | ||
109 | + ref$ = this.getDomain(), started_at = ref$[0], stopped_at = ref$[1]; | ||
110 | + targets = (function(){ | ||
111 | + var i$, ref$, len$, results$ = []; | ||
112 | + for (i$ = 0, len$ = (ref$ = this.getEnabledTargets()).length; i$ < len$; ++i$) { | ||
113 | + t = ref$[i$]; | ||
114 | + results$.push(t.name); | ||
115 | + } | ||
116 | + return results$; | ||
117 | + }.call(this)).sort().join(', '); | ||
118 | + return "Heliopropa for " + targets + " from " + started_at.format(API_TIME_FORMAT) + " to " + stopped_at.format(API_TIME_FORMAT) + "."; | ||
119 | + }; | ||
79 | SpaceWeather.prototype.addTarget = function(target){ | 120 | SpaceWeather.prototype.addTarget = function(target){ |
80 | this.targets[target.slug] = target; | 121 | this.targets[target.slug] = target; |
81 | return this; | 122 | return this; |
82 | }; | 123 | }; |
124 | + SpaceWeather.prototype.getEnabledTargets = function(){ | ||
125 | + var slug, ref$, target, results$ = []; | ||
126 | + for (slug in ref$ = this.targets) { | ||
127 | + target = ref$[slug]; | ||
128 | + if (target.active) { | ||
129 | + results$.push(target); | ||
130 | + } | ||
131 | + } | ||
132 | + return results$; | ||
133 | + }; | ||
83 | SpaceWeather.prototype.enableTarget = function(target_slug){ | 134 | SpaceWeather.prototype.enableTarget = function(target_slug){ |
84 | var this$ = this; | 135 | var this$ = this; |
85 | this.time_series.forEach(function(ts){ | 136 | this.time_series.forEach(function(ts){ |
@@ -270,6 +321,17 @@ | @@ -270,6 +321,17 @@ | ||
270 | }); | 321 | }); |
271 | return this.time_series; | 322 | return this.time_series; |
272 | }; | 323 | }; |
324 | + SpaceWeather.prototype.getEnabledParameters = function(){ | ||
325 | + var i$, ref$, len$, p, slug, results$ = []; | ||
326 | + for (i$ = 0, len$ = (ref$ = this.parameters).length; i$ < len$; ++i$) { | ||
327 | + p = i$; | ||
328 | + slug = ref$[i$]; | ||
329 | + if (p.active) { | ||
330 | + results$.push(p); | ||
331 | + } | ||
332 | + } | ||
333 | + return results$; | ||
334 | + }; | ||
273 | SpaceWeather.prototype.enableParameter = function(parameter_slug){ | 335 | SpaceWeather.prototype.enableParameter = function(parameter_slug){ |
274 | var this$ = this; | 336 | var this$ = this; |
275 | if (!(parameter_slug in this.parameters)) { | 337 | if (!(parameter_slug in this.parameters)) { |
web/static/js/swapp.ls
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # templates, such as `home.html.jinja2`. | 11 | # templates, such as `home.html.jinja2`. |
12 | 12 | ||
13 | # Note: We use Promises and ES6 whenever relevant. | 13 | # Note: We use Promises and ES6 whenever relevant. |
14 | -# You also will need d3js v4 documentation : https://d3js.org/ | 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 | 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, | 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. | 17 | # and d3's brush is stopping propagation, as it should by default. |
@@ -56,13 +56,13 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -56,13 +56,13 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
56 | """ # HelioPropa by CDPP (mushed 'cause we need to escape backslashes) | 56 | """ # HelioPropa by CDPP (mushed 'cause we need to escape backslashes) |
57 | @targets = {} | 57 | @targets = {} |
58 | configs = [@configuration.targets[k] for k of @configuration.targets] | 58 | configs = [@configuration.targets[k] for k of @configuration.targets] |
59 | - configs.forEach((target_config) ~> | ||
60 | - @targets[target_config.slug] = new Target(target_config.slug, target_config.name, target_config) | ||
61 | - ) | 59 | + configs.forEach (target_config) ~> |
60 | + @addTarget(new Target(target_config.slug, target_config.name, target_config)) | ||
61 | + | ||
62 | @parameters = {} | 62 | @parameters = {} |
63 | - @configuration['parameters'].forEach((p) ~> | ||
64 | - @parameters[p['id']] = p | ||
65 | - ) | 63 | + @configuration['parameters'].forEach (p) ~> |
64 | + @parameters[p['id']] = p | ||
65 | + | ||
66 | @orbiter = null # our Orbiter defined below | 66 | @orbiter = null # our Orbiter defined below |
67 | @time_series = [] # a List of TimeSeries objects | 67 | @time_series = [] # a List of TimeSeries objects |
68 | 68 | ||
@@ -74,7 +74,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -74,7 +74,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
74 | """ | 74 | """ |
75 | # Default time interval is from two weeks ago to one week ahead. | 75 | # Default time interval is from two weeks ago to one week ahead. |
76 | # We set the h/m/s to zero to benefit from a daily cache. | 76 | # We set the h/m/s to zero to benefit from a daily cache. |
77 | - started_at = moment().subtract(6, 'month').hours(0).minutes(0).seconds(0) | 77 | + started_at = moment().subtract(1, 'year').hours(0).minutes(0).seconds(0) |
78 | stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0) | 78 | stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0) |
79 | @setStartAndStop(started_at, stopped_at) | 79 | @setStartAndStop(started_at, stopped_at) |
80 | @loadAndCreatePlots(started_at, stopped_at) | 80 | @loadAndCreatePlots(started_at, stopped_at) |
@@ -97,6 +97,22 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -97,6 +97,22 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
97 | url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)) | 97 | url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)) |
98 | url | 98 | url |
99 | 99 | ||
100 | + buildSampUrl: -> | ||
101 | + [started_at, stopped_at] = @getDomain() | ||
102 | + targets = [t for t of @targets when @targets[t].active].sort().join('-') | ||
103 | + parameters = [p for p of @parameters when @parameters[p].active].sort().join('-') | ||
104 | + url = @configuration['api']['samp'] | ||
105 | + url = url.replace('<targets>', targets) | ||
106 | + url = url.replace('<params>', parameters) | ||
107 | + url = url.replace('<started_at>', started_at.format(API_TIME_FORMAT)) | ||
108 | + url = url.replace('<stopped_at>', stopped_at.format(API_TIME_FORMAT)) | ||
109 | + url | ||
110 | + | ||
111 | + buildSampName: -> | ||
112 | + [started_at, stopped_at] = @getDomain() | ||
113 | + targets = [t.name for t in @getEnabledTargets()].sort().join(', ') | ||
114 | + "Heliopropa for #{targets} from #{started_at.format(API_TIME_FORMAT)} to #{stopped_at.format(API_TIME_FORMAT)}." | ||
115 | + | ||
100 | addTarget: (target) -> | 116 | addTarget: (target) -> |
101 | @targets[target.slug] = target | 117 | @targets[target.slug] = target |
102 | this | 118 | this |
@@ -106,6 +122,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -106,6 +122,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
106 | # enableTarget(slug) | 122 | # enableTarget(slug) |
107 | # this | 123 | # this |
108 | 124 | ||
125 | + getEnabledTargets: -> | ||
126 | + [target for slug, target of @targets when target.active] | ||
127 | + | ||
109 | enableTarget: (target_slug) -> | 128 | enableTarget: (target_slug) -> |
110 | @time_series.forEach((ts) ~> ts.show() if ts.target.slug == target_slug && @parameters[ts.parameter].active) | 129 | @time_series.forEach((ts) ~> ts.show() if ts.target.slug == target_slug && @parameters[ts.parameter].active) |
111 | @targets[target_slug].active = true | 130 | @targets[target_slug].active = true |
@@ -237,6 +256,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -237,6 +256,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
237 | ) | 256 | ) |
238 | @time_series | 257 | @time_series |
239 | 258 | ||
259 | + getEnabledParameters: -> | ||
260 | + [p for slug, p in @parameters when p.active] | ||
261 | + | ||
240 | enableParameter: (parameter_slug) -> | 262 | enableParameter: (parameter_slug) -> |
241 | if parameter_slug not of @parameters then console.error("Unknown parameter #{parameter_slug}.") | 263 | if parameter_slug not of @parameters then console.error("Unknown parameter #{parameter_slug}.") |
242 | @parameters[parameter_slug].active = true | 264 | @parameters[parameter_slug].active = true |
web/view/home.html.jinja2
@@ -118,10 +118,16 @@ | @@ -118,10 +118,16 @@ | ||
118 | <div class="mdl-grid"> | 118 | <div class="mdl-grid"> |
119 | <div class="mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet mdl-cell--4-col-phone"> | 119 | <div class="mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet mdl-cell--4-col-phone"> |
120 | <section id="orbits"></section> | 120 | <section id="orbits"></section> |
121 | - <button id="download" class="mdl-button mdl-button--raised mdl-button--primary" | ||
122 | - title="Download the CSV raw data for each target in a tarball."> | ||
123 | - Download | ||
124 | - </button> | 121 | + <div class="plots-actions plots-buttons"> |
122 | + <button id="download" class="mdl-button mdl-button--raised mdl-button--primary" | ||
123 | + title="Download the CSV raw data for each target in a tarball."> | ||
124 | + Download | ||
125 | + </button> | ||
126 | + <button id="samp" class="samp mdl-button mdl-button--raised mdl-button--primary mdl-button--disabled" | ||
127 | + title="Send the data to a connected SAMP hub."> | ||
128 | + SAMP | ||
129 | + </button> | ||
130 | + </div> | ||
125 | </div> | 131 | </div> |
126 | <div class="mdl-cell mdl-cell--8-col mdl-cell--8-col-tablet mdl-cell--4-col-phone"> | 132 | <div class="mdl-cell mdl-cell--8-col mdl-cell--8-col-tablet mdl-cell--4-col-phone"> |
127 | <section id="time_series"> | 133 | <section id="time_series"> |
@@ -234,10 +240,13 @@ | @@ -234,10 +240,13 @@ | ||
234 | animation-delay: .8s; | 240 | animation-delay: .8s; |
235 | } | 241 | } |
236 | 242 | ||
237 | - #download { | ||
238 | - display: block; | 243 | + .plots-buttons { |
244 | + text-align: center; | ||
239 | margin: 3em auto; | 245 | margin: 3em auto; |
240 | } | 246 | } |
247 | + .plots-buttons button { | ||
248 | + margin: auto 1em; | ||
249 | + } | ||
241 | 250 | ||
242 | #time_series svg { | 251 | #time_series svg { |
243 | cursor: crosshair; | 252 | cursor: crosshair; |
@@ -526,7 +535,8 @@ var configuration = { | @@ -526,7 +535,8 @@ var configuration = { | ||
526 | orbits_container: '#orbits', | 535 | orbits_container: '#orbits', |
527 | api : { | 536 | api : { |
528 | 'data_for_interval': "{{ request.url_root }}<target>_<started_at>_<stopped_at>.csv", | 537 | 'data_for_interval': "{{ request.url_root }}<target>_<started_at>_<stopped_at>.csv", |
529 | - 'download': "{{ request.url_root }}<targets>_<started_at>_<stopped_at>.tar.gz" | 538 | + 'download': "{{ request.url_root }}<targets>_<started_at>_<stopped_at>.tar.gz", |
539 | + 'samp': "{{ request.url_root }}<targets>_<params>_<started_at>_<stopped_at>.nc" | ||
530 | }, | 540 | }, |
531 | sun: { | 541 | sun: { |
532 | img: '{{ static('img/sun_128.png') }}' | 542 | img: '{{ static('img/sun_128.png') }}' |
@@ -655,4 +665,58 @@ jQuery().ready(function($){ | @@ -655,4 +665,58 @@ jQuery().ready(function($){ | ||
655 | 665 | ||
656 | }); | 666 | }); |
657 | </script> | 667 | </script> |
668 | + | ||
669 | +{#### SAMP ###################################################################} | ||
670 | +<script type="text/javascript"> | ||
671 | + jQuery().ready(function ($) { | ||
672 | + // Flag to know when a hub is connected or not | ||
673 | + var isConnected = false; | ||
674 | + | ||
675 | + // Show SAMP button(s) depending on whether the hub is available or not. | ||
676 | + var onHubAvailability = function (isHubRunning) { | ||
677 | + $(".samp").each(function (index, element) { | ||
678 | + if (isHubRunning) { | ||
679 | + isConnected = true; | ||
680 | + $(element).removeClass('disabled mdl-button--disabled'); | ||
681 | + } else { | ||
682 | + isConnected = false; | ||
683 | + $(element).addClass('disabled mdl-button--disabled'); | ||
684 | + } | ||
685 | + }); | ||
686 | + }; | ||
687 | + | ||
688 | + // Update the document about the presence of any SAMP hub every 10 sec. | ||
689 | + var connector = new samp.Connector("Sender"); | ||
690 | + connector.onHubAvailability(onHubAvailability, 10000); | ||
691 | + window.onunload = function () { | ||
692 | + connector.unregister(); | ||
693 | + }; | ||
694 | + | ||
695 | + // Clicking on a SAMP button sends the CDF file to the connected hub. | ||
696 | + $("#samp").click(function (event) { | ||
697 | + event.stopPropagation(); | ||
698 | + if ($(this).hasClass('disabled')) { return; } | ||
699 | + // pitfall : connector.connection is ALWAYS undefined here | ||
700 | + if ( ! isConnected) { // so we use a bool flag instead | ||
701 | + alert("We do not detect any connected SAMP hub.\n" + | ||
702 | + "Wait some more, or try refreshing this page?"); | ||
703 | + return; | ||
704 | + } | ||
705 | + var name = sw.buildSampName(); | ||
706 | + var url = sw.buildSampUrl(); | ||
707 | + console.log(name, url); | ||
708 | + connector.runWithConnection(function (connection) { | ||
709 | + var msg = new samp.Message("table.load.cdf", { | ||
710 | + "name": name, | ||
711 | + "url": url // absolute URL required | ||
712 | + }); | ||
713 | + connection.notifyAll([msg]); | ||
714 | + }, function (error) { | ||
715 | + var msg = 'Error: ' + error; | ||
716 | + console.error(msg); | ||
717 | + alert(msg); // let's yell at the user as well | ||
718 | + }); | ||
719 | + }); | ||
720 | + }); | ||
721 | +</script> | ||
658 | {% endblock %} | 722 | {% endblock %} |