All files / components/bar-chart bar-chart.component.ts

33.33% Statements 7/21
0% Branches 0/12
16.66% Functions 1/6
35% Lines 7/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94                                                          1x 1x   1x     1x     1x     1x           1x                                                                                            
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  Component,
  DOCUMENT,
  ElementRef,
  inject,
  Input,
  OnChanges,
  ViewChild,
} from '@angular/core';
 
import { IBarChartOptions, TBarChartData } from '../../interfaces/bar-chart.interface';
import { IChartInputChanges } from '../../interfaces/chart-component.interface';
import { D3_CHART_FACTORY } from '../../providers/d3-chart-factory.provider';
import { defaultBarChartConfig } from '../../util/bar-chart.util';
import { AppD3ChartBase } from '../_base/chart.base';
 
type TBarData = TBarChartData;
type TBarOptions = Partial<IBarChartOptions>;
 
/** The bar chart component. */
@Component({
  selector: 'app-bar-chart',
  templateUrl: './bar-chart.component.html',
  styleUrls: ['./bar-chart.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class AppBarChartComponent extends AppD3ChartBase<TBarData, TBarOptions> implements AfterViewInit, OnChanges {
  private readonly doc = inject(DOCUMENT);
 
  private readonly factory = inject(D3_CHART_FACTORY);
 
  /** The chart id. */
  @Input() public chartId = 'bar-0';
 
  /** The chart data. */
  @Input() public data: TBarData = [];
 
  /** The chart options. */
  @Input() public options: TBarOptions = {};
 
  /** D3 chart view child reference. */
  @ViewChild('container') public readonly container?: ElementRef<HTMLDivElement>;
 
  constructor() {
    super();
  }
 
  /** The chart options constructor. */
  protected chartOptions(): TBarOptions {
    const bodyWidthAdjustment = 10;
    const width = Math.min(
      this.options.width ?? defaultBarChartConfig.width,
      this.doc.body.clientWidth - defaultBarChartConfig.margin.left - defaultBarChartConfig.margin.right - bodyWidthAdjustment,
    );
    const height = Math.min(
      this.options.height ?? width,
      this.doc.body.clientWidth - defaultBarChartConfig.margin.top - defaultBarChartConfig.margin.bottom - bodyWidthAdjustment,
    );
    const yAxisTicks = Math.max(...this.data.map(item => item.value));
    const options: TBarOptions = {
      width,
      height,
      yAxisTicks,
      ...this.options,
    };
    return options;
  }
 
  /** Draws the chart. */
  protected drawChart(): void {
    if (typeof this.container !== 'undefined') {
      const options = this.chartOptions();
      this.factory.drawBarChart(this.container, this.data, options);
    }
  }
 
  /** Actually draws the chart after the component view is initialized. */
  public ngAfterViewInit(): void {
    this.drawChart();
  }
 
  /** Redraws the chart on changes. */
  public ngOnChanges(changes: IChartInputChanges): void {
    const data: TBarData = changes.data?.currentValue;
    const options: TBarOptions = changes.options?.currentValue;
    if ((typeof data !== 'undefined' && data !== null) || (typeof options !== 'undefined' && options !== null)) {
      this.drawChart();
    }
  }
}