Skip to content

Commit

Permalink
Merge pull request #180 from Northeastern-Electric-Racing/#178-graph-…
Browse files Browse the repository at this point in the history
…resizing

#178 - Graph Resizing
  • Loading branch information
RChandler234 authored Sep 14, 2024
2 parents c5e5fd5 + f0cd163 commit 6282e57
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,6 @@ export class AccelerationGraphs implements OnInit {
y: y1
});

//limits the data storage to 400 to prevent lag
if (this.xData.length > this.maxDataPoints) {
this.xData = this.xData.slice(1);
}

if (this.yData.length > this.maxDataPoints) {
this.yData = this.yData.slice(1);
}

//checks if there is a new max
this.xMax = Math.max(Math.abs(x1), this.xMax);
this.yMax = Math.max(Math.abs(y1), this.yMax);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import { GraphData } from 'src/utils/types.utils';
})
export default class AccelerationOverTimeDisplay {
data: GraphData[] = [];
maxDataPoints = 100;

constructor(private storage: Storage) {}

ngOnInit() {
this.storage.get(IdentifierDataType.ACCELERATION).subscribe((value) => {
this.data.push({ x: new Date().getTime(), y: parseInt(value.values[0]) });
if (this.data.length > 100) {
this.data.shift();
}
});
}
}
67 changes: 38 additions & 29 deletions angular-client/src/components/graph/graph.component.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import { Component, Input, OnInit } from '@angular/core';
import * as ApexCharts from 'apexcharts';
import {
ApexAxisChartSeries,
ApexXAxis,
ApexDataLabels,
ApexChart,
ApexMarkers,
ApexGrid,
ApexTooltip,
ApexFill
} from 'ng-apexcharts';
import { ApexXAxis, ApexDataLabels, ApexChart, ApexMarkers, ApexGrid, ApexTooltip, ApexFill } from 'ng-apexcharts';
import { DialogService } from 'primeng/dynamicdialog';
import { GraphDialog } from '../graph-dialog/graph-dialog.component';
import { GraphData } from 'src/utils/types.utils';

type ChartOptions = {
series: ApexAxisChartSeries;
chart: ApexChart;
xaxis: ApexXAxis;
yaxis: ApexYAxis;
Expand All @@ -38,14 +28,12 @@ export class GraphComponent implements OnInit {
@Input() color!: string; // Must be hex
@Input() title?: string;
@Input() graphContainerId!: string;
@Input({ required: false }) timeRangeSec!: number;
options!: ChartOptions;
chart!: ApexCharts;
series: ApexAxisChartSeries = [
{
name: this.title,
data: []
}
];
timeDiffMs: number = 0;
isSliding: boolean = false;
timeRangeMs: number = 120000; // 2 minutes in ms

constructor(public dialogService: DialogService) {}

Expand All @@ -61,23 +49,37 @@ export class GraphComponent implements OnInit {
};

updateChart = () => {
this.series[0].data = this.data;
this.chart.updateSeries(this.series);
this.chart.updateSeries([
{
name: 'Data Series',
data: Array.from(this.data)
}
]);

if (!this.isSliding && this.data.length > 2) {
this.timeDiffMs = this.data[this.data.length - 1].x - this.data[0].x;
}

if (!this.isSliding && this.timeDiffMs > this.timeRangeMs) {
this.isSliding = true;
this.chart.updateOptions({
...this.options,
xaxis: {
...this.options.xaxis,
range: this.timeRangeMs
}
});
}

setTimeout(() => {
this.updateChart();
}, 1000);
}, 800);
};

