Blame view

web/static/js/swapp.js 28.2 KB
438929a4   Goutte   Rewrite the orbit...
1
2
// Generated by LiveScript 1.5.0
(function(){
b60e7acd   Goutte   Rename "source" i...
3
  var GOLDEN_RATIO, Target, SpaceWeather, TimeSeries, Orbits, out$ = typeof exports != 'undefined' && exports || this;
438929a4   Goutte   Rewrite the orbit...
4
  GOLDEN_RATIO = 2 / (1 + Math.sqrt(5));
b60e7acd   Goutte   Rename "source" i...
5
6
7
8
9
10
11
12
13
14
15
  Target = (function(){
    Target.displayName = 'Target';
    var prototype = Target.prototype, constructor = Target;
    function Target(slug, name, config){
      this.slug = slug;
      this.name = name;
      this.config = config;
      this.active = true;
    }
    return Target;
  }());
ae0aa7d2   Goutte   Add an x axis lab...
16
  out$.SpaceWeather = SpaceWeather = (function(){
6bb225d6   Goutte   Link the time ser...
17
    "The main app, instanciated from an inline script.\nIt defaults to an interval starting a year ago, and ending in seven days.\n(both at midnight)";
ae0aa7d2   Goutte   Add an x axis lab...
18
    SpaceWeather.displayName = 'SpaceWeather';
7d6dee0f   Goutte   Continue refacto ...
19
    var timeSeries, prototype = SpaceWeather.prototype, constructor = SpaceWeather;
ae0aa7d2   Goutte   Add an x axis lab...
20
    function SpaceWeather(configuration){
fe3132dd   Goutte   Refactor even more.
21
      var configs, res$, k, this$ = this;
f75faf5f   Goutte   WIP
22
      this.configuration = configuration;
2038c9fb   Goutte   Add a zoom reset ...
23
      console.info("  _   _      _ _       ____\n | | | | ___| (_) ___ |  _ \\ _ __ ___  _ __   __ _\n | |_| |/ _ \\ | |/ _ \\| |_) | '__/ _ \\| '_ \\ / _` |\n |  _  |  __/ | | (_) |  __/| | | (_) | |_) | (_| |\n |_| |_|\\___|_|_|\\___/|_|_  |_|_ \\___/| .__/ \\__,_|\n | |__  _   _   / ___|  _ \\|  _ \\|  _ \\_|\n | '_ \\| | | | | |   | | | | |_) | |_) |\n | |_) | |_| | | |___| |_| |  __/|  __/\n |_.__/ \\__, |  \\____|____/|_|   |_|\n        |___/\n\nThe full source of this website is available at :\nhttps://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE");
b60e7acd   Goutte   Rename "source" i...
24
      this.targets = {};
fe3132dd   Goutte   Refactor even more.
25
      res$ = [];
b60e7acd   Goutte   Rename "source" i...
26
27
      for (k in this.configuration.targets) {
        res$.push(this.configuration.targets[k]);
fe3132dd   Goutte   Refactor even more.
28
29
      }
      configs = res$;
b60e7acd   Goutte   Rename "source" i...
30
31
      configs.forEach(function(target_config){
        return this$.targets[target_config.slug] = new Target(target_config.slug, target_config.name, target_config);
fe3132dd   Goutte   Refactor even more.
32
      });
b7fe650c   Goutte   Misc bundle of ol...
33
34
35
36
      this.parameters = {};
      this.configuration['parameters'].forEach(function(p){
        return this$.parameters[p['id']] = p;
      });
ae0aa7d2   Goutte   Add an x axis lab...
37
    }
b60e7acd   Goutte   Rename "source" i...
38
39
40
41
42
43
44
45
46
47
48
    SpaceWeather.prototype.init = function(){
      "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)";
      var active_targets, res$, k, started_at, stopped_at, this$ = this;
      res$ = [];
      for (k in this.targets) {
        if (this.targets[k].config.active) {
          res$.push(this.targets[k]);
        }
      }
      active_targets = res$;
      this.orbits = new Orbits(this.configuration.orbits_container, this.configuration);
8cb213b9   Goutte   Clean up, and pre...
49
50
51
52
      this.started_at = moment().subtract(1, 'years').hours(0).minutes(0).seconds(0);
      this.stopped_at = moment().add(7, 'days').hours(0).minutes(0).seconds(0);
      started_at = this.started_at.format("YYYY-MM-DDTHH:mm:ss");
      stopped_at = this.stopped_at.format("YYYY-MM-DDTHH:mm:ss");
ebe77ce4   Goutte   Clean up.
53
      console.info("Setting time interval from " + started_at + " to " + stopped_at + "…");
b60e7acd   Goutte   Rename "source" i...
54
      active_targets.forEach(function(target){
93ee5563   Goutte   Add a loading ani...
55
        var targetButton;
c3008fb2   Goutte   Clean up and refa...
56
        console.info("Loading CSV data of " + target.name + "…");
93ee5563   Goutte   Add a loading ani...
57
58
        targetButton = $(".orbiters_filters .target." + target.slug);
        targetButton.addClass('loading');
b60e7acd   Goutte   Rename "source" i...
59
        return this$.loadData(target.slug, started_at, stopped_at).then(function(data){
c3008fb2   Goutte   Clean up and refa...
60
          console.info("Loaded CSV data of " + target.name + ".");
b60e7acd   Goutte   Rename "source" i...
61
          this$.createTimeSeries(target, data);
93ee5563   Goutte   Add a loading ani...
62
          this$.orbits.initOrbiter(target.slug, target.config, data['hci']);
9c0c4509   Goutte   Add a loader to t...
63
64
          targetButton.removeClass('loading');
          return this$.hideLoader();
b60e7acd   Goutte   Rename "source" i...
65
66
67
68
69
70
71
72
73
        }, function(error){
          return console.error('Failed to load CSV data.', error);
        });
      });
      return window.addEventListener('resize', function(){
        return this$.resize();
      });
    };
    SpaceWeather.prototype.buildDataUrlForTarget = function(target_slug, started_at, stopped_at){
f75faf5f   Goutte   WIP
74
75
      var url;
      url = this.configuration['api']['data_for_interval'];
b60e7acd   Goutte   Rename "source" i...
76
      url = url.replace('<target>', target_slug);
a4a9ef03   Goutte   Cache generated C...
77
78
      url = url.replace('<started_at>', started_at);
      url = url.replace('<stopped_at>', stopped_at);
f75faf5f   Goutte   WIP
79
80
      return url;
    };
b60e7acd   Goutte   Rename "source" i...
81
82
    SpaceWeather.prototype.addTarget = function(target){
      this.targets[target.slug] = target;
f75faf5f   Goutte   WIP
83
84
      return this;
    };
6bb225d6   Goutte   Link the time ser...
85
    SpaceWeather.prototype.enableAllTargets = function(){
b60e7acd   Goutte   Rename "source" i...
86
87
88
89
      var slug, ref$, target;
      for (slug in ref$ = this.targets) {
        target = ref$[slug];
        showTarget(slug);
f75faf5f   Goutte   WIP
90
91
92
      }
      return this;
    };
6bb225d6   Goutte   Link the time ser...
93
    SpaceWeather.prototype.enableTarget = function(target_slug){
4cf497e0   Goutte   Make the targets ...
94
95
      var this$ = this;
      timeSeries.forEach(function(ts){
b60e7acd   Goutte   Rename "source" i...
96
        if (ts.target.slug === target_slug && this$.parameters[ts.parameter].active) {
6bb225d6   Goutte   Link the time ser...
97
          return ts.show();
4cf497e0   Goutte   Make the targets ...
98
99
        }
      });
b60e7acd   Goutte   Rename "source" i...
100
      this.targets[target_slug].active = true;
f75faf5f   Goutte   WIP
101
102
      return this;
    };
6bb225d6   Goutte   Link the time ser...
103
    SpaceWeather.prototype.disableTarget = function(target_slug){
4cf497e0   Goutte   Make the targets ...
104
      timeSeries.forEach(function(ts){
b60e7acd   Goutte   Rename "source" i...
105
        if (ts.target.slug === target_slug) {
6bb225d6   Goutte   Link the time ser...
106
          return ts.hide();
4cf497e0   Goutte   Make the targets ...
107
108
        }
      });
b60e7acd   Goutte   Rename "source" i...
109
      this.targets[target_slug].active = false;
f75faf5f   Goutte   WIP
110
111
      return this;
    };
fe3132dd   Goutte   Refactor even more.
112
    SpaceWeather.prototype.resize = function(){
a21f81d9   Goutte   Enable Venus and ...
113
      var ref$;
d49a163c   Goutte   Fix the resize an...
114
115
116
117
118
119
      if ((ref$ = this.orbits) != null) {
        ref$.resize();
      }
      return timeSeries.forEach(function(ts){
        return ts.resize();
      });
fe3132dd   Goutte   Refactor even more.
120
    };
9c0c4509   Goutte   Add a loader to t...
121
122
123
    SpaceWeather.prototype.hideLoader = function(){
      return $("#plots_loader").hide();
    };
b60e7acd   Goutte   Rename "source" i...
124
125
    SpaceWeather.prototype.loadData = function(target_slug, started_at, stopped_at){
      "Load the data as CSV for the specified target and interval,\nand return it in a Promise.";
f75faf5f   Goutte   WIP
126
127
128
129
      var sw, promise;
      sw = this;
      promise = new Promise(function(resolve, reject){
        var url;
b60e7acd   Goutte   Rename "source" i...
130
        url = sw.buildDataUrlForTarget(target_slug, started_at, stopped_at);
a4a9ef03   Goutte   Cache generated C...
131
        return d3.csv(url, function(csv){
f75faf5f   Goutte   WIP
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
          var timeFormat, data;
          timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z');
          data = {
            'hci': []
          };
          configuration['parameters'].forEach(function(parameter){
            return data[parameter['id']] = [];
          });
          csv.forEach(function(d){
            var dtime;
            dtime = timeFormat(d['time']);
            configuration['parameters'].forEach(function(parameter){
              var id;
              id = parameter['id'];
              return data[id].push({
                x: dtime,
                y: parseFloat(d[id])
              });
            });
            if (d['xhci'] && d['yhci']) {
              return data['hci'].push({
                t: dtime,
                x: parseFloat(d['xhci']),
                y: parseFloat(d['yhci'])
              });
            }
          });
          return resolve(data);
        });
      });
      return promise;
    };
7d6dee0f   Goutte   Continue refacto ...
164
    timeSeries = [];
b60e7acd   Goutte   Rename "source" i...
165
    SpaceWeather.prototype.createTimeSeries = function(target, data){
7d6dee0f   Goutte   Continue refacto ...
166
      var this$ = this;
4816cef4   Goutte   Refactor some more.
167
168
      this.configuration['parameters'].forEach(function(parameter){
        var container, id, title;
b7fe650c   Goutte   Misc bundle of ol...
169
        container = this$.configuration['time_series_container'];
4816cef4   Goutte   Refactor some more.
170
171
172
173
174
        id = parameter['id'];
        title = parameter['title'];
        if (!(id in data)) {
          console.error("No data for id '" + id + "'.", data);
        }
c3008fb2   Goutte   Clean up and refa...
175
        return timeSeries.push(new TimeSeries(id, title, target, data[id], this$.parameters[id].active, container));
4816cef4   Goutte   Refactor some more.
176
177
178
      });
      return timeSeries.forEach(function(ts){
        ts.options['onMouseOver'] = function(){
9c0c4509   Goutte   Add a loader to t...
179
          timeSeries.forEach(function(ts2){
4816cef4   Goutte   Refactor some more.
180
181
            return ts2.showCursor();
          });
9c0c4509   Goutte   Add a loader to t...
182
          return true;
4816cef4   Goutte   Refactor some more.
183
184
        };
        ts.options['onMouseOut'] = function(){
9c0c4509   Goutte   Add a loader to t...
185
          timeSeries.forEach(function(ts2){
4816cef4   Goutte   Refactor some more.
186
187
            return ts2.hideCursor();
          });
9c0c4509   Goutte   Add a loader to t...
188
          return true;
4816cef4   Goutte   Refactor some more.
189
        };
c3008fb2   Goutte   Clean up and refa...
190
        ts.options['onMouseMove'] = function(t){
fe3132dd   Goutte   Refactor even more.
191
          var ref$;
4816cef4   Goutte   Refactor some more.
192
193
194
          timeSeries.forEach(function(ts2){
            return ts2.moveCursor(t);
          });
9c0c4509   Goutte   Add a loader to t...
195
196
197
198
          if ((ref$ = this$.orbits) != null) {
            ref$.moveToDate(t);
          }
          return true;
4816cef4   Goutte   Refactor some more.
199
        };
c3008fb2   Goutte   Clean up and refa...
200
        ts.options['onBrushEnd'] = function(sta, sto){
9c0c4509   Goutte   Add a loader to t...
201
202
          this$.resizeDomain(sta, sto);
          return true;
c3008fb2   Goutte   Clean up and refa...
203
204
        };
        return ts.options['onDblClick'] = function(){
9c0c4509   Goutte   Add a loader to t...
205
206
207
208
209
210
          var ref$;
          this$.resetZoom();
          if ((ref$ = $("#zoom_controls_help")) != null) {
            ref$.remove();
          }
          return true;
c3008fb2   Goutte   Clean up and refa...
211
        };
4816cef4   Goutte   Refactor some more.
212
213
      });
    };
b7fe650c   Goutte   Misc bundle of ol...
214
    SpaceWeather.prototype.enableParameter = function(parameter_slug){
4cf497e0   Goutte   Make the targets ...
215
      var this$ = this;
b7fe650c   Goutte   Misc bundle of ol...
216
217
218
      if (!(parameter_slug in this.parameters)) {
        console.error("Unknown parameter " + parameter_slug + ".");
      }
b7fe650c   Goutte   Misc bundle of ol...
219
      this.parameters[parameter_slug].active = true;
4cf497e0   Goutte   Make the targets ...
220
      timeSeries.forEach(function(ts){
b60e7acd   Goutte   Rename "source" i...
221
        if (ts.parameter === parameter_slug && this$.targets[ts.target.slug].active) {
6bb225d6   Goutte   Link the time ser...
222
          return ts.show();
4cf497e0   Goutte   Make the targets ...
223
224
        }
      });
b7fe650c   Goutte   Misc bundle of ol...
225
226
227
228
229
230
      return this;
    };
    SpaceWeather.prototype.disableParameter = function(parameter_slug){
      if (!(parameter_slug in this.parameters)) {
        console.error("Unknown parameter " + parameter_slug + ".");
      }
b7fe650c   Goutte   Misc bundle of ol...
231
      this.parameters[parameter_slug].active = false;
4cf497e0   Goutte   Make the targets ...
232
233
      timeSeries.forEach(function(ts){
        if (ts.parameter === parameter_slug) {
6bb225d6   Goutte   Link the time ser...
234
          return ts.hide();
4cf497e0   Goutte   Make the targets ...
235
236
        }
      });
b7fe650c   Goutte   Misc bundle of ol...
237
238
      return this;
    };
a06a0a67   Goutte   Prepare the time ...
239
240
241
242
243
244
    SpaceWeather.prototype.getDomain = function(){
      if (this.current_started_at != null && this.current_stopped_at != null) {
        return [this.current_started_at, this.current_stopped_at];
      }
      return [this.started_at, this.stopped_at];
    };
8cb213b9   Goutte   Clean up, and pre...
245
246
247
248
249
250
251
252
    SpaceWeather.prototype.resizeDomain = function(started_at, stopped_at){
      var tmp;
      if (stopped_at < started_at) {
        tmp = started_at;
        started_at = stopped_at;
        stopped_at = started_at;
      }
      if (started_at === stopped_at) {
6bb225d6   Goutte   Link the time ser...
253
        console.warn("Please provide distinct start and stop dates.");
8cb213b9   Goutte   Clean up, and pre...
254
255
        return;
      }
a06a0a67   Goutte   Prepare the time ...
256
257
      this.current_started_at = started_at;
      this.current_stopped_at = stopped_at;
8cb213b9   Goutte   Clean up, and pre...
258
      if ((this.started_at <= started_at && started_at <= this.stopped_at) && (this.started_at <= stopped_at && stopped_at <= this.stopped_at)) {
c3008fb2   Goutte   Clean up and refa...
259
        console.info("Resizing the temporal domain from " + started_at + " to " + stopped_at + " without fetching new data…");
8cb213b9   Goutte   Clean up, and pre...
260
        timeSeries.forEach(function(ts){
6bb225d6   Goutte   Link the time ser...
261
262
263
264
265
266
267
268
          if (!ts.visible) {
            return ts.zoomIn(started_at, stopped_at);
          }
        });
        timeSeries.forEach(function(ts){
          if (ts.visible) {
            return ts.zoomIn(started_at, stopped_at);
          }
8cb213b9   Goutte   Clean up, and pre...
269
270
271
272
        });
        this.orbits.resizeDomain(started_at, stopped_at);
      }
    };
6bb225d6   Goutte   Link the time ser...
273
    SpaceWeather.prototype.resetZoom = function(){
667eeb24   Goutte   Resize the domain...
274
      timeSeries.forEach(function(ts){
6bb225d6   Goutte   Link the time ser...
275
276
        return ts.resetZoom();
      });
667eeb24   Goutte   Resize the domain...
277
      return this.orbits.resetZoom();
6bb225d6   Goutte   Link the time ser...
278
    };
ae0aa7d2   Goutte   Add an x axis lab...
279
280
    return SpaceWeather;
  }());
438929a4   Goutte   Rewrite the orbit...
281
282
  out$.TimeSeries = TimeSeries = (function(){
    TimeSeries.displayName = 'TimeSeries';
123313cb   Goutte   Clip the paths of...
283
    var RATIO, prototype = TimeSeries.prototype, constructor = TimeSeries;
c3008fb2   Goutte   Clean up and refa...
284
    function TimeSeries(parameter, title, target, data, visible, container, options){
4cf497e0   Goutte   Make the targets ...
285
      this.parameter = parameter;
438929a4   Goutte   Rewrite the orbit...
286
      this.title = title;
b60e7acd   Goutte   Rename "source" i...
287
      this.target = target;
6bb225d6   Goutte   Link the time ser...
288
      this.visible = visible;
438929a4   Goutte   Rewrite the orbit...
289
290
291
292
      this.container = container;
      this.options = options != null
        ? options
        : {};
08569a6b   Goutte   Add a zooming bru...
293
      this.onBrushEnd = bind$(this, 'onBrushEnd', prototype);
2038c9fb   Goutte   Add a zoom reset ...
294
      this.onDoubleClick = bind$(this, 'onDoubleClick', prototype);
541e2936   Goutte   Synchronize the t...
295
296
297
      this.onMouseOut = bind$(this, 'onMouseOut', prototype);
      this.onMouseOver = bind$(this, 'onMouseOver', prototype);
      this.onMouseMove = bind$(this, 'onMouseMove', prototype);
6bb225d6   Goutte   Link the time ser...
298
      this.setData(data);
438929a4   Goutte   Rewrite the orbit...
299
300
      this.init();
    }
2038c9fb   Goutte   Add a zoom reset ...
301
302
303
    TimeSeries.prototype.toString = function(){
      return this.title + " of " + this.target.name;
    };
6bb225d6   Goutte   Link the time ser...
304
305
306
307
308
309
310
311
312
    TimeSeries.prototype.setData = function(data){
      this.data = data;
      this.xDataExtent = d3.extent(this.data, function(d){
        return d.x;
      });
      return this.yDataExtent = d3.extent(this.data, function(d){
        return d.y;
      });
    };
438929a4   Goutte   Rewrite the orbit...
313
    TimeSeries.prototype.init = function(){
123313cb   Goutte   Clip the paths of...
314
      var clipId, dx, this$ = this;
c3008fb2   Goutte   Clean up and refa...
315
      console.info("Initializing plot of " + this + "…");
438929a4   Goutte   Rewrite the orbit...
316
317
318
319
      this.margin = {
        top: 30,
        right: 20,
        bottom: 30,
fe3132dd   Goutte   Refactor even more.
320
        left: 80
438929a4   Goutte   Rewrite the orbit...
321
      };
6bb225d6   Goutte   Link the time ser...
322
323
      this.xScale = d3.scaleTime().domain(this.xDataExtent);
      this.yScale = d3.scaleLinear().domain(this.yDataExtent);
08569a6b   Goutte   Add a zooming bru...
324
      this.xAxis = d3.axisBottom().ticks(7);
438929a4   Goutte   Rewrite the orbit...
325
326
327
328
329
330
331
      this.yAxis = d3.axisLeft().ticks(10);
      this.line = d3.line().x(function(d){
        return this$.xScale(d.x);
      }).y(function(d){
        return this$.yScale(d.y);
      });
      this.svg = d3.select(this.container).append('svg');
b60e7acd   Goutte   Rename "source" i...
332
      this.svg.attr("class", this.parameter + " " + this.target.slug);
438929a4   Goutte   Rewrite the orbit...
333
334
      this.plotWrapper = this.svg.append('g');
      this.plotWrapper.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
123313cb   Goutte   Clip the paths of...
335
336
337
338
339
      clipId = "ts-clip-" + this.parameter + "-" + this.target.slug;
      this.clip = this.svg.append("defs").append("svg:clipPath").attr("id", clipId).append("svg:rect").attr("x", 0).attr("y", 0);
      this.pathWrapper = this.plotWrapper.append('g');
      this.pathWrapper.attr("clip-path", "url(#" + clipId + ")");
      this.path = this.pathWrapper.append('path').datum(this.data).classed('line', true);
08569a6b   Goutte   Add a zooming bru...
340
341
      this.brush = this.plotWrapper.append("g").attr("class", "brush");
      this.mouseCanvas = this.plotWrapper.append("rect").style("fill", "none");
438929a4   Goutte   Rewrite the orbit...
342
343
344
      this.plotWrapper.append('g').classed('x axis', true);
      this.plotWrapper.append('g').classed('y axis', true);
      this.yAxisText = this.plotWrapper.append("text").attr("transform", "rotate(-90)").attr("dy", "1em").style("text-anchor", "middle").text(this.title);
b60e7acd   Goutte   Rename "source" i...
345
      this.yAxisTextTarget = this.plotWrapper.append("text").attr("transform", "rotate(-90)").attr("dy", "1em").style("text-anchor", "middle").style("font-style", "oblique").text(this.target.name);
81c9b2e8   Goutte   Add the values to...
346
347
      this.focus = this.plotWrapper.append('g').style("display", "none");
      this.cursorCircle = this.focus.append("circle").attr("class", "cursor-circle").attr("r", 3);
541e2936   Goutte   Synchronize the t...
348
349
350
351
352
      dx = 8;
      this.cursorValueShadow = this.focus.append("text").attr("class", "cursor-text cursor-text-shadow").attr("dx", dx).attr("dy", "-.3em");
      this.cursorValue = this.focus.append("text").attr("class", "cursor-text cursor-value").attr("dx", dx).attr("dy", "-.3em");
      this.cursorDateShadow = this.focus.append("text").attr("class", "cursor-text cursor-text-shadow").attr("dx", dx).attr("dy", "1em");
      this.cursorDate = this.focus.append("text").attr("class", "cursor-text cursor-date").attr("dx", dx).attr("dy", "1em");
438929a4   Goutte   Rewrite the orbit...
353
354
      return this.resize();
    };
123313cb   Goutte   Clip the paths of...
355
    RATIO = GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO;
438929a4   Goutte   Rewrite the orbit...
356
357
    TimeSeries.prototype.resize = function(){
      var width, height;
123313cb   Goutte   Clip the paths of...
358
359
      width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right);
      height = Math.ceil(RATIO * width);
541e2936   Goutte   Synchronize the t...
360
361
      this.plotWidth = width;
      this.plotHeight = height;
123313cb   Goutte   Clip the paths of...
362
      console.debug("Resizing " + this + ": " + width + " x " + height + "…");
438929a4   Goutte   Rewrite the orbit...
363
364
365
      this.xScale.range([0, width]);
      this.yScale.range([height, 0]);
      this.svg.attr('width', width + this.margin.right + this.margin.left).attr('height', height + this.margin.top + this.margin.bottom);
123313cb   Goutte   Clip the paths of...
366
      this.clip.attr("width", width).attr("height", height);
438929a4   Goutte   Rewrite the orbit...
367
368
369
      this.path.attr('d', this.line);
      this.xAxis.scale(this.xScale);
      this.yAxis.scale(this.yScale);
d49a163c   Goutte   Fix the resize an...
370
371
      this.xAxis.ticks(Math.floor(width / 90.0));
      this.yAxis.ticks(Math.floor(height / 18.0));
438929a4   Goutte   Rewrite the orbit...
372
373
      this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')').call(this.xAxis);
      this.svg.select('.y.axis').call(this.yAxis);
fe3132dd   Goutte   Refactor even more.
374
      this.yAxisText.attr("y", 20 - this.margin.left).attr("x", 0 - height / 2);
b60e7acd   Goutte   Rename "source" i...
375
      this.yAxisTextTarget.attr("y", 0 - this.margin.left).attr("x", 0 - height / 2);
2463bd16   Goutte   Add a circle foll...
376
      this.mouseCanvas.attr("width", width).attr("height", height);
08569a6b   Goutte   Add a zooming bru...
377
      if (this.brushFunction == null) {
c3008fb2   Goutte   Clean up and refa...
378
        console.debug("Creating the zooming brush for " + this + "…");
08569a6b   Goutte   Add a zooming bru...
379
380
        this.brushFunction = d3.brushX().extent([[0, 0], [width, height]]).handleSize(0).on("end", this.onBrushEnd);
        this.brush.call(this.brushFunction);
c3008fb2   Goutte   Clean up and refa...
381
        this.svg.select(".brush .overlay").on("mouseover.swapp", this.onMouseOver).on("mouseout.swapp", this.onMouseOut).on("mousemove.swapp", this.onMouseMove).on("dblclick.swapp", this.onDoubleClick);
08569a6b   Goutte   Add a zooming bru...
382
      }
6bb225d6   Goutte   Link the time ser...
383
384
      if (!this.visible) {
        this.hide();
b7fe650c   Goutte   Misc bundle of ol...
385
      }
2463bd16   Goutte   Add a circle foll...
386
387
      return this;
    };
6bb225d6   Goutte   Link the time ser...
388
389
390
391
392
393
394
395
    TimeSeries.prototype.show = function(){
      $(this.svg.node()).show();
      return this.visible = true;
    };
    TimeSeries.prototype.hide = function(){
      $(this.svg.node()).hide();
      return this.visible = false;
    };
541e2936   Goutte   Synchronize the t...
396
397
398
399
    TimeSeries.prototype.onMouseMove = function(){
      var x;
      x = this.xScale.invert(d3.mouse(this.mouseCanvas.node())[0]);
      if (this.options.onMouseMove != null) {
2038c9fb   Goutte   Add a zoom reset ...
400
        return this.options.onMouseMove(x);
541e2936   Goutte   Synchronize the t...
401
      } else {
2038c9fb   Goutte   Add a zoom reset ...
402
        return this.moveCursor(x);
541e2936   Goutte   Synchronize the t...
403
      }
541e2936   Goutte   Synchronize the t...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    };
    TimeSeries.prototype.onMouseOver = function(){
      if (this.options.onMouseOver != null) {
        return this.options.onMouseOver();
      } else {
        return this.showCursor();
      }
    };
    TimeSeries.prototype.onMouseOut = function(){
      if (this.options.onMouseOut != null) {
        return this.options.onMouseOut();
      } else {
        return this.hideCursor();
      }
    };
2038c9fb   Goutte   Add a zoom reset ...
419
    TimeSeries.prototype.onDoubleClick = function(){
c3008fb2   Goutte   Clean up and refa...
420
421
422
423
424
      if (this.options.onDblClick != null) {
        return this.options.onDblClick();
      } else {
        return this.resetZoom();
      }
2038c9fb   Goutte   Add a zoom reset ...
425
    };
08569a6b   Goutte   Add a zooming bru...
426
427
428
    TimeSeries.prototype.onBrushEnd = function(){
      var s, minmax;
      s = d3.event.selection;
08569a6b   Goutte   Add a zooming bru...
429
430
      if (s) {
        minmax = [s[0], s[1]].map(this.xScale.invert, this.xScale);
08569a6b   Goutte   Add a zooming bru...
431
        this.brush.call(this.brushFunction.move, null);
c3008fb2   Goutte   Clean up and refa...
432
433
434
435
436
        if (this.options.onBrushEnd != null) {
          return this.options.onBrushEnd(minmax[0], minmax[1]);
        } else {
          return this.zoomIn(minmax[0], minmax[1]);
        }
2038c9fb   Goutte   Add a zoom reset ...
437
438
439
440
441
      }
    };
    TimeSeries.prototype.zoomIn = function(startDate, stopDate){
      var ref$, minDate, maxDate;
      console.debug("Zooming in " + this + " from " + startDate + " to " + stopDate + ".");
6bb225d6   Goutte   Link the time ser...
442
      ref$ = this.xDataExtent, minDate = ref$[0], maxDate = ref$[1];
2038c9fb   Goutte   Add a zoom reset ...
443
444
445
446
447
      if (startDate < minDate) {
        startDate = minDate;
      }
      if (stopDate > maxDate) {
        stopDate = maxDate;
08569a6b   Goutte   Add a zooming bru...
448
      }
2038c9fb   Goutte   Add a zoom reset ...
449
450
451
452
      this.xScale.domain([startDate, stopDate]);
      return this.applyZoom();
    };
    TimeSeries.prototype.resetZoom = function(){
6bb225d6   Goutte   Link the time ser...
453
454
      this.xScale.domain(this.xDataExtent);
      this.yScale.domain(this.yDataExtent);
2038c9fb   Goutte   Add a zoom reset ...
455
      return this.applyZoom();
08569a6b   Goutte   Add a zooming bru...
456
    };
2038c9fb   Goutte   Add a zoom reset ...
457
    TimeSeries.prototype.applyZoom = function(){
08569a6b   Goutte   Add a zooming bru...
458
      var t;
6bb225d6   Goutte   Link the time ser...
459
      if (this.visible) {
c3008fb2   Goutte   Clean up and refa...
460
        console.debug("Applying zoom to visible " + this + "…");
6bb225d6   Goutte   Link the time ser...
461
462
463
464
465
        t = this.svg.transition().duration(750);
        this.svg.select('.x.axis').transition(t).call(this.xAxis);
        this.svg.select('.y.axis').transition(t).call(this.yAxis);
        return this.path.transition(t).attr('d', this.line);
      } else {
c3008fb2   Goutte   Clean up and refa...
466
        console.debug("Applying zoom to hidden " + this + "…");
6bb225d6   Goutte   Link the time ser...
467
468
469
470
        this.svg.select('.x.axis').call(this.xAxis);
        this.svg.select('.y.axis').call(this.yAxis);
        return this.path.attr('d', this.line);
      }
08569a6b   Goutte   Add a zooming bru...
471
    };
541e2936   Goutte   Synchronize the t...
472
473
474
475
476
477
    TimeSeries.prototype.showCursor = function(){
      return this.focus.style("display", null);
    };
    TimeSeries.prototype.hideCursor = function(){
      return this.focus.style("display", "none");
    };
2463bd16   Goutte   Add a circle foll...
478
479
480
    TimeSeries.prototype.bisectDate = d3.bisector(function(d){
      return d.x;
    }).left;
81c9b2e8   Goutte   Add the values to...
481
    TimeSeries.prototype.timeFormat = d3.timeFormat("%Y-%m-%d %Hh");
541e2936   Goutte   Synchronize the t...
482
    TimeSeries.prototype.moveCursor = function(x0){
8cb213b9   Goutte   Clean up, and pre...
483
      var i, d0, d1, d, xx, yy, mirrored, dx, transform;
2463bd16   Goutte   Add a circle foll...
484
485
486
      i = this.bisectDate(this.data, x0, 1);
      d0 = this.data[i - 1];
      d1 = this.data[i];
541e2936   Goutte   Synchronize the t...
487
488
489
      if (!(d1 && d0)) {
        return;
      }
2463bd16   Goutte   Add a circle foll...
490
491
492
      d = x0 - d0.x > d1.x - x0 ? d1 : d0;
      xx = this.xScale(d.x);
      yy = this.yScale(d.y);
541e2936   Goutte   Synchronize the t...
493
494
495
496
497
      mirrored = this.plotWidth != null && xx > this.plotWidth / 2 ? true : false;
      dx = 8;
      if (mirrored) {
        dx = -1 * dx;
      }
8cb213b9   Goutte   Clean up, and pre...
498
      transform = "translate(" + xx + ", " + yy + ")";
81c9b2e8   Goutte   Add the values to...
499
      this.cursorCircle.attr("transform", transform);
541e2936   Goutte   Synchronize the t...
500
501
502
503
      this.cursorValue.attr("transform", transform).text(d.y).attr('text-anchor', mirrored ? 'end' : 'start').attr("dx", dx);
      this.cursorValueShadow.attr("transform", transform).text(d.y).attr('text-anchor', mirrored ? 'end' : 'start').attr("dx", dx);
      this.cursorDate.attr("transform", transform).text(this.timeFormat(d.x)).attr('text-anchor', mirrored ? 'end' : 'start').attr("dx", dx);
      this.cursorDateShadow.attr("transform", transform).text(this.timeFormat(d.x)).attr('text-anchor', mirrored ? 'end' : 'start').attr("dx", dx);
438929a4   Goutte   Rewrite the orbit...
504
505
506
507
508
      return this;
    };
    return TimeSeries;
  }());
  out$.Orbits = Orbits = (function(){
8cb213b9   Goutte   Clean up, and pre...
509
    "View of the solar system from above, with orbits segments for selected time\ninterval, from real data.";
438929a4   Goutte   Rewrite the orbit...
510
511
    Orbits.displayName = 'Orbits';
    var prototype = Orbits.prototype, constructor = Orbits;
a21f81d9   Goutte   Enable Venus and ...
512
    function Orbits(container, options){
438929a4   Goutte   Rewrite the orbit...
513
514
515
516
      this.container = container;
      this.options = options != null
        ? options
        : {};
438929a4   Goutte   Rewrite the orbit...
517
518
519
      this.init();
    }
    Orbits.prototype.init = function(){
c3008fb2   Goutte   Clean up and refa...
520
      console.log("Initializing plot of orbits…");
438929a4   Goutte   Rewrite the orbit...
521
522
523
      this.margin = {
        top: 30,
        right: 20,
11662eed   Goutte   Add Y axis label ...
524
        bottom: 42,
438929a4   Goutte   Rewrite the orbit...
525
526
        left: 60
      };
a21f81d9   Goutte   Enable Venus and ...
527
528
529
      this.data = {};
      this.orbiters = {};
      this.extremum = 1;
438929a4   Goutte   Rewrite the orbit...
530
531
532
533
534
535
536
      this.xScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]);
      this.yScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]);
      this.xAxis = d3.axisBottom().ticks(10);
      this.yAxis = d3.axisLeft().ticks(10);
      this.svg = d3.select(this.container).append('svg');
      this.plotWrapper = this.svg.append('g');
      this.plotWrapper.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
