Commit 17c52617f831a8b117dba01261bb7b1b4d8fd351
1 parent
b500e561
Exists in
master
and in
2 other branches
Make the orbits plot dynamic. (finally!)
Showing
4 changed files
with
161 additions
and
64 deletions
Show diff stats
VERSION
config.yml
@@ -102,7 +102,7 @@ targets: | @@ -102,7 +102,7 @@ targets: | ||
102 | - type: 'planet' | 102 | - type: 'planet' |
103 | slug: 'earth' | 103 | slug: 'earth' |
104 | name: 'Earth' | 104 | name: 'Earth' |
105 | - title: 'Earth' | 105 | + title: 'Earth (Coming NEXT!)' |
106 | orbit: | 106 | orbit: |
107 | models: | 107 | models: |
108 | - slug: 'earth_orb_all' | 108 | - slug: 'earth_orb_all' |
web/static/js/swapp.js
@@ -132,22 +132,29 @@ | @@ -132,22 +132,29 @@ | ||
132 | return results$; | 132 | return results$; |
133 | }; | 133 | }; |
134 | SpaceWeather.prototype.enableTarget = function(target_slug){ | 134 | SpaceWeather.prototype.enableTarget = function(target_slug){ |
135 | - var this$ = this; | 135 | + var ref$, this$ = this; |
136 | this.time_series.forEach(function(ts){ | 136 | this.time_series.forEach(function(ts){ |
137 | if (ts.target.slug === target_slug && this$.parameters[ts.parameter].active) { | 137 | if (ts.target.slug === target_slug && this$.parameters[ts.parameter].active) { |
138 | return ts.show(); | 138 | return ts.show(); |
139 | } | 139 | } |
140 | }); | 140 | }); |
141 | this.targets[target_slug].active = true; | 141 | this.targets[target_slug].active = true; |
142 | + if ((ref$ = this.orbits) != null) { | ||
143 | + ref$.showOrbiter(target_slug); | ||
144 | + } | ||
142 | return this; | 145 | return this; |
143 | }; | 146 | }; |
144 | SpaceWeather.prototype.disableTarget = function(target_slug){ | 147 | SpaceWeather.prototype.disableTarget = function(target_slug){ |
148 | + var ref$; | ||
145 | this.time_series.forEach(function(ts){ | 149 | this.time_series.forEach(function(ts){ |
146 | if (ts.target.slug === target_slug) { | 150 | if (ts.target.slug === target_slug) { |
147 | return ts.hide(); | 151 | return ts.hide(); |
148 | } | 152 | } |
149 | }); | 153 | }); |
150 | this.targets[target_slug].active = false; | 154 | this.targets[target_slug].active = false; |
155 | + if ((ref$ = this.orbits) != null) { | ||
156 | + ref$.hideOrbiter(target_slug); | ||
157 | + } | ||
151 | return this; | 158 | return this; |
152 | }; | 159 | }; |
153 | SpaceWeather.prototype.resize = function(){ | 160 | SpaceWeather.prototype.resize = function(){ |
@@ -706,9 +713,10 @@ | @@ -706,9 +713,10 @@ | ||
706 | this.data = {}; | 713 | this.data = {}; |
707 | this.orbiters = {}; | 714 | this.orbiters = {}; |
708 | this.orbitersElements = {}; | 715 | this.orbitersElements = {}; |
709 | - this.extremum = 1; | ||
710 | - this.xScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]); | ||
711 | - this.yScale = d3.scaleLinear().domain([this.extremum, -1 * this.extremum]); | 716 | + this.orbitersExtrema = {}; |
717 | + this.lastOrbiterData = {}; | ||
718 | + this.xScale = d3.scaleLinear().domain([-1, 1]); | ||
719 | + this.yScale = d3.scaleLinear().domain([1, -1]); | ||
712 | this.xAxis = d3.axisBottom().ticks(10); | 720 | this.xAxis = d3.axisBottom().ticks(10); |
713 | this.yAxis = d3.axisLeft().ticks(10); | 721 | this.yAxis = d3.axisLeft().ticks(10); |
714 | this.svg = d3.select(this.container).append('svg'); | 722 | this.svg = d3.select(this.container).append('svg'); |
@@ -738,11 +746,6 @@ | @@ -738,11 +746,6 @@ | ||
738 | if (slug in this.orbitersElements) { | 746 | if (slug in this.orbitersElements) { |
739 | throw new Error("Second init of " + slug); | 747 | throw new Error("Second init of " + slug); |
740 | } | 748 | } |
741 | - this.extremum = Math.max(this.extremum, 1.11 * d3.max(data, function(d){ | ||
742 | - return Math.max(Math.abs(d.x), Math.abs(d.y)); | ||
743 | - })); | ||
744 | - this.xScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]); | ||
745 | - this.yScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]); | ||
746 | orbit_ellipse = this.plotWrapper.append("svg:ellipse").classed('orbit orbit_ellipse', true); | 749 | orbit_ellipse = this.plotWrapper.append("svg:ellipse").classed('orbit orbit_ellipse', true); |
747 | orbiter = this.plotWrapper.append("svg:image").attr('xlink:href', config['img']).attr('width', '32px').attr('height', '32px'); | 750 | orbiter = this.plotWrapper.append("svg:image").attr('xlink:href', config['img']).attr('width', '32px').attr('height', '32px'); |
748 | orbiter.append('svg:title').text(config.name); | 751 | orbiter.append('svg:title').text(config.name); |
@@ -752,65 +755,122 @@ | @@ -752,65 +755,122 @@ | ||
752 | return this$.yScale(d.x); | 755 | return this$.yScale(d.x); |
753 | }); | 756 | }); |
754 | orbit_section = this.plotWrapper.append('path').datum(data).classed('orbit orbit_section', true); | 757 | orbit_section = this.plotWrapper.append('path').datum(data).classed('orbit orbit_section', true); |
755 | - this.orbiters[slug] = config; | ||
756 | this.data[slug] = data; | 758 | this.data[slug] = data; |
759 | + this.orbiters[slug] = config; | ||
757 | this.orbitersElements[slug] = { | 760 | this.orbitersElements[slug] = { |
758 | orbiter: orbiter, | 761 | orbiter: orbiter, |
759 | orbit_ellipse: orbit_ellipse, | 762 | orbit_ellipse: orbit_ellipse, |
760 | orbit_section: orbit_section, | 763 | orbit_section: orbit_section, |
761 | orbit_line: orbit_line | 764 | orbit_line: orbit_line |
762 | }; | 765 | }; |
763 | - this.resize(); | 766 | + this.orbitersExtrema[slug] = d3.max(data, function(d){ |
767 | + return Math.max(Math.abs(d.x), Math.abs(d.y)); | ||
768 | + }); | ||
764 | $(this.svg.node()).show(); | 769 | $(this.svg.node()).show(); |
770 | + this.resize(true); | ||
765 | return this; | 771 | return this; |
766 | }; | 772 | }; |
773 | + Orbits.prototype.showOrbiter = function(slug){ | ||
774 | + this.orbiters[slug].hidden = false; | ||
775 | + this.orbitersElements[slug].orbiter.style("display", null); | ||
776 | + this.orbitersElements[slug].orbit_ellipse.style("display", null); | ||
777 | + this.orbitersElements[slug].orbit_section.style("display", null); | ||
778 | + return this.resize(true); | ||
779 | + }; | ||
780 | + Orbits.prototype.hideOrbiter = function(slug){ | ||
781 | + this.orbiters[slug].hidden = true; | ||
782 | + this.orbitersElements[slug].orbiter.style("display", "none"); | ||
783 | + this.orbitersElements[slug].orbit_ellipse.style("display", "none"); | ||
784 | + this.orbitersElements[slug].orbit_section.style("display", "none"); | ||
785 | + return this.resize(true); | ||
786 | + }; | ||
767 | Orbits.prototype.clear = function(){ | 787 | Orbits.prototype.clear = function(){ |
768 | return $(this.svg.node()).remove(); | 788 | return $(this.svg.node()).remove(); |
769 | }; | 789 | }; |
770 | - Orbits.prototype.resize = function(){ | ||
771 | - var width, height, slug, ref$, config; | 790 | + Orbits.prototype.resize = function(animate){ |
791 | + var width, height, extremum, s, o, slug, ref$, config, t, t1, this$ = this; | ||
792 | + animate == null && (animate = false); | ||
772 | width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); | 793 | width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); |
773 | height = Math.ceil(1.0 * width); | 794 | height = Math.ceil(1.0 * width); |
774 | console.debug("Resizing orbits : " + width + " × " + height + "…"); | 795 | console.debug("Resizing orbits : " + width + " × " + height + "…"); |
796 | + extremum = 1.1 * d3.max((function(){ | ||
797 | + var ref$, results$ = []; | ||
798 | + for (s in ref$ = this.orbiters) { | ||
799 | + o = ref$[s]; | ||
800 | + if (!o.hidden) { | ||
801 | + results$.push(s); | ||
802 | + } | ||
803 | + } | ||
804 | + return results$; | ||
805 | + }.call(this)), function(d){ | ||
806 | + return this$.orbitersExtrema[d]; | ||
807 | + }); | ||
808 | + this.xScale = d3.scaleLinear().domain([-1 * extremum, extremum]); | ||
809 | + this.yScale = d3.scaleLinear().domain([extremum, -1 * extremum]); | ||
775 | this.xScale.range([0, width]); | 810 | this.xScale.range([0, width]); |
776 | - this.yScale.range([0, height]); | 811 | + this.yScale.range([height, 0]); |
777 | this.svg.attr('width', width + this.margin.right + this.margin.left).attr('height', height + this.margin.top + this.margin.bottom); | 812 | this.svg.attr('width', width + this.margin.right + this.margin.left).attr('height', height + this.margin.top + this.margin.bottom); |
778 | this.sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16); | 813 | this.sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16); |
779 | for (slug in ref$ = this.orbiters) { | 814 | for (slug in ref$ = this.orbiters) { |
780 | config = ref$[slug]; | 815 | config = ref$[slug]; |
781 | - this.resizeOrbiter(slug, config, width, height); | 816 | + this.resizeOrbiter(slug, config, width, height, animate); |
782 | } | 817 | } |
783 | this.xAxis.scale(this.xScale); | 818 | this.xAxis.scale(this.xScale); |
784 | this.yAxis.scale(this.yScale); | 819 | this.yAxis.scale(this.yScale); |
785 | - this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')').call(this.xAxis); | ||
786 | - this.svg.select('.y.axis').call(this.yAxis); | 820 | + this.svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')'); |
821 | + if (animate) { | ||
822 | + t = this.svg.transition().duration(750); | ||
823 | + t1 = this.svg.transition().duration(4750); | ||
824 | + this.svg.select('.x.axis').transition(t).call(this.xAxis); | ||
825 | + this.svg.select('.y.axis').transition(t).call(this.yAxis); | ||
826 | + } else { | ||
827 | + this.svg.select('.x.axis').call(this.xAxis); | ||
828 | + this.svg.select('.y.axis').call(this.yAxis); | ||
829 | + } | ||
787 | this.xAxisTitle.attr("x", width / 2).attr("y", 37); | 830 | this.xAxisTitle.attr("x", width / 2).attr("y", 37); |
788 | this.yAxisTitle.attr("x", -1 * height / 2).attr("y", -30); | 831 | this.yAxisTitle.attr("x", -1 * height / 2).attr("y", -30); |
789 | return this; | 832 | return this; |
790 | }; | 833 | }; |
791 | - Orbits.prototype.resizeOrbiter = function(slug, config, width, height){ | ||
792 | - var el, a, b, c, cx, cy, data; | 834 | + Orbits.prototype.resizeOrbiter = function(slug, config, width, height, animate){ |
835 | + var tt, el, orbit_section, t, a, b, c, cx, cy, orbit_ellipse; | ||
836 | + animate == null && (animate = false); | ||
793 | console.debug("Resizing orbit of " + slug + "…"); | 837 | console.debug("Resizing orbit of " + slug + "…"); |
838 | + tt = this.svg.transition().duration(750); | ||
794 | el = this.orbitersElements[slug]; | 839 | el = this.orbitersElements[slug]; |
795 | - el['orbit_section'].attr('d', el['orbit_line']); | 840 | + orbit_section = el['orbit_section']; |
841 | + if (animate) { | ||
842 | + t = this.svg.transition().duration(750); | ||
843 | + orbit_section = orbit_section.transition(tt); | ||
844 | + } | ||
845 | + orbit_section.attr('d', el['orbit_line']); | ||
796 | a = config['orbit']['a']; | 846 | a = config['orbit']['a']; |
797 | b = config['orbit']['b']; | 847 | b = config['orbit']['b']; |
798 | c = Math.sqrt(a * a - b * b); | 848 | c = Math.sqrt(a * a - b * b); |
799 | cx = width / 2 - c; | 849 | cx = width / 2 - c; |
800 | cy = height / 2; | 850 | cy = height / 2; |
801 | - 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)); | ||
802 | - data = this.data[slug]; | ||
803 | - el['orbiter'].attr('x', this.xScale(data[data.length - 1].y) - 16); | ||
804 | - el['orbiter'].attr('y', this.yScale(data[data.length - 1].x) - 16); | 851 | + orbit_ellipse = el['orbit_ellipse']; |
852 | + if (animate) { | ||
853 | + t = this.svg.transition().duration(750); | ||
854 | + orbit_ellipse = orbit_ellipse.transition(t); | ||
855 | + } | ||
856 | + orbit_ellipse.attr('cx', cx).attr('cy', cy).attr('rx', this.xScale(a) - this.xScale(0)).attr('ry', this.yScale(b) - this.yScale(0)); | ||
857 | + this.repositionOrbiter(slug, null, true); | ||
805 | return this; | 858 | return this; |
806 | }; | 859 | }; |
807 | - Orbits.prototype.repositionOrbiter = function(slug, datum){ | ||
808 | - var data, el; | 860 | + Orbits.prototype.repositionOrbiter = function(slug, datum, animate){ |
861 | + var data, el, t; | ||
862 | + animate == null && (animate = false); | ||
809 | data = this.data[slug]; | 863 | data = this.data[slug]; |
864 | + datum == null && (datum = this.lastOrbiterData[slug]); | ||
810 | datum == null && (datum = data[data.length - 1]); | 865 | datum == null && (datum = data[data.length - 1]); |
811 | - el = this.orbitersElements[slug]; | ||
812 | - el['orbiter'].attr('x', this.xScale(datum.y) - 16); | ||
813 | - el['orbiter'].attr('y', this.yScale(datum.x) - 16); | 866 | + this.lastOrbiterData[slug] = datum; |
867 | + el = this.orbitersElements[slug]['orbiter']; | ||
868 | + if (animate) { | ||
869 | + t = this.svg.transition().duration(750); | ||
870 | + el = el.transition(t); | ||
871 | + } | ||
872 | + el.attr('x', this.xScale(datum.y) - 16); | ||
873 | + el.attr('y', this.yScale(datum.x) - 16); | ||
814 | return this; | 874 | return this; |
815 | }; | 875 | }; |
816 | Orbits.prototype.bisectDate = d3.bisector(function(d){ | 876 | Orbits.prototype.bisectDate = d3.bisector(function(d){ |
web/static/js/swapp.ls
@@ -128,11 +128,13 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -128,11 +128,13 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
128 | enableTarget: (target_slug) -> | 128 | enableTarget: (target_slug) -> |
129 | @time_series.forEach((ts) ~> ts.show() if ts.target.slug == target_slug && @parameters[ts.parameter].active) | 129 | @time_series.forEach((ts) ~> ts.show() if ts.target.slug == target_slug && @parameters[ts.parameter].active) |
130 | @targets[target_slug].active = true | 130 | @targets[target_slug].active = true |
131 | + @orbits?.showOrbiter target_slug | ||
131 | this | 132 | this |
132 | 133 | ||
133 | disableTarget: (target_slug) -> | 134 | disableTarget: (target_slug) -> |
134 | @time_series.forEach((ts) -> ts.hide() if ts.target.slug == target_slug) | 135 | @time_series.forEach((ts) -> ts.hide() if ts.target.slug == target_slug) |
135 | @targets[target_slug].active = false | 136 | @targets[target_slug].active = false |
137 | + @orbits?.hideOrbiter target_slug | ||
136 | this | 138 | this |
137 | 139 | ||
138 | resize: -> | 140 | resize: -> |
@@ -656,10 +658,11 @@ export class Orbits | @@ -656,10 +658,11 @@ export class Orbits | ||
656 | 658 | ||
657 | @data = {} # slug => HEE array | 659 | @data = {} # slug => HEE array |
658 | @orbiters = {} # slug => config | 660 | @orbiters = {} # slug => config |
659 | - @orbitersElements = {} | ||
660 | - @extremum = 1 | ||
661 | - @xScale = d3.scaleLinear().domain([-1 * @extremum, @extremum]) | ||
662 | - @yScale = d3.scaleLinear().domain([@extremum, -1 * @extremum]) | 661 | + @orbitersElements = {} # see initOrbiter |
662 | + @orbitersExtrema = {} # slug => local extrema | ||
663 | + @lastOrbiterData = {} # slug => most recently used datum for position | ||
664 | + @xScale = d3.scaleLinear().domain([-1, 1]) | ||
665 | + @yScale = d3.scaleLinear().domain([1, -1]) | ||
663 | 666 | ||
664 | @xAxis = d3.axisBottom().ticks(10) | 667 | @xAxis = d3.axisBottom().ticks(10) |
665 | @yAxis = d3.axisLeft().ticks(10) | 668 | @yAxis = d3.axisLeft().ticks(10) |
@@ -700,12 +703,6 @@ export class Orbits | @@ -700,12 +703,6 @@ export class Orbits | ||
700 | console.info "Initializing orbit of #{config.name}…" | 703 | console.info "Initializing orbit of #{config.name}…" |
701 | if slug of @orbitersElements then throw new Error("Second init of #{slug}") | 704 | if slug of @orbitersElements then throw new Error("Second init of #{slug}") |
702 | 705 | ||
703 | - @extremum = Math.max(@extremum, 1.11 * d3.max(data, (d) -> | ||
704 | - Math.max(Math.abs(d.x), Math.abs(d.y)) | ||
705 | - )) | ||
706 | - @xScale = d3.scaleLinear().domain([-1 * @extremum, @extremum]) | ||
707 | - @yScale = d3.scaleLinear().domain([-1 * @extremum, @extremum]) | ||
708 | - | ||
709 | # The order is important, as it will define the default z-order | 706 | # The order is important, as it will define the default z-order |
710 | orbit_ellipse = @plotWrapper.append("svg:ellipse") | 707 | orbit_ellipse = @plotWrapper.append("svg:ellipse") |
711 | .classed('orbit orbit_ellipse', true) | 708 | .classed('orbit orbit_ellipse', true) |
@@ -722,31 +719,54 @@ export class Orbits | @@ -722,31 +719,54 @@ export class Orbits | ||
722 | .datum(data) | 719 | .datum(data) |
723 | .classed('orbit orbit_section', true) | 720 | .classed('orbit orbit_section', true) |
724 | 721 | ||
725 | - @orbiters[slug] = config | ||
726 | @data[slug] = data | 722 | @data[slug] = data |
723 | + @orbiters[slug] = config | ||
727 | @orbitersElements[slug] = | 724 | @orbitersElements[slug] = |
728 | orbiter: orbiter | 725 | orbiter: orbiter |
729 | orbit_ellipse: orbit_ellipse | 726 | orbit_ellipse: orbit_ellipse |
730 | orbit_section: orbit_section | 727 | orbit_section: orbit_section |
731 | orbit_line: orbit_line | 728 | orbit_line: orbit_line |
732 | - | ||
733 | - @resize() | 729 | + @orbitersExtrema[slug] = d3.max(data, (d) -> |
730 | + Math.max(Math.abs(d.x), Math.abs(d.y)) | ||
731 | + ) | ||
734 | 732 | ||
735 | $(@svg.node()).show(); | 733 | $(@svg.node()).show(); |
736 | 734 | ||
735 | + @resize(true) | ||
736 | + | ||
737 | this | 737 | this |
738 | 738 | ||
739 | + showOrbiter: (slug) -> | ||
740 | + @orbiters[slug].hidden = false | ||
741 | + @orbitersElements[slug].orbiter.style("display", null) | ||
742 | + @orbitersElements[slug].orbit_ellipse.style("display", null) | ||
743 | + @orbitersElements[slug].orbit_section.style("display", null) | ||
744 | + @resize(true) | ||
745 | + | ||
746 | + hideOrbiter: (slug) -> | ||
747 | + @orbiters[slug].hidden = true | ||
748 | + @orbitersElements[slug].orbiter.style("display", "none") | ||
749 | + @orbitersElements[slug].orbit_ellipse.style("display", "none") | ||
750 | + @orbitersElements[slug].orbit_section.style("display", "none") | ||
751 | + @resize(true) | ||
752 | + | ||
739 | clear: -> | 753 | clear: -> |
740 | $(@svg.node()).remove() | 754 | $(@svg.node()).remove() |
741 | 755 | ||
742 | - resize: -> | 756 | + resize: (animate = false) -> |
743 | width = Math.ceil($(@container).width() - @margin.left - @margin.right) | 757 | width = Math.ceil($(@container).width() - @margin.left - @margin.right) |
744 | height = Math.ceil(1.0 * width) | 758 | height = Math.ceil(1.0 * width) |
745 | 759 | ||
746 | console.debug("Resizing orbits : #{width} × #{height}…") | 760 | console.debug("Resizing orbits : #{width} × #{height}…") |
747 | 761 | ||
762 | + extremum = 1.1 * d3.max([s for s, o of @orbiters when not o.hidden], (d) ~> | ||
763 | + @orbitersExtrema[d] | ||
764 | + ) | ||
765 | + @xScale = d3.scaleLinear().domain([-1 * extremum, extremum]) | ||
766 | + @yScale = d3.scaleLinear().domain([extremum, -1 * extremum]) | ||
767 | + | ||
748 | @xScale.range([0, width]) | 768 | @xScale.range([0, width]) |
749 | - @yScale.range([0, height]) | 769 | + @yScale.range([height, 0]) |
750 | 770 | ||
751 | @svg.attr('width', width + @margin.right + @margin.left) | 771 | @svg.attr('width', width + @margin.right + @margin.left) |
752 | .attr('height', height + @margin.top + @margin.bottom) | 772 | .attr('height', height + @margin.top + @margin.bottom) |
@@ -754,17 +774,20 @@ export class Orbits | @@ -754,17 +774,20 @@ export class Orbits | ||
754 | @sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16) | 774 | @sun.attr("x", width / 2 - 16).attr("y", height / 2 - 16) |
755 | 775 | ||
756 | for slug, config of @orbiters | 776 | for slug, config of @orbiters |
757 | - @resizeOrbiter(slug, config, width, height) | 777 | + @resizeOrbiter(slug, config, width, height, animate) |
758 | 778 | ||
759 | @xAxis.scale(@xScale) | 779 | @xAxis.scale(@xScale) |
760 | @yAxis.scale(@yScale) | 780 | @yAxis.scale(@yScale) |
761 | 781 | ||
762 | - @svg.select('.x.axis') | ||
763 | - .attr('transform', 'translate(0,' + height + ')') | ||
764 | - .call(@xAxis) | ||
765 | - | ||
766 | - @svg.select('.y.axis') | ||
767 | - .call(@yAxis) | 782 | + @svg.select('.x.axis').attr('transform', 'translate(0,' + height + ')') |
783 | + if animate | ||
784 | + t = @svg.transition().duration(750) | ||
785 | + t1 = @svg.transition().duration(4750) | ||
786 | + @svg.select('.x.axis').transition(t).call(@xAxis); | ||
787 | + @svg.select('.y.axis').transition(t).call(@yAxis); | ||
788 | + else | ||
789 | + @svg.select('.x.axis').call(@xAxis) | ||
790 | + @svg.select('.y.axis').call(@yAxis) | ||
768 | 791 | ||
769 | @xAxisTitle.attr("x", width / 2) | 792 | @xAxisTitle.attr("x", width / 2) |
770 | .attr("y", 37) | 793 | .attr("y", 37) |
@@ -773,35 +796,49 @@ export class Orbits | @@ -773,35 +796,49 @@ export class Orbits | ||
773 | 796 | ||
774 | this | 797 | this |
775 | 798 | ||
776 | - resizeOrbiter: (slug, config, width, height) -> | 799 | + resizeOrbiter: (slug, config, width, height, animate = false) -> |
777 | console.debug("Resizing orbit of #{slug}…") | 800 | console.debug("Resizing orbit of #{slug}…") |
778 | 801 | ||
802 | + tt = @svg.transition().duration(750) | ||
779 | el = @orbitersElements[slug] | 803 | el = @orbitersElements[slug] |
780 | - el['orbit_section'].attr('d', el['orbit_line']) | 804 | + orbit_section = el['orbit_section'] |
805 | + if animate | ||
806 | + t = @svg.transition().duration(750) | ||
807 | + orbit_section = orbit_section.transition(tt) | ||
808 | + orbit_section.attr('d', el['orbit_line']) | ||
781 | 809 | ||
782 | a = config['orbit']['a'] | 810 | a = config['orbit']['a'] |
783 | b = config['orbit']['b'] | 811 | b = config['orbit']['b'] |
784 | c = Math.sqrt(a*a - b*b) | 812 | c = Math.sqrt(a*a - b*b) |
785 | cx = (width / 2) - c | 813 | cx = (width / 2) - c |
786 | cy = (height / 2) | 814 | cy = (height / 2) |
787 | - el['orbit_ellipse'].attr('cx', cx).attr('cy', cy) | 815 | + |
816 | + orbit_ellipse = el['orbit_ellipse'] | ||
817 | + if animate | ||
818 | + t = @svg.transition().duration(750) | ||
819 | + orbit_ellipse = orbit_ellipse.transition(t) | ||
820 | + # These ellipses ain't worth much | ||
821 | + # Maybe a simple circle whose radius is the mean radius of the orbit ? | ||
822 | + orbit_ellipse.attr('cx', cx).attr('cy', cy) | ||
788 | .attr('rx', @xScale(a) - @xScale(0)) | 823 | .attr('rx', @xScale(a) - @xScale(0)) |
789 | .attr('ry', @yScale(b) - @yScale(0)) | 824 | .attr('ry', @yScale(b) - @yScale(0)) |
790 | # .attr('transform', 'rotate(66,'+(cx+c)+', '+cy+')') | 825 | # .attr('transform', 'rotate(66,'+(cx+c)+', '+cy+')') |
791 | 826 | ||
792 | - data = @data[slug] | ||
793 | - | ||
794 | - el['orbiter'].attr('x', @xScale(data[data.length - 1].y) - 16) | ||
795 | - el['orbiter'].attr('y', @yScale(data[data.length - 1].x) - 16) | 827 | + @repositionOrbiter(slug, null, true) |
796 | 828 | ||
797 | this | 829 | this |
798 | 830 | ||
799 | - repositionOrbiter: (slug, datum) -> | 831 | + repositionOrbiter: (slug, datum, animate = false) -> |
800 | data = @data[slug] | 832 | data = @data[slug] |
833 | + datum ?= @lastOrbiterData[slug] | ||
801 | datum ?= data[data.length - 1] | 834 | datum ?= data[data.length - 1] |
802 | - el = @orbitersElements[slug] | ||
803 | - el['orbiter'].attr('x', @xScale(datum.y) - 16) | ||
804 | - el['orbiter'].attr('y', @yScale(datum.x) - 16) | 835 | + @lastOrbiterData[slug] = datum |
836 | + el = @orbitersElements[slug]['orbiter'] | ||
837 | + if animate | ||
838 | + t = @svg.transition().duration(750) | ||
839 | + el = el.transition(t) | ||
840 | + el.attr('x', @xScale(datum.y) - 16) | ||
841 | + el.attr('y', @yScale(datum.x) - 16) | ||
805 | this | 842 | this |
806 | 843 | ||
807 | bisectDate: d3.bisector((d) -> d.t).left | 844 | bisectDate: d3.bisector((d) -> d.t).left |