// Generated by LiveScript 1.5.0 (function(){ var GOLDEN_RATIO, SpaceWeather, Source, TimeSeries, Orbits, out$ = typeof exports != 'undefined' && exports || this; GOLDEN_RATIO = 2 / (1 + Math.sqrt(5)); out$.SpaceWeather = SpaceWeather = (function(){ "The main app, instanciated from an inline script."; SpaceWeather.displayName = 'SpaceWeather'; var timeSeries, prototype = SpaceWeather.prototype, constructor = SpaceWeather; function SpaceWeather(configuration){ var configs, res$, k, this$ = this; this.configuration = configuration; console.info("Creating Space Weather app...", this.configuration); this.sources = {}; res$ = []; for (k in this.configuration.sources) { res$.push(this.configuration.sources[k]); } configs = res$; configs.forEach(function(source_config){ return this$.sources[source_config.slug] = new Source(source_config.slug, source_config.name, source_config); }); this.parameters = {}; this.configuration['parameters'].forEach(function(p){ return this$.parameters[p['id']] = p; }); } SpaceWeather.prototype.buildDataUrlForSource = function(source_slug, started_at, stopped_at){ var url; url = this.configuration['api']['data_for_interval']; url = url.replace('', source_slug); url = url.replace('', started_at); url = url.replace('', stopped_at); return url; }; SpaceWeather.prototype.addSource = function(source){ this.sources[source.slug] = source; return this; }; SpaceWeather.prototype.showAllSources = function(){ var slug, ref$, source; for (slug in ref$ = this.sources) { source = ref$[slug]; showSource(slug); } return this; }; SpaceWeather.prototype.showSource = function(source_slug){ var this$ = this; timeSeries.forEach(function(ts){ if (ts.source.slug === source_slug && this$.parameters[ts.parameter].active) { return $(ts.svg.node()).show(); } }); this.sources[source_slug].active = true; return this; }; SpaceWeather.prototype.hideSource = function(source_slug){ timeSeries.forEach(function(ts){ if (ts.source.slug === source_slug) { return $(ts.svg.node()).hide(); } }); this.sources[source_slug].active = false; return this; }; SpaceWeather.prototype.resize = function(){ var ref$; if ((ref$ = this.orbits) != null) { ref$.resize(); } return timeSeries.forEach(function(ts){ return ts.resize(); }); }; SpaceWeather.prototype.init = function(){ var active_sources, res$, k, started_at, stopped_at, this$ = this; res$ = []; for (k in this.sources) { if (this.sources[k].config.active) { res$.push(this.sources[k]); } } active_sources = res$; this.orbits = new Orbits(this.configuration.orbits_container, this.configuration); started_at = moment().subtract(1, 'years').hours(0).minutes(0).seconds(0); stopped_at = moment().add(7, 'days').hours(0).minutes(0).seconds(0); started_at = started_at.format("YYYY-MM-DDTHH:mm:ss"); stopped_at = stopped_at.format("YYYY-MM-DDTHH:mm:ss"); active_sources.forEach(function(source){ return this$.loadData(source.slug, started_at, stopped_at).then(function(data){ console.info("Loaded CSV data for " + source.slug + "."); this$.createTimeSeries(source, data); return this$.orbits.initOrbiter(source.slug, source.config, data['hci']); }, function(data){ return console.error('Failed to load SW data.', data); }); }); return window.addEventListener('resize', function(){ return this$.resize(); }); }; SpaceWeather.prototype.loadData = function(source_slug, started_at, stopped_at){ var sw, promise; sw = this; promise = new Promise(function(resolve, reject){ var url; url = sw.buildDataUrlForSource(source_slug, started_at, stopped_at); return d3.csv(url, function(csv){ 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; }; timeSeries = []; SpaceWeather.prototype.createTimeSeries = function(source, data){ var this$ = this; this.configuration['parameters'].forEach(function(parameter){ var container, id, title; container = this$.configuration['time_series_container']; id = parameter['id']; title = parameter['title']; if (!(id in data)) { console.error("No data for id '" + id + "'.", data); } return timeSeries.push(new TimeSeries(id, title, source, data[id], this$.parameters[id].active, container)); }); return timeSeries.forEach(function(ts){ ts.options['onMouseOver'] = function(){ return timeSeries.forEach(function(ts2){ return ts2.showCursor(); }); }; ts.options['onMouseOut'] = function(){ return timeSeries.forEach(function(ts2){ return ts2.hideCursor(); }); }; return ts.options['onMouseMove'] = function(t){ var ref$; timeSeries.forEach(function(ts2){ return ts2.moveCursor(t); }); return (ref$ = this$.orbits) != null ? ref$.moveToDate(t) : void 8; }; }); }; SpaceWeather.prototype.enableParameter = function(parameter_slug){ var this$ = this; if (!(parameter_slug in this.parameters)) { console.error("Unknown parameter " + parameter_slug + "."); } this.parameters[parameter_slug].active = true; timeSeries.forEach(function(ts){ if (ts.parameter === parameter_slug && this$.sources[ts.source.slug].active) { return $(ts.svg.node()).show(); } }); return this; }; SpaceWeather.prototype.disableParameter = function(parameter_slug){ if (!(parameter_slug in this.parameters)) { console.error("Unknown parameter " + parameter_slug + "."); } this.parameters[parameter_slug].active = false; timeSeries.forEach(function(ts){ if (ts.parameter === parameter_slug) { return $(ts.svg.node()).hide(); } }); return this; }; return SpaceWeather; }()); Source = (function(){ Source.displayName = 'Source'; var prototype = Source.prototype, constructor = Source; function Source(slug, name, config){ this.slug = slug; this.name = name; this.config = config; this.active = true; } return Source; }()); out$.TimeSeries = TimeSeries = (function(){ TimeSeries.displayName = 'TimeSeries'; var prototype = TimeSeries.prototype, constructor = TimeSeries; function TimeSeries(parameter, title, source, data, active, container, options){ this.parameter = parameter; this.title = title; this.source = source; this.data = data; this.active = active; this.container = container; this.options = options != null ? options : {}; this.onMouseOut = bind$(this, 'onMouseOut', prototype); this.onMouseOver = bind$(this, 'onMouseOver', prototype); this.onMouseMove = bind$(this, 'onMouseMove', prototype); if (this.active) { console.info("Creating time series '" + this.title + "'..."); } else { console.info("Creating inactive time series '" + this.title + "'..."); } this.init(); } TimeSeries.prototype.init = function(){ var dx, this$ = this; console.info("Initializing time series '" + this.title + "'...", this.data, this.options); this.margin = { top: 30, right: 20, bottom: 30, left: 80 }; this.xScale = d3.scaleTime().domain(d3.extent(this.data, function(d){ return d.x; })); this.yScale = d3.scaleLinear().domain(d3.extent(this.data, function(d){ return d.y; })); this.xAxis = d3.axisBottom().tickFormat(d3.timeFormat("%Y-%m-%d")).ticks(7); 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'); this.svg.attr("class", this.parameter + " " + this.source.slug); this.plotWrapper = this.svg.append('g'); this.plotWrapper.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); this.path = this.plotWrapper.append('path').datum(this.data).classed('line', true); this.mouseCanvas = this.plotWrapper.append("rect").style("fill", "none").style("pointer-events", "all"); this.mouseCanvas.on("mouseover", this.onMouseOver).on("mouseout", this.onMouseOut).on("mousemove", this.onMouseMove); 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); this.yAxisTextSource = this.plotWrapper.append("text").attr("transform", "rotate(-90)").attr("dy", "1em").style("text-anchor", "middle").style("font-style", "oblique").text(this.source.name); this.focus = this.plotWrapper.append('g').style("display", "none"); this.cursorCircle = this.focus.append("circle").attr("class", "cursor-circle").attr("r", 3); 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"); return this.resize(); }; TimeSeries.prototype.resize = function(){ var width, height; width = jQuery(this.container).width() - this.margin.left - this.margin.right; height = GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO * width; this.plotWidth = width; this.plotHeight = height; console.log("Resizing time series " + this.title + " : " + width + " x " + height); 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); this.path.attr('d', this.line); this.xAxis.scale(this.xScale); this.yAxis.scale(this.yScale); this.xAxis.ticks(Math.floor(width / 90.0)); this.yAxis.ticks(Math.floor(height / 18.0)); this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')').call(this.xAxis); this.svg.select('.y.axis').call(this.yAxis); this.yAxisText.attr("y", 20 - this.margin.left).attr("x", 0 - height / 2); this.yAxisTextSource.attr("y", 0 - this.margin.left).attr("x", 0 - height / 2); this.mouseCanvas.attr("width", width).attr("height", height); if (!this.active) { $(this.svg.node()).hide(); } return this; }; TimeSeries.prototype.onMouseMove = function(){ var x; x = this.xScale.invert(d3.mouse(this.mouseCanvas.node())[0]); if (this.options.onMouseMove != null) { return this.options.onMouseMove(x); } else { return this.moveCursor(x); } }; 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(); } }; TimeSeries.prototype.showCursor = function(){ return this.focus.style("display", null); }; TimeSeries.prototype.hideCursor = function(){ return this.focus.style("display", "none"); }; TimeSeries.prototype.bisectDate = d3.bisector(function(d){ return d.x; }).left; TimeSeries.prototype.timeFormat = d3.timeFormat("%Y-%m-%d %Hh"); TimeSeries.prototype.moveCursor = function(x0){ var i, d0, d1, d, xx, yy, transform, mirrored, dx; i = this.bisectDate(this.data, x0, 1); d0 = this.data[i - 1]; d1 = this.data[i]; if (!(d1 && d0)) { return; } d = x0 - d0.x > d1.x - x0 ? d1 : d0; xx = this.xScale(d.x); yy = this.yScale(d.y); transform = "translate(" + xx + ", " + yy + ")"; mirrored = this.plotWidth != null && xx > this.plotWidth / 2 ? true : false; dx = 8; if (mirrored) { dx = -1 * dx; } this.cursorCircle.attr("transform", transform); 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); return this; }; return TimeSeries; }()); out$.Orbits = Orbits = (function(){ Orbits.displayName = 'Orbits'; var prototype = Orbits.prototype, constructor = Orbits; function Orbits(container, options){ this.container = container; this.options = options != null ? options : {}; this.init(); } Orbits.prototype.init = function(){ console.log("Initializing orbits...", this.options); this.margin = { top: 30, right: 20, bottom: 42, left: 60 }; this.data = {}; this.orbiters = {}; this.extremum = 1; 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 + ')'); 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'); this.xAxisTitle.append('tspan').attr('dy', '3px').text('HEE').attr('font-size', '8px'); this.xAxisTitle.append('tspan').attr('dy', '-3px').text(' (AU)'); 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)'); this.sun = this.plotWrapper.append("svg:image").attr('xlink:href', this.options.sun.img).attr('width', '32px').attr('height', '32px'); this.sun.append('svg:title').text("Sol"); return this.resize(); }; Orbits.prototype.orbitersElements = {}; Orbits.prototype.initOrbiter = function(slug, config, data){ var orbit_ellipse, orbiter, orbit_line, orbit_section, this$ = this; console.log("Initializing target " + slug + "'s orbit...", config, data); if (slug in this.orbitersElements) { throw new Error("Second init of " + slug); } 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]); 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); }); orbit_section = this.plotWrapper.append('path').datum(data).classed('orbit orbit_section', true); this.orbiters[slug] = config; this.data[slug] = data; this.orbitersElements[slug] = { orbiter: orbiter, orbit_ellipse: orbit_ellipse, orbit_section: orbit_section, orbit_line: orbit_line }; this.resize(); return this; }; Orbits.prototype.resize = function(){ var width, height, slug, ref$, config; width = jQuery(this.container).width() - this.margin.left - this.margin.right; height = 1.0 * width; console.log("Resize orbits : " + width + " x " + height); 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); this.sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16); for (slug in ref$ = this.orbiters) { config = ref$[slug]; this.resizeOrbiter(slug, config); } 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); this.xAxisTitle.attr("x", width / 2).attr("y", 37); this.yAxisTitle.attr("x", -1 * height / 2).attr("y", -30); return this; }; Orbits.prototype.resizeOrbiter = function(slug, config){ var width, height, el, a, b, c, cx, cy, data; width = jQuery(this.container).width() - this.margin.left - this.margin.right; height = 1.0 * width; console.log("Resize orbiter " + slug); 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]); 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)); this.yScale.range([height, 0]); data = this.data[slug]; 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; }; Orbits.prototype.repositionOrbiter = function(slug, datum){ var data, el; data = this.data[slug]; 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){ var slug, ref$, el, data, i, d0, d1, d; if (!t) { console.log("Trying to move to an undefined date"); } for (slug in ref$ = this.orbitersElements) { el = ref$[slug]; data = this.data[slug]; 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; this.repositionOrbiter(slug, d); } return this; }; return Orbits; }()); function bind$(obj, key, target){ return function(){ return (target || obj)[key].apply(obj, arguments) }; } }).call(this);