diff --git a/src/app/charts/line-graph.component.ts b/src/app/charts/line-graph.component.ts index 4a143674..b259a9af 100644 --- a/src/app/charts/line-graph.component.ts +++ b/src/app/charts/line-graph.component.ts @@ -40,14 +40,12 @@ export class LineGraphComponent implements OnInit, OnDestroy { private yScale; // D3 scale in Y private htmlElement; // Host HTMLElement private valueline; // Base for a chart line - private xRange: Array; // Min, max date range + private xRange: Array; // Min, max date range private xData: Array; // Stores x axis data as integers rather than dates, necessary for trendline math private yData: Array; // Stores primary y axis data, multi-use - private trendData: Array; // Formatted data for the trendline + private timeFormat: string; // Date formatting for x axis labels (e.g, '%Y-%m') private scrubber; // Lump of scrubber elements private scrubberLine; // Scrubber element, independent - private timeOptions: any; - private timeFormat: string; private id: string; // Randomly generated int # used to distinguish the chart for drawing and isolated chart scrubber // Not a perfect solution should the random int and indicator be the same // However, this is quite unlikely (1/10000, and even less likely by way of app use) @@ -61,10 +59,6 @@ export class LineGraphComponent implements OnInit, OnDestroy { constructor(private element: ElementRef, private chartService: ChartService) { this.htmlElement = this.element.nativeElement; this.host = D3.select(this.element.nativeElement); - this.timeOptions = { - 'yearly': '%Y', - 'daily': '%Y-%m-%d' - } } @HostListener('window:resize', ['$event']) @@ -129,16 +123,12 @@ export class LineGraphComponent implements OnInit, OnDestroy { private filterData(): void { // Preserves parent data by fresh copying indicator data that will undergo processing let clippedData = _.cloneDeep(_.find(this.data, obj => obj.indicator.name === this.indicator.name)); - if (clippedData) { - this.timeFormat = this.timeOptions[clippedData.time_agg]; - } _.has(clippedData, 'data') ? this.extractedData = clippedData['data'] : this.extractedData = []; // Remove empty day in non-leap years (affects only daily data) if (this.extractedData[365] && this.extractedData[365]['date'] == null) { this.extractedData.pop(); } - // Parse out avg data for ease of use later - this.yData = _.map(this.extractedData, d => d.values.avg); + this.timeFormat = clippedData.time_format; } /* Will setup the chart basics */ @@ -163,9 +153,11 @@ export class LineGraphComponent implements OnInit, OnDestroy { // Set axis and line scales private setLineScales(): void { - // Time scales only recognize annual and daily data - var parseTime = D3.timeParse(this.timeFormat); - this.extractedData.forEach(d => d.date = parseTime(d.date)); + // Sort data by date ascending + this.extractedData.sort(function(a, b) {return +a.date - +b.date;}); + // Parse out avg data for ease of use later + this.yData = _.map(this.extractedData, d => d.values.avg); + this.xRange = D3.extent(this.extractedData, d => d.date); this.xScale.domain(this.xRange); @@ -249,9 +241,9 @@ export class LineGraphComponent implements OnInit, OnDestroy { var y1 = leastSquaresCoeff[0] + leastSquaresCoeff[1]; var x2 = this.xRange[0]; var y2 = leastSquaresCoeff[0] * this.xData.length + leastSquaresCoeff[1]; - this.trendData = [{'date': x1, 'value': y2}, {'date': x2, 'value': y1}]; + let trendData = [{'date': x1, 'value': y2}, {'date': x2, 'value': y1}]; // Add trendline - this.drawLine(this.trendData, 'trendline'); + this.drawLine(trendData, 'trendline'); } } diff --git a/src/app/models/chart.ts b/src/app/models/chart.ts index 30959669..9c3561a3 100644 --- a/src/app/models/chart.ts +++ b/src/app/models/chart.ts @@ -34,18 +34,19 @@ export class ChartData { indicator: string; data: MultiDataPoint[]; time_agg: string[]; + time_format: string; } export class DataPoint { - date: string; - value: number; + date: Date; + value: number; } export class MultiDataPoint { - date: string; + date: Date; values: { - 'avg': Number, - 'min': Number, - 'max': Number + 'avg': number, + 'min': number, + 'max': number }; } \ No newline at end of file diff --git a/src/app/services/chart.service.ts b/src/app/services/chart.service.ts index 27df96ee..aeb2c0c4 100644 --- a/src/app/services/chart.service.ts +++ b/src/app/services/chart.service.ts @@ -5,6 +5,7 @@ import { ChartData, MultiDataPoint } from '../models/chart'; import * as moment from 'moment'; import * as _ from 'lodash'; +import * as D3 from 'd3'; /* * Chart Service @@ -19,6 +20,13 @@ export class ChartService { public multiChartScrubberInfoObservable = this._multiChartScrubberInfo.asObservable(); public multiChartScrubberHoverObservable = this._multiChartScrubberHover.asObservable(); + + private timeOptions = { + 'yearly': '%Y', + 'daily': '%Y-%m-%d', + 'monthly': '%Y-%m' + }; + constructor() {} // receive and ship mousemove event @@ -51,9 +59,12 @@ export class ChartService { _.each(data, obj => { let indicatorData: MultiDataPoint[] = []; let indicator = obj.indicator; + let timeFormat = this.timeOptions[indicator.time_aggregation]; + let parseTime = D3.timeParse(timeFormat); + _.each(obj.data, (values, key) => { indicatorData.push({ - 'date': key, + 'date': parseTime(key), 'values': values } as MultiDataPoint); }); @@ -63,7 +74,8 @@ export class ChartService { chartData.push({ 'indicator': indicator, 'data': indicatorData, - 'time_agg': indicator.time_aggregation + 'time_agg': indicator.time_aggregation, + 'time_format': timeFormat } as ChartData); } });