diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dd05f8..02c13a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,6 @@ et prendre aussi ## Future ? -- [ ] Re-enable Earth - [ ] Enable p67 - [ ] Layer : Auroral Emissions - [ ] Set the log level to _error_ in production (see `web/run.py`) @@ -39,6 +38,12 @@ et prendre aussi - [ ] IE compat, if you can (I can't) +## 1.6 + +- [x] Re-enable Earth +- [x] Layer : CME Catalogs + + ## 1.5 - [x] Use the new AMDA API diff --git a/config.yml b/config.yml index b81314b..583057c 100644 --- a/config.yml +++ b/config.yml @@ -69,6 +69,7 @@ layers: file: "ICME_WP4_V10.json" start: "ICME_START_TIME" stop: "MO_END_TIME" + format: "%Y-%m-%dT%H:%MZ" l1: venus: constraints: [ { SC_INSITU: ["VEX"] } ] @@ -78,6 +79,7 @@ layers: url: "https://www.helcats-fp7.eu/catalogues/data/HCME_WP4_V6.json" file: "HCME_WP4_V6.json" start: "TARGET_ARRIVAL" + format: "%Y-%m-%dT%H:%MZ" l1: mars: constraints: [ { TARGET_NAME: ["MARS", "MAVEN", "MSC"] } ] @@ -85,6 +87,7 @@ layers: url: "https://cdaw.gsfc.nasa.gov/CME_list/UNIVERSAL/text_ver/univ_all.txt" file: "univ_all.json" start: "DATETIME" + format: "%Y-%m-%dT%H:%M:%S" l1: earth: ~ diff --git a/web/run.py b/web/run.py index 34d3967..b51a3fe 100755 --- a/web/run.py +++ b/web/run.py @@ -44,6 +44,7 @@ with open(get_path('../config.yml'), 'r') as config_file: config = yaml_load(config_file.read()) FILE_DATE_FMT = "%Y-%m-%dT%H:%M:%S" +MOMENT_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" # LOGGING ##################################################################### @@ -802,7 +803,7 @@ def get_interval_from_query(): return started_at, stopped_at -def get_catalog_layers(input_slug, target_slug): +def get_catalog_layers(input_slug, target_slug, started_at, stopped_at): """ In the JSON file we have "columns" and "data". Of course, each JSON file has its own columns, with different conventions. @@ -821,6 +822,15 @@ def get_catalog_layers(input_slug, target_slug): raise return index + try: + started_at = datetime.datetime.strptime(started_at, FILE_DATE_FMT) + except: + abort(400, "Invalid started_at parameter : '%s'." % started_at) + try: + stopped_at = datetime.datetime.strptime(stopped_at, FILE_DATE_FMT) + except: + abort(400, "Invalid stopped_at parameter : '%s'." % stopped_at) + catalog_layers = {} for config_layer in config['layers']: if 'data' not in config_layer: @@ -836,11 +846,15 @@ def get_catalog_layers(input_slug, target_slug): constraints = [] else: constraints = cl_datum[input_slug][target_slug]['constraints'] + with open(get_path("../data/catalog/%s" % cl_datum['file'])) as f: json_data = json.load(f) if 'start' not in cl_datum: log.error("Invalid configuration: 'start' is missing.") continue # skip this + if 'format' not in cl_datum: + log.error("Invalid configuration: 'format' is missing.") + continue # skip this start_index = _get_index_of_key(json_data, cl_datum['start']) if 'stop' not in cl_datum: stop_index = start_index @@ -867,9 +881,20 @@ def get_catalog_layers(input_slug, target_slug): continue start_time = json_datum[start_index] stop_time = json_datum[stop_index] + + start_time = datetime.datetime.strptime( + start_time, cl_datum['format'] + ) + stop_time = datetime.datetime.strptime( + stop_time, cl_datum['format'] + ) + + if start_time < started_at: + continue + catalog_layers[config_layer['slug']].append({ - 'start': start_time, - 'stop': stop_time, + 'start': start_time.strftime(MOMENT_DATE_FMT), + 'stop': stop_time.strftime(MOMENT_DATE_FMT), }) return catalog_layers @@ -940,7 +965,7 @@ def home(): started_at, stopped_at = get_interval_from_query() for i, target in enumerate(targets): targets[i]['catalog_layers'] = get_catalog_layers( - input_slug, target['slug'] + input_slug, target['slug'], started_at, stopped_at ) return render_view('home.html.jinja2', { # 'targets': config['targets'], diff --git a/web/static/js/main.js b/web/static/js/main.js index 67384e0..21e64b3 100644 --- a/web/static/js/main.js +++ b/web/static/js/main.js @@ -71,12 +71,12 @@ init(started_at, stopped_at) { // "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)"; - const this$ = this; + const app = this; started_at = moment(started_at).hours(0).minutes(0).seconds(0); stopped_at = moment(stopped_at).hours(0).minutes(0).seconds(0); this.setStartAndStop(started_at, stopped_at); this.loadAndCreatePlots(started_at, stopped_at); - window.addEventListener('resize', () => this$.resize()); + window.addEventListener('resize', () => app.resize()); return this; } @@ -219,9 +219,8 @@ } resize() { - let ref$; - if ((ref$ = this.orbits) != null) { - ref$.resize(); + if (null != this.orbits) { + this.orbits.resize(); } this.time_series.forEach(ts => ts.resize()); return this; @@ -401,7 +400,7 @@ return true; }).bind(ts); - return ts.options['onDblClick'] = () => { + ts.options['onDblClick'] = () => { let ref$; app.resetZoom(); if ((ref$ = $("#zoom_controls_help")) != null) { @@ -506,6 +505,7 @@ let starting_ts_key = tsv.indexOf(starting_ts); if (starting_ts_key === -1) starting_ts_key = 0; zoomedOnVisible = new Promise((resolve, reject) => { + console.log("Zoom on invisible time series…"); let tsv_zoom_on_next; tsv_zoom_on_next = i => { let ts; @@ -517,9 +517,10 @@ ts.zoomIn(started_at, stopped_at) .then(() => tsv_zoom_on_next(i + 1)); }; - return tsv_zoom_on_next(0); + tsv_zoom_on_next(0); }); zoomedOnVisible.then(() => { + console.log("Now zoom on invisible time series…"); this.time_series.forEach(ts => { if (!ts.visible) { ts.zoomIn(started_at, stopped_at); @@ -843,13 +844,12 @@ } applyZoom() { - let duration; - let t; + let duration = 0; duration = 0; if (this.visible) { duration = 750; console.debug(`Applying zoom to visible ${this}…`); - t = this.svg.transition().duration(duration); + let t = this.svg.transition().duration(duration); this.svg.select('.x.axis').transition(t).call(this.xAxis); this.svg.select('.y.axis').transition(t).call(this.yAxis); this.path.transition(t).attr('d', this.line); @@ -1095,7 +1095,7 @@ return this.hideOrbiter(slug); } - showOrbiter(slug) { + showOrbiter(slug, doResize=true) { if (!this.data[slug].length) { return; } @@ -1106,7 +1106,9 @@ this.orbitersElements[slug].orbiter.style("display", null); this.orbitersElements[slug].orbit_ellipse.style("display", null); this.orbitersElements[slug].orbit_section.style("display", null); - return this.resize(true); + if (doResize) this.resize(true); + + return this; } hideOrbiter(slug) { @@ -1136,7 +1138,7 @@ extremum == null && (extremum = null); const width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); const height = width; // it's a square - console.debug(`Resizing orbits : ${width} × ${height}…`); + console.debug(`Resizing orbits : ${width} × ${height}… (animated: ${animate})`); if (extremum === null) { extremum = 1.1 * d3.max((function () { let ref$; @@ -1272,25 +1274,24 @@ } resizeDomain(started_at, stopped_at) { - let slug; - let ref$; let config; let el; let data; - const results$ = []; - for (slug in ref$ = this.orbiters) { - config = ref$[slug]; + for (let slug in this.orbiters) { + config = this.orbiters[slug]; el = this.orbitersElements[slug]; data = this.data[slug].filter(onlyDataInRange); - if (!data.length) { + if ( ! data.length) { this.hideOrbiter(slug); continue; } el['orbit_section'].datum(data); el['orbit_section'].attr('d', el['orbit_line']); - results$.push(this.showOrbiter(slug)); + this.showOrbiter(slug, false); } - return results$; + this.resize(true); + + return this; function onlyDataInRange(d) { return started_at <= d.t && d.t <= stopped_at; -- libgit2 0.21.2