admin管理员组

文章数量:1422317

I am developing an app using Angular, the case is that when I want to put the fill property inside the ApexChartsOptions it throws an "TypeError: Cannot read properties of undefined (reading 'length')" but I dont know why.

HTML:

<apx-chart
          class="chart"
          [series]="emodChartConfig.routingOverviewSeries"
          [chart]="emodChartConfig.routingOverviewChartOptions.chart"
          [stroke]="emodChartConfig.routingOverviewChartOptions.stroke"
          [tooltip]="emodChartConfig.routingOverviewChartOptions.tooltip"
          [fill]="emodChartConfig.routingOverviewChartOptions.fill"
          [legend]="emodChartConfig.routingOverviewChartOptions.legend"
          [xaxis]="emodChartConfig.overviewXAxis"
          [yaxis]="emodChartConfig.routingOverviewChartOptions.yaxis"
          [plotOptions]="emodChartConfig.routingOverviewChartOptions.plotOptions"
          [dataLabels]="emodChartConfig.routingOverviewChartOptions.dataLabels"
></apx-chart>

TS(Angular):

async loadOverviewData() {
    this.monthlyEMODService.getOverviewMonthlyEMOD().subscribe({
      next: (data) => {
        const categories = data.map((item) => IdToUn[item.departmentId]);
        const routingData = data.map((item) => item.emod);
        const totalData = data.map((item) => item.pureEMOD);
        const totalBudget = data.map((item) => item.totalBudget);
        const routingBudget = data.map((item) => item.routingBudget);

        this.routingOverviewSeries = [
          {
            name: 'EMOD',
            type: 'column',
            data: [...routingData],
          },
          {
            name: 'Objetivo',
            type: 'line',
            data: [...routingBudget],
          },
        ];

        this.routingOverviewChartOptions = {

          dataLabels: {
            enabled: true,
            enabledOnSeries: [0],
            style: {
              fontSize: '14px',
              fontWeight: 'bold',
              colors: [
                function (opts: any) {
                  
                  const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
                  const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie
                            
                  if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex])
                    return '#00FF00'; // Verde
                  else
                    return '#FF0000'; // Rojo

                },
              ],
            },
          },
          plotOptions: {
            bar: {
              distributed: true,
            },
          },
          fill: {
            colors: [function(opts:any) {
              const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
              const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie
                        
              if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex]) {
                return '#00FF00'; // Verde
              } else {
                return '#FF0000'; // Rojo
              }
            }]
          },
     }

}

As you can see, i have the exact same thing in dataLabels and in the Fill property, however in the Fill property is not working but in the datalabels property it is.

I´ve tried doing a console.log(opts.dataPointIndex); for example and it only gives me: 0 and 1 and then it fails and displays the error in the console, like if the array only had 2 elements. I want to know what am i doing wrong if im literally doing the same thing in both properties.

This is the fetched data:

[
  {
    "departmentId": 1,
    "emod": 64.24,
    "pureEMOD": 59.59,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 70
  },
  {
    "departmentId": 2,
    "emod": 84.25,
    "pureEMOD": 73.05,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 86
  },
  {
    "departmentId": 3,
    "emod": 90.32,
    "pureEMOD": 79.77,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 85,
    "routingBudget": 87
  },
  {
    "departmentId": 4,
    "emod": 75.61,
    "pureEMOD": 67.6,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 87
  },
  {
    "departmentId": 5,
    "emod": 89.03,
    "pureEMOD": 81.18,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 85
  },
  {
    "departmentId": 6,
    "emod": 87.12,
    "pureEMOD": 70.93,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 82
  },
  {
    "departmentId": 7,
    "emod": 79.66,
    "pureEMOD": 70.91,
    "noCEDISEMOD": 91.23,
    "noCEDISPureEMOD": 70.91,
    "totalBudget": 82,
    "routingBudget": 82
  }
]

ApexCharts Fill Documentation

I am developing an app using Angular, the case is that when I want to put the fill property inside the ApexChartsOptions it throws an "TypeError: Cannot read properties of undefined (reading 'length')" but I dont know why.

