comparison src/app/visualisations/curve/curve.component.ts @ 368:a8a6e8a4ec70

Refactor the curve reshaping stuff to a utility function.
author Lucas Thompson <dev@lucas.im>
date Tue, 30 May 2017 22:15:42 +0100
parents f967cb22a37a
children 3fa0c8cab919
comparison
equal deleted inserted replaced
367:f967cb22a37a 368:a8a6e8a4ec70
10 Input, 10 Input,
11 ViewChild 11 ViewChild
12 } from "@angular/core"; 12 } from "@angular/core";
13 import {VectorFeature} from "piper/HigherLevelUtilities"; 13 import {VectorFeature} from "piper/HigherLevelUtilities";
14 import Waves from 'waves-ui-piper'; 14 import Waves from 'waves-ui-piper';
15 15 import {generatePlotData, PlotLayerData} from "../FeatureUtilities";
16 interface PlotData {
17 cx: number;
18 cy: number;
19 }
20
21 interface PlotLayerData {
22 data: PlotData[];
23 color: string;
24 height: number;
25 yDomain: [number, number];
26 startTime: number;
27 duration: number;
28 }
29 16
30 @Component({ 17 @Component({
31 selector: 'ugly-curve', 18 selector: 'ugly-curve',
32 templateUrl: '../waves-template.html', 19 templateUrl: '../waves-template.html',
33 styleUrls: ['../waves-template.css'], 20 styleUrls: ['../waves-template.css'],
37 24
38 @ViewChild('track') trackDiv: ElementRef; 25 @ViewChild('track') trackDiv: ElementRef;
39 26
40 private mFeature: VectorFeature; 27 private mFeature: VectorFeature;
41 private currentState: PlotLayerData[]; 28 private currentState: PlotLayerData[];
29 private height: number; // As it stands, height is fixed. Store once onInit.
42 30
43 @Input() set feature(input: VectorFeature) { 31 @Input() set feature(input: VectorFeature) {
44 this.mFeature = input; 32 this.mFeature = input;
45 this.currentState = this.generatePlotData([input], '', 'black'); 33 this.currentState = generatePlotData([input]);
46 this.update(); 34 this.update();
47 } 35 }
36 @Input() colour: string;
48 37
49 get feature(): VectorFeature { 38 get feature(): VectorFeature {
50 return this.mFeature; 39 return this.mFeature;
51 } 40 }
52 41
53 ngAfterViewInit(): void { 42 ngAfterViewInit(): void {
43 this.height = this.trackDiv.nativeElement.getBoundingClientRect().height;
54 this.renderTimeline(this.trackDiv); 44 this.renderTimeline(this.trackDiv);
55 this.update(); 45 this.update();
56 } 46 }
57 47
58 update(): void { 48 update(): void {
59 if (this.waveTrack) { 49 if (this.waveTrack) {
60 this.clearTimeline(this.trackDiv); 50 this.clearTimeline(this.trackDiv);
61 for (const feature of this.currentState) { 51 for (const feature of this.currentState) {
62 const lineLayer = new Waves.helpers.LineLayer(feature.data, { 52 const lineLayer = new Waves.helpers.LineLayer(feature.data, {
63 color: feature.color, 53 color: this.colour,
64 height: feature.height, 54 height: this.height,
65 yDomain: feature.yDomain 55 yDomain: feature.yDomain
66 }); 56 });
67 this.addLayer( 57 this.addLayer(
68 lineLayer, 58 lineLayer,
69 this.waveTrack, 59 this.waveTrack,
75 lineLayer.start = feature.startTime; 65 lineLayer.start = feature.startTime;
76 lineLayer.duration = feature.duration; 66 lineLayer.duration = feature.duration;
77 } 67 }
78 } 68 }
79 } 69 }
80
81 private generatePlotData(features: VectorFeature[],
82 unit: string,
83 colour: string): PlotLayerData[] {
84
85 // Winnow out empty features
86 features = features.filter(feature => (feature.data.length > 0));
87
88 // First establish a [min,max] range across all of the features
89 let [min, max] = features.reduce((acc, feature) => {
90 return feature.data.reduce((acc, val) => {
91 const [min, max] = acc;
92 return [Math.min(min, val), Math.max(max, val)];
93 }, acc);
94 }, [Infinity, -Infinity]);
95
96 if (min === Infinity) {
97 min = 0;
98 max = 1;
99 }
100
101 if (min !== min || max !== max) {
102 console.log('WARNING: min or max is NaN');
103 min = 0;
104 max = 1;
105 }
106
107 const height = this.trackDiv.nativeElement.getBoundingClientRect().height;
108 return features.map(feature => {
109 let duration = 0;
110
111 // Give the plot items positions relative to the start of the
112 // line, rather than relative to absolute time 0. This is
113 // because we'll be setting the layer timeline start property
114 // later on and these will be positioned relative to that
115
116 const plotData = [...feature.data].map((val, i) => {
117 const t = i * feature.stepDuration;
118 duration = t + feature.stepDuration;
119 return {
120 cx: t,
121 cy: val
122 };
123 });
124
125 return {
126 data: plotData,
127 color: colour,
128 height: height,
129 yDomain: [min, max] as [number, number],
130 startTime: feature.startTime,
131 duration: duration
132 };
133 });
134 }
135 } 70 }