ae0aa7d2   Goutte   Add an x axis lab...
537
538
539
540
541
      this.xAxisLine = this.plotWrapper.append('g').classed('x axis', true);
      this.yAxisLine = this.plotWrapper.append('g').classed('y axis', true);
      this.xAxisTitle = this.xAxisLine.append('text').attr('fill', '#000');
      this.xAxisTitle.style("text-anchor", "middle");
      this.xAxisTitle.append('tspan').text('X');
11662eed   Goutte   Add Y axis label ...
542
      this.xAxisTitle.append('tspan').attr('dy', '3px').text('HEE').attr('font-size', '8px');
ae0aa7d2   Goutte   Add an x axis lab...
543
      this.xAxisTitle.append('tspan').attr('dy', '-3px').text('   (AU)');
11662eed   Goutte   Add Y axis label ...
544
545
546
547
548
549
      this.yAxisTitle = this.yAxisLine.append('text').attr('fill', '#000');
      this.yAxisTitle.style("text-anchor", "middle");
      this.yAxisTitle.append('tspan').text('Y');
      this.yAxisTitle.append('tspan').attr('dy', '3px').text('HEE').attr('font-size', '8px');
      this.yAxisTitle.append('tspan').attr('dy', '-3px').text('   (AU)');
      this.yAxisTitle.attr('transform', 'rotate(-90)');