HTML:

<apx-chart
          class="chart"
          [series]="emodChartConfig.routingOverviewSeries"
          [chart]="emodChartConfig.routingOverviewChartOptions.chart"
          [stroke]="emodChartConfig.routingOverviewChartOptions.stroke"
          [tooltip]="emodChartConfig.routingOverviewChartOptions.tooltip"
          [fill]="emodChartConfig.routingOverviewChartOptions.fill"
          [legend]="emodChartConfig.routingOverviewChartOptions.legend"
          [xaxis]="emodChartConfig.overviewXAxis"
          [yaxis]="emodChartConfig.routingOverviewChartOptions.yaxis"
          [plotOptions]="emodChartConfig.routingOverviewChartOptions.plotOptions"
          [dataLabels]="emodChartConfig.routingOverviewChartOptions.dataLabels"
></apx-chart>

TS(Angular):

async loadOverviewData() {
    this.monthlyEMODService.getOverviewMonthlyEMOD().subscribe({
      next: (data) => {
        const categories = data.map((item) => IdToUn[item.departmentId]);
        const routingData = data.map((item) => item.emod);
        const totalData = data.map((item) => item.pureEMOD);
        const totalBudget = data.map((item) => item.totalBudget);
        const routingBudget = data.map((item) => item.routingBudget);

        this.routingOverviewSeries = [
          {
            name: 'EMOD',
            type: 'column',
            data: [...routingData],
          },
          {
            name: 'Objetivo',
            type: 'line',
            data: [...routingBudget],
          },
        ];

        this.routingOverviewChartOptions = {

          dataLabels: {
            enabled: true,
            enabledOnSeries: [0],
            style: {
              fontSize: '14px',
              fontWeight: 'bold',
              colors: [
                function (opts: any) {
                  
                  const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
                  const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie
                            
                  if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex])
                    return '#00FF00'; // Verde
                  else
                    return '#FF0000'; // Rojo

                },
              ],
            },
          },
          plotOptions: {
            bar: {
              distributed: true,
            },
          },
          fill: {
            colors: [function(opts:any) {
              const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
              const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie
                        
              if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex]) {
                return '#00FF00'; // Verde
              } else {
                return '#FF0000'; // Rojo
              }
            }]
          },
     }

}

As you can see, i have the exact same thing in dataLabels and in the Fill property, however in the Fill property is not working but in the datalabels property it is.

I´ve tried doing a console.log(opts.dataPointIndex); for example and it only gives me: 0 and 1 and then it fails and displays the error in the console, like if the array only had 2 elements. I want to know what am i doing wrong if im literally doing the same thing in both properties.

This is the fetched data:

[
  {
    "departmentId": 1,
    "emod": 64.24,
    "pureEMOD": 59.59,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 70
  },
  {
    "departmentId": 2,
    "emod": 84.25,
    "pureEMOD": 73.05,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 86
  },
  {
    "departmentId": 3,
    "emod": 90.32,
    "pureEMOD": 79.77,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 85,
    "routingBudget": 87
  },
  {
    "departmentId": 4,
    "emod": 75.61,
    "pureEMOD": 67.6,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 87
  },
  {
    "departmentId": 5,
    "emod": 89.03,
    "pureEMOD": 81.18,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 85
  },
  {
    "departmentId": 6,
    "emod": 87.12,
    "pureEMOD": 70.93,
    "noCEDISEMOD": null,
    "noCEDISPureEMOD": null,
    "totalBudget": 82,
    "routingBudget": 82
  },
  {
    "departmentId": 7,
    "emod": 79.66,
    "pureEMOD": 70.91,
    "noCEDISEMOD": 91.23,
    "noCEDISPureEMOD": 70.91,
    "totalBudget": 82,
    "routingBudget": 82
  }
]

ApexCharts Fill Documentation

Share Improve this question asked Mar 14 at 5:24 Fernando HernandezFernando Hernandez 256 bronze badges 2
  • please share the full reproducible stackblitz - reference stackblitz – Naren Murali Commented Mar 14 at 6:32
  • If you erase the [fill] property in the apexchart it will display correctly, otherwise it will show the error in the console. StackBlitz Project @NarenMurali If you need more information, let me know, thanks a lot! – Fernando Hernandez Commented Mar 14 at 15:56
