Average Profit Bar Chart with One Product Line Highlighted in Angular

Using ApexCharts with Angular

This Average Profit Bar Chart with One Product Line Highlighted example wires ApexCharts into Angular through the ng-apexcharts component.

Install it with npm install ng-apexcharts apexcharts, then mount the chart with <apx-chart [series]="series" [chart]="chart"></apx-chart>.

Angular charts guide

This demo uses imperative chart updates. The generated code is a faithful Angular translation: open it in CodeSandbox to run and tweak.

import { Component, AfterViewInit, OnDestroy, ViewChild } from '@angular/core';
import {
  ChartComponent,
  ApexAxisChartSeries,
  ApexNonAxisChartSeries,
  ApexChart,
  ApexXAxis,
  ApexYAxis,
  ApexTitleSubtitle,
  ApexDataLabels,
  ApexStroke,
  ApexFill,
  ApexLegend,
  ApexTooltip,
  ApexMarkers,
  ApexPlotOptions,
  ApexResponsive,
  ApexGrid,
  ApexAnnotations,
  ApexStates,
  ApexTheme,
  NgApexchartsModule,
} from 'ng-apexcharts';

import 'apexcharts/features/highlight-filter';

export type ChartOptions = {
  series?: ApexAxisChartSeries | ApexNonAxisChartSeries;
  chart?: ApexChart;
  xaxis?: ApexXAxis;
  yaxis?: ApexYAxis | ApexYAxis[];
  title?: ApexTitleSubtitle;
  subtitle?: ApexTitleSubtitle;
  dataLabels?: ApexDataLabels;
  stroke?: ApexStroke;
  fill?: ApexFill;
  legend?: ApexLegend;
  tooltip?: ApexTooltip;
  markers?: ApexMarkers;
  plotOptions?: ApexPlotOptions;
  responsive?: ApexResponsive[];
  grid?: ApexGrid;
  annotations?: ApexAnnotations;
  states?: ApexStates;
  theme?: ApexTheme;
  colors?: string[];
  labels?: any;
};

@Component({
  selector: 'app-chart',
  standalone: true,
  imports: [NgApexchartsModule],
  templateUrl: './chart.component.html',
})
export class AppChart implements AfterViewInit, OnDestroy {
  @ViewChild('chart') chart!: ChartComponent;
  private money = (v: any): any => {
        return (v < 0 ? '-$' : '$') + Math.abs(Math.round(v))
      };

  private STORES: any = ['Seattle', 'Denver', 'Austin', 'Chicago', 'Boston', 'Miami'];

  private ALL: any = [42, -18, 31, 24, 12, -9];

  private LINES: any = {
        premium: [
          { x: 'Seattle', y: 42, highlight: 61 },
          { x: 'Denver', y: -18, highlight: -4 },
          { x: 'Austin', y: 31, highlight: 48 },
          { x: 'Chicago', y: 24, highlight: 19 },
          { x: 'Boston', y: 12, highlight: 27 },
          { x: 'Miami', y: -9, highlight: 6 },
        ],
        budget: [
          { x: 'Seattle', y: 42, highlight: 18 },
          { x: 'Denver', y: -18, highlight: -26 },
          { x: 'Austin', y: 31, highlight: 12 },
          { x: 'Chicago', y: 24, highlight: 28 },
          { x: 'Boston', y: 12, highlight: -3 },
          { x: 'Miami', y: -9, highlight: -21 },
        ],
      };

  private seriesFor = (line: any): any => {
        return [
          {
            name: 'Avg profit per order',
            data: line
              ? this.LINES[line]
              : this.STORES.map(function (s, i) {
                  return { x: s, y: this.ALL[i] }
                }),
          },
        ]
      };

  private pickLine = (chart: any, line: any): any => {
        document.querySelectorAll('[data-line]').forEach(function (b) {
          b.classList.toggle('active', b.getAttribute('data-line') === line)
        })
        return chart.updateSeries(this.seriesFor(line))
      };

  private wireLines = (chart: any): any => {
        document.querySelectorAll('[data-line]').forEach(function (b) {
          b.addEventListener('click', function () {
            this.pickLine(chart, b.getAttribute('data-line'))
          })
        })
      };

  public chartOptions: Partial<ChartOptions> = {
          series: this.seriesFor('premium'),
          chart: {
            id: 'profit',
            type: 'bar',
            height: 360,
            toolbar: { show: false },
          },
          colors: ['#0d9488'],
          plotOptions: {
            bar: { horizontal: true, barHeight: '62%', borderRadius: 4 },
          },
          dataLabels: {
            enabled: true,
            formatter: this.money,
          },
          xaxis: {
            labels: { formatter: this.money },
          },
          grid: { xaxis: { lines: { show: true } }, yaxis: { lines: { show: false } } },
          tooltip: {
            y: { formatter: this.money },
          },
        };
  ngAfterViewInit() {
    (window as any).ApexCharts.setLicense('APEX-eyJleHBpcnlEYXRlIjoiMjEyNi0wNy0wNCIsImlzc3VlRGF0ZSI6IjIwMjYtMDctMjgiLCJwbGFuIjoicHJlbWl1bSIsImRvbWFpbnMiOlsiYXBleGNoYXJ0cy5jb20iLCIxMjcuMC4wLjEiLCJsb2NhbGhvc3QiXSwic2lnIjoieVBmb1VCc0Z3TU9ZdUEyaEZkR0I2Y1FtZ0JITUtXcVdJSjB2NVRESXRZbFR3eDJMUmh6R2x0RUc3VXJ4X0s3b25ZMWRZb2Z2VGItN01ydFYyNDVyOWcifQ==');
    this.wireLines(this.chart)

    function pickLine(chart, line) {
          document.querySelectorAll('[data-line]').forEach(function (b) {
            b.classList.toggle('active', b.getAttribute('data-line') === line)
          })
          return this.chart.updateSeries(this.seriesFor(line))
        }
    function wireLines(chart) {
          document.querySelectorAll('[data-line]').forEach(function (b) {
            b.addEventListener('click', () => {
              this.pickLine(chart, b.getAttribute('data-line'))
            })
          })
        }
  }

  ngOnDestroy() {
    // no cleanup needed
  }
}