8bd715ad   Goutte   Use a pixel art i...
550
      this.sun = this.plotWrapper.append("svg:image").attr('xlink:href', this.options.sun.img).attr('width', '32px').attr('height', '32px');
438929a4   Goutte   Rewrite the orbit...
551
      this.sun.append('svg:title').text("Sol");
3ee0b596   Goutte   Fix an annoying b...
552
      $(this.svg.node()).hide();
438929a4   Goutte   Rewrite the orbit...
553
554
555
      return this.resize();
    };
    Orbits.prototype.orbitersElements = {};
a21f81d9   Goutte   Enable Venus and ...
556
    Orbits.prototype.initOrbiter = function(slug, config, data){
438929a4   Goutte   Rewrite the orbit...
557
      var orbit_ellipse, orbiter, orbit_line, orbit_section, this$ = this;
ebe77ce4   Goutte   Clean up.
558
      console.info("Initializing orbit of " + config.name + "…");
438929a4   Goutte   Rewrite the orbit...
559
560
561
      if (slug in this.orbitersElements) {
        throw new Error("Second init of " + slug);
      }
a21f81d9   Goutte   Enable Venus and ...
562
563
564
565
566
      this.extremum = Math.max(this.extremum, 1.11 * d3.max(data, function(d){
        return Math.max(Math.abs(d.x), Math.abs(d.y));
      }));
      this.xScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]);
      this.yScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]);
