angular - Line annotation not updating position although update() called - Stack Overflow

admin2025-04-16  4

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.

Share Improve this question edited Feb 3 at 19:03 Sithys asked Feb 3 at 18:24 SithysSithys 3,8018 gold badges36 silver badges68 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 1

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.

转载请注明原文地址:http://anycun.com/QandA/1744756709a87176.html