Add a comment  | 

1 Answer 1

Reset to default 1

You are getting this error because the colors property was not specified for stroke property.

This could be a bug I am not sure. But the fix is to apply the same function to the stroke also, so that both will have the same color.

conditionalColor = function (opts: any) {
  const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
  const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie

  if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex]) {
    return '#00FF00'; // Verde
  } else {
    return '#FF0000'; // Rojo
  }
};
...

...  
ngOnInit() {
this.getOverviewMonthlyEMOD().subscribe({
  next: (data: any[]) => {
    this.routingOverviewChartOptions = {
      ...
      stroke: {
        width: [0, 1.5, 2], // Configuración para columnas y líneas
        colors: [this.conditionalColor],
      },
      ...
      fill: {
        colors: [this.conditionalColor],
      },
      ...

Full Code:

import { Component } from '@angular/core';
import {
  ApexChart,
  ApexStroke,
  ApexTooltip,
  ApexLegend,
  ApexPlotOptions,
  ApexYAxis,
  ApexDataLabels,
  ApexAxisChartSeries,
  ApexXAxis,
  ApexFill,
  NgApexchartsModule,
} from 'ng-apexcharts';
import { of } from 'rxjs';

@Component({
  selector: 'app-root',
  imports: [NgApexchartsModule],
  templateUrl: './appponent.html',
  styleUrls: ['./appponent.css'],
})
export class AppComponent {
  public idToUn: { [key: number]: string } = {
    1: 'UN1',
    2: 'UN2',
    3: 'UN3',
    4: 'UN4',
    5: 'UN5',
    6: 'CEDIS',
    7: 'PLANTA',
  };

  getOverviewMonthlyEMOD() {
    return of([
      {
        departmentId: 1,
        emod: 64.24,
        pureEMOD: 59.59,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 82,
        routingBudget: 70,
      },
      {
        departmentId: 2,
        emod: 84.25,
        pureEMOD: 73.05,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 82,
        routingBudget: 86,
      },
      {
        departmentId: 3,
        emod: 90.32,
        pureEMOD: 79.77,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 85,
        routingBudget: 87,
      },
      {
        departmentId: 4,
        emod: 75.61,
        pureEMOD: 67.6,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 82,
        routingBudget: 87,
      },
      {
        departmentId: 5,
        emod: 89.03,
        pureEMOD: 81.18,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 82,
        routingBudget: 85,
      },
      {
        departmentId: 6,
        emod: 87.12,
        pureEMOD: 70.93,
        noCEDISEMOD: null,
        noCEDISPureEMOD: null,
        totalBudget: 82,
        routingBudget: 82,
      },
      {
        departmentId: 7,
        emod: 79.66,
        pureEMOD: 70.91,
        noCEDISEMOD: 91.23,
        noCEDISPureEMOD: 70.91,
        totalBudget: 82,
        routingBudget: 82,
      },
    ]);
  }
  public routingOverviewSeries: ApexAxisChartSeries = [];
  public overviewXAxis: ApexXAxis = { categories: [] };
  public routingOverviewChartOptions: {
    chart: ApexChart;
    stroke: ApexStroke;
    tooltip: ApexTooltip;
    fill: ApexFill;
    legend: ApexLegend;
    plotOptions: ApexPlotOptions;
    yaxis: ApexYAxis;
    dataLabels: ApexDataLabels;
  } = {
    chart: { type: 'line' },
    stroke: {},
    tooltip: {},
    fill: {},
    legend: { show: false },
    plotOptions: { bar: { distributed: true } },
    yaxis: {},
    dataLabels: {},
  };

  conditionalColor = function (opts: any) {
    const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
    const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie

    if (routingData[opts.dataPointIndex] > routingBudget[opts.dataPointIndex]) {
      return '#00FF00'; // Verde
    } else {
      return '#FF0000'; // Rojo
    }
  };
  ngOnInit() {
    this.getOverviewMonthlyEMOD().subscribe({
      next: (data: any[]) => {
        console.log(data);
        const categories = data.map((item) => this.idToUn[item.departmentId]);
        const routingData = data.map((item) => item.emod);
        const totalBudget = data.map((item) => item.totalBudget);
        const routingBudget = data.map((item) => item.routingBudget);

        this.routingOverviewSeries = [
          {
            name: 'EMOD',
            type: 'column',
            data: [...routingData],
          },
          {
            name: 'Objetivo',
            type: 'line',
            data: [...routingBudget],
          },
        ];

        this.overviewXAxis = {
          categories: [...categories],
        };

        this.routingOverviewChartOptions = {
          chart: {
            animations: {
              enabled: false,
            },
            type: 'line', // Tipo principal
            height: '100%', // Altura de la gráfica
            width: '100%', // Ancho de la gráfica
            toolbar: {
              show: true,
              tools: {
                download: true, // Deshabilita la descarga de la gráfica
                selection: false, // Deshabilita la selección de la gráfica
                zoom: false, // Deshabilita el zoom de la gráfica
                zoomin: false, // Deshabilita el zoom in de la gráfica
                zoomout: false, // Deshabilita el zoom out de la gráfica
                pan: false, // Deshabilita el pan de la gráfica
                reset: false, // Deshabilita el reset de la gráfica
              },
              export: {
                png: {
                  filename: 'grafica-emod', // Nombre del archivo
                },
              },
            },
          },
          stroke: {
            width: [0, 1.5, 2], // Configuración para columnas y líneas
            colors: [this.conditionalColor],
          },
          tooltip: {
            enabled: true,
            custom: ({ series, seriesIndex, dataPointIndex, w }) => {
              const serie = series[0]; // Obtiene la serie del EMOD series[1] es el objetivo budget
              const xaxis = w.globals.categoryLabels[dataPointIndex]; // Obtiene las etiquetas del eje X
              const value = serie[dataPointIndex]; // Obtiene el valor real del punto de la serie
              const color =
                value >= totalBudget[dataPointIndex] ? 'green' : 'red'; // Cambia el color según el valor
              const isHistorical = series.length === 3; // Si los datos de la serie son 3 (EMOD, Objetivo, EMOD Año pasado)
              const Actual =
                isHistorical && series[2][dataPointIndex] !== null // Si es histórico y el valor no es nulo
                  ? `<br><span>EMOD Actual: ${series[2][dataPointIndex]}</span>`
                  : '';
              return `
                <div style="padding: 5px; color: white; background-color: ${color}; border-radius: 5px;">
                  <span>${xaxis}</span>
                  <br><span>EMOD${
                    isHistorical && series[2][dataPointIndex] !== null
                      ? ' YTD'
                      : ''
                  }: ${value}</span>
                  ${Actual}
                  <br><span>Objetivo: ${totalBudget[dataPointIndex]}</span>
                </div>
              `;
            },
          },
          legend: {
            show: false,
          },
          plotOptions: {
            bar: {
              distributed: true,
            },
          },
          fill: {
            colors: [this.conditionalColor],
          },
          yaxis: {
            labels: {
              show: false,
            },
          },
          dataLabels: {
            enabled: true,
            enabledOnSeries: [0],
            style: {
              fontSize: '14px',
              fontWeight: 'bold',
              colors: [
                function (opts: any) {
                  const routingBudget = opts.w.config.series[1].data; // Asumiendo que 'Objetivo' es la segunda serie
                  const routingData = opts.w.config.series[0].data; // Asumiendo que 'EMOD' es la primera serie

                  if (
                    routingData[opts.dataPointIndex] >
                    routingBudget[opts.dataPointIndex]
                  )
                    return '#00FF00'; // Verde
                  else return '#FF0000'; // Rojo
                },
              ],
            },
          },
        };
      },
      error: (err) => {
        console.error('Error al cargar los datos de EMOD Mensual', err);
      },
    });
  }
}

Stackblitz Demo

本文标签: