My line annotation is not changing its position although i'm rerendering the chart. I can't figure out how to update the annotation line dynamically.
videolistponent.html
<c-card-body>
<c-chart [data]="chartData" [options]="chartOptions" type="line" (chartRef)="handleChartRef($event)"></c-chart>
</c-card-body>
videolistponent.ts
import { Chart, registerables } from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { ChartjsComponent } from '@coreui/angular-chartjs';
chartData: { labels: number[]; displayLabels: string[]; datasets: { label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; }[] } = {
labels: [], // Für Berechnungen
displayLabels: [], // Für Anzeige auf der X-Achse
datasets: [
{
label: 'Batteriezustand',
data: [] as number[],
borderColor: 'rgba(34,139,34,1)',
backgroundColor: 'rgba(34,139,34,0.2)',
fill: false,
},
{
label: 'Höhe',
data: [] as number[],
borderColor: 'rgba(151,187,205,1)',
backgroundColor: 'rgba(151,187,205,0.2)',
fill: false,
},
{
label: 'Geschwindigkeit',
data: [] as number[],
borderColor: 'rgba(255,99,132,1)',
backgroundColor: 'rgba(255,99,132,0.2)',
fill: false,
}
]
};
private chartRef: any;
ngOnInit(): void {
this.loadData();
Chart.register(...registerables, annotationPlugin);
this.chartOptions = {
responsive: true,
plugins: {
annotation: {
annotations: {
videoMarker: {
type: 'line',
xMin: 0,
xMax: 0,
borderColor: 'red',
borderWidth: 2
}
}
}
},
scales: {
x: {
grid: {
display: false,
drawBorder: false
},
callback: (value: any, index: number) => {
return this.chartData.displayLabels[index] || '';
}
}
},
};
}
....
....
....
loadGraphData(cloudLivestreamMetaId: string): void {
this.graphAvailable = true;
this.videoMetaService.getVideoCloudLivestreamMeta(cloudLivestreamMetaId).subscribe({
next: (metaData: { flightData: { battery: number; date: string; height: number; speed: number }[] }) => {
if (!metaData || !metaData.flightData || metaData.flightData.length === 0) {
return;
}
// Sortiere die Daten nach Zeitstempel
const sortedFlightData = metaData.flightData.sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
const newLabels = sortedFlightData.map(data => new Date(data.date).getTime()); // Zeitstempel
const displayLabels = sortedFlightData.map(data => new Date(data.date).toLocaleTimeString()); // Anzeige
const newBatteryData = sortedFlightData.map(data => data.battery);
const newHeightData = sortedFlightData.map(data => data.height);
const newSpeedData = sortedFlightData.map(data => data.speed);
// Aktualisiere die Chart-Daten
this.chartData = {
labels: newLabels,
displayLabels: displayLabels,
datasets: [
{ ...this.chartData.datasets[0], data: newBatteryData },
{ ...this.chartData.datasets[1], data: newHeightData },
{ ...this.chartData.datasets[2], data: newSpeedData }
]
};
if (this.chartRef) {
this.chartRef.update();
}
this.graphLoaded = true;
setTimeout(() => {
console.log('X-Achse min:', this.chartRef.scales.x.min); // -> 0
console.log('X-Achse max:', this.chartRef.scales.x.max); // -> 181
const marker = this.chartRef.options.plugins.annotation.annotations.videoMarker;
marker.xMin = 110;
marker.xMax = 110;
this.chartRef.update();
}, 5000);
},
error: (error) => {
console.error(error);
}
});
}
So as i'm thinking this is a minimum example i cant get why it isn't working. If i set the xMin to (for example) 91 in ngOnInit the line correctly starts at 91. For testing purposes i setted xMin and xMax directly in my code inside the loadGraphData()
function
Settings xMin
to 70 for example in the ngOnInit()
is working fine. But changing afterwards not.
My line annotation is not changing its position although i'm rerendering the chart. I can't figure out how to update the annotation line dynamically.
videolist.component.html
<c-card-body>
<c-chart [data]="chartData" [options]="chartOptions" type="line" (chartRef)="handleChartRef($event)"></c-chart>
</c-card-body>
videolist.component.ts
import { Chart, registerables } from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { ChartjsComponent } from '@coreui/angular-chartjs';
chartData: { labels: number[]; displayLabels: string[]; datasets: { label: string; data: number[]; borderColor: string; backgroundColor: string; fill: boolean; }[] } = {
labels: [], // Für Berechnungen
displayLabels: [], // Für Anzeige auf der X-Achse
datasets: [
{
label: 'Batteriezustand',
data: [] as number[],
borderColor: 'rgba(34,139,34,1)',
backgroundColor: 'rgba(34,139,34,0.2)',
fill: false,
},
{
label: 'Höhe',
data: [] as number[],
borderColor: 'rgba(151,187,205,1)',
backgroundColor: 'rgba(151,187,205,0.2)',
fill: false,
},
{
label: 'Geschwindigkeit',
data: [] as number[],
borderColor: 'rgba(255,99,132,1)',
backgroundColor: 'rgba(255,99,132,0.2)',
fill: false,
}
]
};
private chartRef: any;
ngOnInit(): void {
this.loadData();
Chart.register(...registerables, annotationPlugin);
this.chartOptions = {
responsive: true,
plugins: {
annotation: {
annotations: {
videoMarker: {
type: 'line',
xMin: 0,
xMax: 0,
borderColor: 'red',
borderWidth: 2
}
}
}
},
scales: {
x: {
grid: {
display: false,
drawBorder: false
},
callback: (value: any, index: number) => {
return this.chartData.displayLabels[index] || '';
}
}
},
};
}
....
....
....
loadGraphData(cloudLivestreamMetaId: string): void {
this.graphAvailable = true;
this.videoMetaService.getVideoCloudLivestreamMeta(cloudLivestreamMetaId).subscribe({
next: (metaData: { flightData: { battery: number; date: string; height: number; speed: number }[] }) => {
if (!metaData || !metaData.flightData || metaData.flightData.length === 0) {
return;
}
// Sortiere die Daten nach Zeitstempel
const sortedFlightData = metaData.flightData.sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
const newLabels = sortedFlightData.map(data => new Date(data.date).getTime()); // Zeitstempel
const displayLabels = sortedFlightData.map(data => new Date(data.date).toLocaleTimeString()); // Anzeige
const newBatteryData = sortedFlightData.map(data => data.battery);
const newHeightData = sortedFlightData.map(data => data.height);
const newSpeedData = sortedFlightData.map(data => data.speed);
// Aktualisiere die Chart-Daten
this.chartData = {
labels: newLabels,
displayLabels: displayLabels,
datasets: [
{ ...this.chartData.datasets[0], data: newBatteryData },
{ ...this.chartData.datasets[1], data: newHeightData },
{ ...this.chartData.datasets[2], data: newSpeedData }
]
};
if (this.chartRef) {
this.chartRef.update();
}
this.graphLoaded = true;
setTimeout(() => {
console.log('X-Achse min:', this.chartRef.scales.x.min); // -> 0
console.log('X-Achse max:', this.chartRef.scales.x.max); // -> 181
const marker = this.chartRef.options.plugins.annotation.annotations.videoMarker;
marker.xMin = 110;
marker.xMax = 110;
this.chartRef.update();
}, 5000);
},
error: (error) => {
console.error(error);
}
});
}
So as i'm thinking this is a minimum example i cant get why it isn't working. If i set the xMin to (for example) 91 in ngOnInit the line correctly starts at 91. For testing purposes i setted xMin and xMax directly in my code inside the loadGraphData()
function
Settings xMin
to 70 for example in the ngOnInit()
is working fine. But changing afterwards not.
Maybe create a new memory reference for the options , so that the chart component triggers a change detection.
setTimeout(() => {
console.log('X-Achse min:', this.chartRef.scales.x.min); // -> 0
console.log('X-Achse max:', this.chartRef.scales.x.max); // -> 181
const marker = this.chartRef.options.plugins.annotation.annotations.videoMarker;
marker.xMin = 110;
marker.xMax = 110;
// this.chartRef.update();
this.chartOptions = { ...this.chartOptions }; // <- changed here!
}, 5000);
The solution was to set the whole chartData another time after setting the new values for the annotation. I don't know why that is working and why @naren muralis example doesn't but it works now for me.