438929a4   Goutte   Rewrite the orbit...
567
568
569
570
571
572
573
      orbit_ellipse = this.plotWrapper.append("svg:ellipse").classed('orbit orbit_ellipse', true);
      orbiter = this.plotWrapper.append("svg:image").attr('xlink:href', config['img']).attr('width', '32px').attr('height', '32px');
      orbit_line = d3.line().x(function(d){
        return this$.xScale(d.x);
      }).y(function(d){
        return this$.yScale(d.y);
      });
a21f81d9   Goutte   Enable Venus and ...
574
575
576
      orbit_section = this.plotWrapper.append('path').datum(data).classed('orbit orbit_section', true);
      this.orbiters[slug] = config;
      this.data[slug] = data;
438929a4   Goutte   Rewrite the orbit...
577
578
579
580
581
582
      this.orbitersElements[slug] = {
        orbiter: orbiter,
        orbit_ellipse: orbit_ellipse,
        orbit_section: orbit_section,
        orbit_line: orbit_line
      };
a21f81d9   Goutte   Enable Venus and ...
583
      this.resize();
3ee0b596   Goutte   Fix an annoying b...
584
      $(this.svg.node()).show();
438929a4   Goutte   Rewrite the orbit...
585
586
587
588
      return this;
    };
    Orbits.prototype.resize = function(){
      var width, height, slug, ref$, config;
667eeb24   Goutte   Resize the domain...
589
590
591
      width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right);
      height = Math.ceil(1.0 * width);
      console.debug("Resizing orbits : " + width + " × " + height + "…");