ngOnInit(): void {
this.series = [
{
name: this.title,
data: this.data
}
];
this.timeRangeMs = (this.timeRangeSec ?? 120) * 1000;

this.options = {
series: [],
chart: {
id: 'graph',
type: 'line',
Expand Down Expand Up @@ -116,7 +118,14 @@ export class GraphComponent implements OnInit {
colors: '#FFFFFF'
},
formatter: (value) => {
return '' + new Date(value).getHours() + ':' + new Date(value).getMinutes() + ':' + new Date(value).getSeconds();
return (
'' +
new Date(value).getHours() +
':' +
((new Date(value).getMinutes() < 10 ? '0' : '') + new Date(value).getMinutes()) +
':' +
((new Date(value).getSeconds() < 10 ? '0' : '') + new Date(value).getSeconds())
);
}
},
axisBorder: {
Expand Down Expand Up @@ -163,7 +172,7 @@ export class GraphComponent implements OnInit {
return;
}

this.chart = new ApexCharts(chartContainer, this.options);
this.chart = new ApexCharts(chartContainer, { series: [{ data: [] }], ...this.options });

this.chart.render();
this.updateChart();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@ import { GraphData } from 'src/utils/types.utils';
})
export default class SpeedOverTimeDisplay implements OnInit {
data: GraphData[] = [];
maxDataPoints = 100;

constructor(private storage: Storage) {}
ngOnInit() {
this.storage.get(IdentifierDataType.SPEED).subscribe((value) => {
this.data.push({ x: new Date().getTime(), y: parseInt(value.values[0]) });
if (this.data.length > 100) {
this.data.shift();
}
});
}
}
4 changes: 2 additions & 2 deletions angular-client/src/pages/graph-page/graph-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export default class GraphPage implements OnInit {
this.clearDataType = () => {
if (this.subscription) this.subscription.unsubscribe();
this.selectedDataType.next({ name: '', unit: '' });
this.selectedDataTypeValuesSubject.next([]);
this.selectedDataTypeValuesSubject = new BehaviorSubject<GraphData[]>([]);
};

this.setSelectedDataType = (dataType: DataType) => {
this.selectedDataType.next(dataType);
this.selectedDataTypeValuesSubject.next([]);
this.selectedDataTypeValuesSubject = new BehaviorSubject<GraphData[]>([]);
if (this.realTime) {
if (this.subscription) this.subscription.unsubscribe();
const key = dataType.name;
Expand Down
110 changes: 76 additions & 34 deletions angular-client/src/pages/graph-page/graph/graph.component.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import * as ApexCharts from 'apexcharts';
import {
ApexAxisChartSeries,
ApexXAxis,
ApexDataLabels,
ApexChart,
ApexMarkers,
ApexGrid,
ApexTooltip,
ApexFill
} from 'ng-apexcharts';
import { ApexXAxis, ApexDataLabels, ApexChart, ApexMarkers, ApexGrid, ApexTooltip, ApexFill } from 'ng-apexcharts';
import { BehaviorSubject } from 'rxjs';
import { convertUTCtoLocal } from 'src/utils/pipes.utils';
import { GraphData } from 'src/utils/types.utils';

type ChartOptions = {
series: ApexAxisChartSeries;
chart: ApexChart;
xaxis: ApexXAxis;
yaxis: ApexYAxis;
Expand All @@ -32,38 +21,55 @@ type ChartOptions = {
templateUrl: './graph.component.html',
styleUrls: ['./graph.component.css']
})
export default class Graph implements OnInit {
export default class Graph implements OnChanges {
@Input() valuesSubject!: BehaviorSubject<GraphData[]>;
options!: ChartOptions;
chart!: ApexCharts;
previousDataLength: number = 0;
series: ApexAxisChartSeries = [
{
name: 'Data Series',
data: []
}
];
data!: Map<number, number>;
timeDiffMs: number = 0;
isSliding: boolean = false;
timeRangeMs = 120000;

updateChart = () => {
if (this.previousDataLength !== this.series[0].data.length) {
this.previousDataLength = this.series[0].data.length;
this.chart.updateSeries(this.series);
if (this.previousDataLength !== Array.from(this.data).length) {
this.previousDataLength = Array.from(this.data).length;
this.chart.updateSeries([
{
name: 'Data Series',
data: Array.from(this.data)
}
]);

if (!this.isSliding && this.timeDiffMs > this.timeRangeMs) {
this.isSliding = true;
this.chart.updateOptions({
...this.options,
xaxis: {
...this.options.xaxis,
range: this.timeRangeMs
}
});
}
}
setTimeout(() => {
this.updateChart();
}, 1000);
}, 800);
};

ngOnInit(): void {
this.data = new Map();
this.valuesSubject.subscribe((values: GraphData[]) => {
const mappedValues = values.map((value: GraphData) => [convertUTCtoLocal(value.x), +value.y.toFixed(3)]);
const newSeries = [
{
name: 'Data Series',
data: mappedValues
values.forEach((value) => {
if (!this.data.has(value.x)) {
this.data.set(value.x, +value.y.toFixed(3));
}
];
this.series = newSeries;
});

if (!this.isSliding) {
const times = Array.from(this.data.keys());
this.timeDiffMs = times[times.length - 1] - times[0];
}
});

const chartContainer = document.getElementById('chart-container');
Expand All @@ -73,7 +79,6 @@ export default class Graph implements OnInit {
}

this.options = {
series: [],
chart: {
id: 'graph',
type: 'line',
Expand All @@ -99,11 +104,21 @@ export default class Graph implements OnInit {
size: 0
},
xaxis: {
type: 'datetime',
type: 'category',
tickAmount: 6,
labels: {
style: {
colors: '#fff'
},
formatter: (value) => {
return (
'' +
new Date(value).getHours() +
':' +
((new Date(value).getMinutes() < 10 ? '0' : '') + new Date(value).getMinutes()) +
':' +
((new Date(value).getSeconds() < 10 ? '0' : '') + new Date(value).getSeconds())
);
}
}
},
Expand Down Expand Up @@ -136,10 +151,37 @@ export default class Graph implements OnInit {

// Weird rendering stuff with apex charts, view link to see why https://github.com/apexcharts/react-apexcharts/issues/187
setTimeout(() => {
this.chart = new ApexCharts(chartContainer, this.options);
this.chart = new ApexCharts(chartContainer, { series: [{ data: [] }], ...this.options });

this.chart.render();
this.updateChart();
}, 0);
}

ngOnChanges(changes: SimpleChanges) {
this.data = new Map();
this.isSliding = false;

//set range to undefined
this.chart.updateOptions({
...this.options,
xaxis: {
...this.options.xaxis,
range: undefined
}
});

this.valuesSubject.subscribe((values: GraphData[]) => {
values.forEach((value) => {
if (!this.data.has(value.x)) {
this.data.set(value.x, +value.y.toFixed(3));
}
});

if (!this.isSliding) {
const times = Array.from(this.data.keys());
this.timeDiffMs = times[times.length - 1] - times[0];
}
});
}
}

0 comments on commit 6282e57

Please sign in to comment.