// Generated by LiveScript 1.5.0 (function(){ var GOLDEN_RATIO, Target, SpaceWeather, TimeSeries, Orbits, out$ = typeof exports != 'undefined' && exports || this; GOLDEN_RATIO = 2 / (1 + Math.sqrt(5)); 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 = this.config.active; } return Target; }()); out$.SpaceWeather = SpaceWeather = (function(){ "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)"; SpaceWeather.displayName = 'SpaceWeather'; var API_TIME_FORMAT, INPUT_TIME_FORMAT, prototype = SpaceWeather.prototype, constructor = SpaceWeather; API_TIME_FORMAT = "YYYY-MM-DDTHH:mm:ss"; INPUT_TIME_FORMAT = "YYYY-MM-DD"; function SpaceWeather(configuration){ var configs, res$, k, this$ = this; this.configuration = configuration; console.info("©2017\n _ _ _ _ ____\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"); this.targets = {}; res$ = []; for (k in this.configuration.targets) { res$.push(this.configuration.targets[k]); } configs = res$; configs.forEach(function(target_config){ return this$.addTarget(new Target(target_config.slug, target_config.name, target_config)); }); this.parameters = {}; this.configuration['parameters'].forEach(function(p){ return this$.parameters[p['id']] = p; }); this.orbiter = null; this.time_series = []; } 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 started_at, stopped_at, this$ = this; started_at = moment().subtract(1, 'year').hours(0).minutes(0).seconds(0); stopped_at = moment().add(3, 'week').hours(0).minutes(0).seconds(0); this.setStartAndStop(started_at, stopped_at); this.loadAndCreatePlots(started_at, stopped_at); return window.addEventListener('resize', function(){ return this$.resize(); }); }; SpaceWeather.prototype.buildDataUrlForTarget = function(target_slug, started_at, stopped_at){ var url; url = this.configuration['api']['data_for_interval']; url = url.replace('', target_slug); url = url.replace('', started_at); url = url.replace('', stopped_at); return url; }; SpaceWeather.prototype.buildDownloadUrl = function(){ var ref$, started_at, stopped_at, targets, t, url; ref$ = this.getDomain(), started_at = ref$[0], stopped_at = ref$[1]; targets = (function(){ var results$ = []; for (t in this.targets) { if (this.targets[t].active) { results$.push(t); } } return results$; }.call(this)).sort().join('-'); url = this.configuration['api']['download']; url = url.replace('', targets); url = url.replace('', started_at.format(API_TIME_FORMAT)); url = url.replace('', stopped_at.format(API_TIME_FORMAT)); return url; }; SpaceWeather.prototype.buildSampUrl = function(){ var ref$, started_at, stopped_at, targets, t, parameters, p, url; ref$ = this.getDomain(), started_at = ref$[0], stopped_at = ref$[1]; targets = (function(){ var results$ = []; for (t in this.targets) { if (this.targets[t].active) { results$.push(t); } } return results$; }.call(this)).sort().join('-'); parameters = (function(){ var results$ = []; for (p in this.parameters) { if (this.parameters[p].active) { results$.push(p); } } return results$; }.call(this)).sort().join('-'); url = this.configuration['api']['samp']; url = url.replace('', targets); url = url.replace('', parameters); url = url.replace('', started_at.format(API_TIME_FORMAT)); url = url.replace('', stopped_at.format(API_TIME_FORMAT)); return url; }; SpaceWeather.prototype.buildSampName = function(){ var ref$, started_at, stopped_at, targets, t; ref$ = this.getDomain(), started_at = ref$[0], stopped_at = ref$[1]; targets = (function(){ var i$, ref$, len$, results$ = []; for (i$ = 0, len$ = (ref$ = this.getEnabledTargets()).length; i$ < len$; ++i$) { t = ref$[i$]; results$.push(t.name); } return results$; }.call(this)).sort().join(', '); return "Heliopropa for " + targets + " from " + started_at.format(API_TIME_FORMAT) + " to " + stopped_at.format(API_TIME_FORMAT) + "."; }; SpaceWeather.prototype.addTarget = function(target){ this.targets[target.slug] = target; return this; }; SpaceWeather.prototype.getEnabledTargets = function(){ var slug, ref$, target, results$ = []; for (slug in ref$ = this.targets) { target = ref$[slug]; if (target.active) { results$.push(target); } } return results$; }; SpaceWeather.prototype.enableTarget = function(target_slug){ var ref$, this$ = this; this.time_series.forEach(function(ts){ if (ts.target.slug === target_slug && this$.parameters[ts.parameter].active) { return ts.show(); } }); this.targets[target_slug].active = true; if ((ref$ = this.orbits) != null) { ref$.showOrbiter(target_slug); } return this; }; SpaceWeather.prototype.disableTarget = function(target_slug){ var ref$; this.time_series.forEach(function(ts){ if (ts.target.slug === target_slug) { return ts.hide(); } }); this.targets[target_slug].active = false; if ((ref$ = this.orbits) != null) { ref$.hideOrbiter(target_slug); } return this; }; SpaceWeather.prototype.resize = function(){ var ref$; if ((ref$ = this.orbits) != null) { ref$.resize(); } return this.time_series.forEach(function(ts){ return ts.resize(); }); }; SpaceWeather.prototype.showLoader = function(){ return $('#plots_loader').show(); }; SpaceWeather.prototype.hideLoader = function(){ return $('#plots_loader').hide(); }; 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."; var sw; sw = this; return new Promise(function(resolve, reject){ var url; url = sw.buildDataUrlForTarget(target_slug, started_at, stopped_at); return d3.csv(url, function(csv){ var timeFormat, data; console.debug("Requested CSV for " + target_slug + "…", csv); timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); data = { 'hee': [] }; configuration['parameters'].forEach(function(parameter){ return data[parameter['id']] = []; }); if (!csv) { reject('invalid'); } if (!csv.length) { reject('empty'); } 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['xhee'] && d['yhee']) { return data['hee'].push({ t: dtime, x: parseFloat(d['xhee']), y: parseFloat(d['yhee']) }); } }); return resolve(data); }); }); }; SpaceWeather.prototype.loadAndCreatePlots = function(started_at, stopped_at){ "started_at: moment(.js) datetime object\nstopped_at: moment(.js) datetime object"; var targets, res$, k, handleTarget, this$ = this; this.showLoader(); this.started_at = started_at; this.stopped_at = stopped_at; this.orbits = new Orbits(this.configuration.orbits_container, this.configuration); started_at = started_at.format(API_TIME_FORMAT); stopped_at = stopped_at.format(API_TIME_FORMAT); res$ = []; for (k in this.targets) { res$.push(this.targets[k]); } targets = res$; targets.forEach(function(target){ var targetButton; targetButton = $(".targets-filters .target." + target.slug); targetButton.addClass('loading'); return targetButton.removeClass('failed error empty'); }); handleTarget = function(i){ var target, targetButton; if (i >= targets.length) { return; } target = targets[i]; console.info("Loading CSV data of " + target.name + "…"); targetButton = $(".targets-filters .target." + target.slug); return this$.loadData(target.slug, started_at, stopped_at).then(function(data){ console.info("Loaded CSV data of " + target.name + ".", data); this$.createTimeSeries(target, data); this$.orbits.initOrbiter(target.slug, target.config, data['hee']); targetButton.removeClass('loading'); if (target.active) { this$.hideLoader(); } else { this$.disableTarget(target.slug); } return handleTarget(i + 1); }, function(error){ var msg; switch (error) { case 'invalid': console.error("Failed loading CSV data of " + target.name + "."); targetButton.addClass('error'); this$.is_invalid = true; break; case 'empty': msg = "No data for " + target.name + "\n during interval from \n" + started_at + " to " + stopped_at + "."; console.warn(msg); targetButton.addClass('empty'); break; } targetButton.addClass('failed'); targetButton.removeClass('loading'); this$.hideLoader(); return handleTarget(i + 1); }); }; handleTarget(0); return this; }; SpaceWeather.prototype.clearPlots = function(){ this.orbits.clear(); this.time_series.forEach(function(ts){ return ts.clear(); }); this.orbits = null; this.time_series = []; return this; }; SpaceWeather.prototype.createTimeSeries = function(target, 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 this$.time_series.push(new TimeSeries(id, title, target, data[id], this$.parameters[id].active, container, { 'started_at': this$.started_at, 'stopped_at': this$.stopped_at })); }); this.time_series.forEach(function(ts){ ts.options['onMouseOver'] = function(){ this$.time_series.forEach(function(ts2){ return ts2.showCursor(); }); return true; }; ts.options['onMouseOut'] = function(){ this$.time_series.forEach(function(ts2){ return ts2.hideCursor(); }); return true; }; ts.options['onMouseMove'] = function(t){ var ref$; this$.time_series.forEach(function(ts2){ return ts2.moveCursor(t); }); if ((ref$ = this$.orbits) != null) { ref$.moveToDate(t); } return true; }; ts.options['onBrushEnd'] = function(sta, sto){ this$.resizeDomain(moment(sta), moment(sto)); return true; }; return ts.options['onDblClick'] = function(){ var ref$; this$.resetZoom(); if ((ref$ = $("#zoom_controls_help")) != null) { ref$.remove(); } return true; }; }); return this.time_series; }; SpaceWeather.prototype.getEnabledParameters = function(){ var i$, ref$, len$, p, slug, results$ = []; for (i$ = 0, len$ = (ref$ = this.parameters).length; i$ < len$; ++i$) { p = i$; slug = ref$[i$]; if (p.active) { results$.push(p); } } return results$; }; 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; this.time_series.forEach(function(ts){ if (ts.parameter === parameter_slug && this$.targets[ts.target.slug].active) { return ts.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; this.time_series.forEach(function(ts){ if (ts.parameter === parameter_slug) { return ts.hide(); } }); return this; }; 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]; }; SpaceWeather.prototype.resizeDomain = function(started_at, stopped_at){ var ref$, max_stopped_at, formatted_started_at, formatted_stopped_at; if (stopped_at < started_at) { ref$ = [stopped_at, started_at], started_at = ref$[0], stopped_at = ref$[1]; } if (started_at === stopped_at) { console.warn("Please provide distinct start and stop dates."); return; } max_stopped_at = started_at.clone().add(2, 'years'); if (stopped_at > max_stopped_at) { console.warn("The time interval was truncated beacuse it was bigger than two years."); stopped_at = max_stopped_at; } this.setStartAndStop(started_at, stopped_at); formatted_started_at = started_at.format(); formatted_stopped_at = stopped_at.format(); if (!this.is_invalid && (this.started_at <= started_at && started_at <= this.stopped_at) && (this.started_at <= stopped_at && stopped_at <= this.stopped_at)) { console.info("Resizing the temporal domain from " + formatted_started_at + " to " + formatted_stopped_at + " without fetching new data…"); this.time_series.forEach(function(ts){ if (!ts.visible) { return ts.zoomIn(started_at, stopped_at); } }); this.time_series.forEach(function(ts){ if (ts.visible) { return ts.zoomIn(started_at, stopped_at); } }); this.orbits.resizeDomain(started_at, stopped_at); } else { this.is_invalid = false; console.info("Resizing the temporal domain from " + formatted_started_at + " to " + formatted_stopped_at + " and fetching new data…"); console.warn("This might take a while… Why not see what else we're up to on http://cdpp.eu while you're waiting?"); this.clearPlots(); this.loadAndCreatePlots(started_at, stopped_at); } return this; }; SpaceWeather.prototype.resetZoom = function(){ this.time_series.forEach(function(ts){ return ts.resetZoom(); }); this.orbits.resetZoom(); this.setStartAndStop(this.started_at, this.stopped_at); return this; }; SpaceWeather.prototype.setStartAndStop = function(started_at, stopped_at){ console.info("Setting time interval from " + started_at + " to " + stopped_at + "…"); this.current_started_at = started_at; this.current_stopped_at = stopped_at; $("#started_at").val(started_at.format(INPUT_TIME_FORMAT)); $("#stopped_at").val(stopped_at.format(INPUT_TIME_FORMAT)); return this; }; return SpaceWeather; }()); out$.TimeSeries = TimeSeries = (function(){ TimeSeries.displayName = 'TimeSeries'; var RATIO, prototype = TimeSeries.prototype, constructor = TimeSeries; function TimeSeries(parameter, title, target, data, visible, container, options){ this.parameter = parameter; this.title = title; this.target = target; this.data = data; this.visible = visible; this.container = container; this.options = options != null ? options : {}; this.onBrushEnd = bind$(this, 'onBrushEnd', prototype); this.onDoubleClick = bind$(this, 'onDoubleClick', prototype); this.onMouseOut = bind$(this, 'onMouseOut', prototype); this.onMouseOver = bind$(this, 'onMouseOver', prototype); this.onMouseMove = bind$(this, 'onMouseMove', prototype); this.init(); } TimeSeries.prototype.toString = function(){ return this.title + " of " + this.target.name; }; TimeSeries.prototype.init = function(){ var formatMillisecond, formatSecond, formatMinute, formatHour, formatDay, formatWeek, formatMonth, formatYear, multiFormat, clipId, dx, this$ = this; console.info("Initializing plot of " + this + "…"); this.xDataExtent = d3.extent(this.data, function(d){ return d.x; }); this.yDataExtent = d3.extent(this.data, function(d){ return d.y; }); if (this.options['started_at']) { this.xDataExtent[0] = this.options['started_at']; } if (this.options['stopped_at']) { this.xDataExtent[1] = this.options['stopped_at']; } this.margin = { top: 30, right: 20, bottom: 30, left: 80 }; this.xScale = d3.scaleTime().domain(this.xDataExtent); this.yScale = d3.scaleLinear().domain(this.yDataExtent); formatMillisecond = d3.timeFormat(".%L"); formatSecond = d3.timeFormat(":%S"); formatMinute = d3.timeFormat("%I:%M"); formatHour = d3.timeFormat("%I:%M"); formatDay = d3.timeFormat("%a %d"); formatWeek = d3.timeFormat("%b %d"); formatMonth = d3.timeFormat("%B"); formatYear = d3.timeFormat("%Y"); multiFormat = function(date){ if (date > d3.timeSecond(date)) { return formatMillisecond(date); } if (date > d3.timeMinute(date)) { return formatSecond(date); } if (date > d3.timeHour(date)) { return formatMinute(date); } if (date > d3.timeDay(date)) { return formatHour(date); } if (date > d3.timeMonth(date)) { if (date > d3.timeWeek(date)) { return formatDay(date); } else { return formatWeek(date); } } if (date > d3.timeYear(date)) { return formatMonth(date); } return formatYear(date); }; this.xAxis = d3.axisBottom().tickFormat(multiFormat).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.target.slug); this.plotWrapper = this.svg.append('g'); this.plotWrapper.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')'); 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); this.brush = this.plotWrapper.append("g").attr("class", "brush"); this.mouseCanvas = this.plotWrapper.append("rect").style("fill", "none"); 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.yAxisTextTarget = this.plotWrapper.append("text").attr("transform", "rotate(-90)").attr("dy", "1em").style("text-anchor", "middle").style("font-style", "oblique").text(this.target.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(); }; RATIO = GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO * GOLDEN_RATIO; TimeSeries.prototype.resize = function(){ var width, height; width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); height = Math.ceil(RATIO * width); this.plotWidth = width; this.plotHeight = height; console.debug("Resizing " + this + ": " + 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.clip.attr("width", width).attr("height", height); 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.yAxisTextTarget.attr("y", 0 - this.margin.left).attr("x", 0 - height / 2); this.mouseCanvas.attr("width", width).attr("height", height); if (this.brushFunction == null) { console.debug("Creating the zooming brush for " + this + "…"); this.brushFunction = d3.brushX().extent([[0, 0], [width, height]]).handleSize(0).on("end", this.onBrushEnd); this.brush.call(this.brushFunction); 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); } if (!this.visible) { this.hide(); } return this; }; TimeSeries.prototype.clear = function(){ $(this.svg.node()).remove(); return this.visible = false; }; TimeSeries.prototype.show = function(){ $(this.svg.node()).show(); return this.visible = true; }; TimeSeries.prototype.hide = function(){ $(this.svg.node()).hide(); return this.visible = false; }; 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.onDoubleClick = function(){ if (this.options.onDblClick != null) { return this.options.onDblClick(); } else { return this.resetZoom(); } }; TimeSeries.prototype.onBrushEnd = function(){ var s, minmax; s = d3.event.selection; if (s) { minmax = [s[0], s[1]].map(this.xScale.invert, this.xScale); this.brush.call(this.brushFunction.move, null); if (this.options.onBrushEnd != null) { return this.options.onBrushEnd(minmax[0], minmax[1]); } else { return this.zoomIn(minmax[0], minmax[1]); } } }; TimeSeries.prototype.zoomIn = function(startDate, stopDate){ var ref$, minDate, maxDate; console.debug("Zooming in " + this + " from " + startDate + " to " + stopDate + "."); ref$ = this.xDataExtent, minDate = ref$[0], maxDate = ref$[1]; if (startDate < minDate) { startDate = minDate; } if (stopDate > maxDate) { stopDate = maxDate; } this.xScale.domain([startDate, stopDate]); return this.applyZoom(); }; TimeSeries.prototype.resetZoom = function(){ this.xScale.domain(this.xDataExtent); this.yScale.domain(this.yDataExtent); return this.applyZoom(); }; TimeSeries.prototype.applyZoom = function(){ var t; if (this.visible) { console.debug("Applying zoom to visible " + this + "…"); 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 { console.debug("Applying zoom to hidden " + this + "…"); this.svg.select('.x.axis').call(this.xAxis); this.svg.select('.y.axis').call(this.yAxis); return this.path.attr('d', this.line); } }; 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 %H:%M"); TimeSeries.prototype.moveCursor = function(x0){ var i, d0, d1, d, xx, yy, mirrored, dx, transform; 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); mirrored = this.plotWidth != null && xx > this.plotWidth / 2 ? true : false; dx = 8; if (mirrored) { dx = -1 * dx; } transform = "translate(" + xx + ", " + yy + ")"; 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(){ "View of the solar system from above, with orbits segments for selected time\ninterval, from real data."; 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 plot of orbits…"); this.margin = { top: 30, right: 20, bottom: 42, left: 60 }; this.data = {}; this.orbiters = {}; this.orbitersElements = {}; this.orbitersExtrema = {}; this.lastOrbiterData = {}; this.xScale = d3.scaleLinear().domain([-1, 1]); this.yScale = d3.scaleLinear().domain([1, -1]); 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('Y'); 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('X'); 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("Sun"); $(this.svg.node()).hide(); return this.resize(); }; Orbits.prototype.initOrbiter = function(slug, config, data){ var orbit_ellipse, orbiter, orbit_line, orbit_section, this$ = this; this.data[slug] = data; this.orbiters[slug] = config; if (data.length) { console.info("Initializing orbit of " + config.name + "…"); } else { console.warn("No orbit data for " + config.name + "…"); return; } if (slug in this.orbitersElements) { throw new Error("Second init of " + slug); } 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'); orbiter.append('svg:title').text(config.name); orbit_line = d3.line().x(function(d){ return this$.xScale(d.y); }).y(function(d){ return this$.yScale(d.x); }); orbit_section = this.plotWrapper.append('path').datum(data).classed('orbit orbit_section', true); this.orbitersElements[slug] = { orbiter: orbiter, orbit_ellipse: orbit_ellipse, orbit_section: orbit_section, orbit_line: orbit_line }; this.orbitersExtrema[slug] = d3.max(data, function(d){ return Math.max(Math.abs(d.x), Math.abs(d.y)); }); $(this.svg.node()).show(); this.resize(true); return this; }; Orbits.prototype.showOrbiter = function(slug){ if (!this.data[slug].length) { return; } this.orbiters[slug].hidden = false; 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); }; Orbits.prototype.hideOrbiter = function(slug){ if (!this.data[slug].length) { return; } this.orbiters[slug].hidden = true; this.orbitersElements[slug].orbiter.style("display", "none"); this.orbitersElements[slug].orbit_ellipse.style("display", "none"); this.orbitersElements[slug].orbit_section.style("display", "none"); return this.resize(true); }; Orbits.prototype.clear = function(){ return $(this.svg.node()).remove(); }; Orbits.prototype.resize = function(animate){ var width, height, extremum, s, o, slug, ref$, config, t, t1, this$ = this; animate == null && (animate = false); width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); height = Math.ceil(1.0 * width); console.debug("Resizing orbits : " + width + " × " + height + "…"); extremum = 1.1 * d3.max((function(){ var ref$, results$ = []; for (s in ref$ = this.orbiters) { o = ref$[s]; if (!o.hidden) { results$.push(s); } } return results$; }.call(this)), function(d){ return this$.orbitersExtrema[d]; }); this.xScale = d3.scaleLinear().domain([-1 * extremum, extremum]); this.yScale = d3.scaleLinear().domain([extremum, -1 * extremum]); 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, width, height, animate); } this.xAxis.scale(this.xScale); this.yAxis.scale(this.yScale); this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')'); if (animate) { t = this.svg.transition().duration(750); t1 = this.svg.transition().duration(4750); this.svg.select('.x.axis').transition(t).call(this.xAxis); this.svg.select('.y.axis').transition(t).call(this.yAxis); } else { this.svg.select('.x.axis').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, width, height, animate){ var data, tt, el, orbit_section, t, a, b, c, cx, cy, orbit_ellipse; animate == null && (animate = false); data = this.data[slug]; if (!data.length) { return; } console.debug("Resizing orbit of " + slug + "…"); tt = this.svg.transition().duration(750); el = this.orbitersElements[slug]; orbit_section = el['orbit_section']; if (animate) { t = this.svg.transition().duration(750); orbit_section = orbit_section.transition(tt); } 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; orbit_ellipse = el['orbit_ellipse']; if (animate) { t = this.svg.transition().duration(750); orbit_ellipse = orbit_ellipse.transition(t); } 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.repositionOrbiter(slug, null, true); return this; }; Orbits.prototype.repositionOrbiter = function(slug, datum, animate){ var data, el, t; animate == null && (animate = false); data = this.data[slug]; if (!data.length) { return; } datum == null && (datum = this.lastOrbiterData[slug]); datum == null && (datum = data[data.length - 1]); this.lastOrbiterData[slug] = datum; el = this.orbitersElements[slug]['orbiter']; if (animate) { t = this.svg.transition().duration(750); el = el.transition(t); } el.attr('x', this.xScale(datum.y) - 16); el.attr('y', this.yScale(datum.x) - 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.warn("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; }; Orbits.prototype.resizeDomain = function(started_at, stopped_at){ var slug, ref$, config, el, data; for (slug in ref$ = this.orbiters) { config = ref$[slug]; el = this.orbitersElements[slug]; data = this.data[slug].filter(fn$); if (!data.length) { return; } el['orbit_section'].datum(data); el['orbit_section'].attr('d', el['orbit_line']); } function fn$(d){ var ref$; return started_at <= (ref$ = d.t) && ref$ <= stopped_at; } }; Orbits.prototype.resetZoom = function(){ var slug, ref$, config, el; for (slug in ref$ = this.orbiters) { config = ref$[slug]; el = this.orbitersElements[slug]; if (!this.data[slug].length) { return; } el['orbit_section'].datum(this.data[slug]); el['orbit_section'].attr('d', el['orbit_line']); } }; return Orbits; }()); function bind$(obj, key, target){ return function(){ return (target || obj)[key].apply(obj, arguments) }; } }).call(this);