438929a4   Goutte   Rewrite the orbit...
592
593
594
      this.xScale.range([0, width]);
      this.yScale.range([height, 0]);
      this.svg.attr('width', width + this.margin.right + this.margin.left).attr('height', height + this.margin.top + this.margin.bottom);
8bd715ad   Goutte   Use a pixel art i...
595
      this.sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16);
438929a4   Goutte   Rewrite the orbit...
596
597
      for (slug in ref$ = this.orbiters) {
        config = ref$[slug];
667eeb24   Goutte   Resize the domain...
598
        this.resizeOrbiter(slug, config, width, height);
438929a4   Goutte   Rewrite the orbit...
599
600
601
602
603
      }
      this.xAxis.scale(this.xScale);
      this.yAxis.scale(this.yScale);
      this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')').call(this.xAxis);
      this.svg.select('.y.axis').call(this.yAxis);
11662eed   Goutte   Add Y axis label ...
604
605
      this.xAxisTitle.attr("x", width / 2).attr("y", 37);
      this.yAxisTitle.attr("x", -1 * height / 2).attr("y", -30);
438929a4   Goutte   Rewrite the orbit...
606
607
      return this;
    };
667eeb24   Goutte   Resize the domain...
608
609
610
    Orbits.prototype.resizeOrbiter = function(slug, config, width, height){
      var el, a, b, c, cx, cy, data;
      console.debug("Resizing orbit of " + slug + "…");
438929a4   Goutte   Rewrite the orbit...
611
612
613
614
615
616
617
618
      el = this.orbitersElements[slug];
      el['orbit_section'].attr('d', el['orbit_line']);
      a = config['orbit']['a'];
      b = config['orbit']['b'];
      c = Math.sqrt(a * a - b * b);
      cx = width / 2 - c;
      cy = height / 2;
      this.yScale.range([0, height]);
a21f81d9   Goutte   Enable Venus and ...
619
      el['orbit_ellipse'].attr('cx', cx).attr('cy', cy).attr('rx', this.xScale(a) - this.xScale(0)).attr('ry', this.yScale(b) - this.yScale(0));
438929a4   Goutte   Rewrite the orbit...
620
      this.yScale.range([height, 0]);
a21f81d9   Goutte   Enable Venus and ...
621
      data = this.data[slug];
438929a4   Goutte   Rewrite the orbit...
622
623
624
625
      el['orbiter'].attr('x', this.xScale(data[data.length - 1].x) - 16);
      el['orbiter'].attr('y', this.yScale(data[data.length - 1].y) - 16);
      return this;
    };
ae0aa7d2   Goutte   Add an x axis lab...
626
627
    Orbits.prototype.repositionOrbiter = function(slug, datum){
      var data, el;
a21f81d9   Goutte   Enable Venus and ...
628
      data = this.data[slug];
ae0aa7d2   Goutte   Add an x axis lab...
629
630
631
632
633
634
635
636
637
638
      datum == null && (datum = data[data.length - 1]);
      el = this.orbitersElements[slug];
      el['orbiter'].attr('x', this.xScale(datum.x) - 16);
      el['orbiter'].attr('y', this.yScale(datum.y) - 16);
      return this;
    };
    Orbits.prototype.bisectDate = d3.bisector(function(d){
      return d.t;
    }).left;
    Orbits.prototype.moveToDate = function(t){
a21f81d9   Goutte   Enable Venus and ...
639
640
      var slug, ref$, el, data, i, d0, d1, d;
      if (!t) {
667eeb24   Goutte   Resize the domain...
641
        console.warn("Trying to move to an undefined date !");
a21f81d9   Goutte   Enable Venus and ...
642
      }
ae0aa7d2   Goutte   Add an x axis lab...
643
644
      for (slug in ref$ = this.orbitersElements) {
        el = ref$[slug];
a21f81d9   Goutte   Enable Venus and ...
645
        data = this.data[slug];
ae0aa7d2   Goutte   Add an x axis lab...
646
647
648
649
650
651
652
        i = this.bisectDate(data, t, 1);
        d0 = data[i - 1];
        d1 = data[i];
        if (!(d1 && d0)) {
          continue;
        }
        d = t - d0.t > d1.t - t ? d1 : d0;
a21f81d9   Goutte   Enable Venus and ...
653
        this.repositionOrbiter(slug, d);
ae0aa7d2   Goutte   Add an x axis lab...
654
      }
a21f81d9   Goutte   Enable Venus and ...
655
      return this;
ae0aa7d2   Goutte   Add an x axis lab...
656
    };
667eeb24   Goutte   Resize the domain...
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
    Orbits.prototype.resizeDomain = function(started_at, stopped_at){
      var slug, ref$, config, el, data, results$ = [];
      for (slug in ref$ = this.orbiters) {
        config = ref$[slug];
        el = this.orbitersElements[slug];
        data = this.data[slug].filter(fn$);
        el['orbit_section'].datum(data);
        results$.push(el['orbit_section'].attr('d', el['orbit_line']));
      }
      return results$;
      function fn$(d){
        var ref$;
        return started_at <= (ref$ = d.t) && ref$ <= stopped_at;
      }
    };
    Orbits.prototype.resetZoom = function(){
      var slug, ref$, config, el, results$ = [];
      for (slug in ref$ = this.orbiters) {
        config = ref$[slug];
        el = this.orbitersElements[slug];
        el['orbit_section'].datum(this.data[slug]);
        results$.push(el['orbit_section'].attr('d', el['orbit_line']));
      }
      return results$;
    };
438929a4   Goutte   Rewrite the orbit...
682
683
    return Orbits;
  }());
2463bd16   Goutte   Add a circle foll...
684
685
686
  function bind$(obj, key, target){
    return function(){ return (target || obj)[key].apply(obj, arguments) };
  }
438929a4   Goutte   Rewrite the orbit...
687
}).call(this);