File

src/app/shared/widgets/charts/time-series-chart/time-series-chart.component.ts

Index

Properties

Properties

name
name: string
Type : string
value
value: string
Type : string
import {
  timer,
  empty,
  combineLatest,
  of,
  Subject,
  Observable,
  Subscription,
} from "rxjs";

import {
  takeUntil,
  debounceTime,
  mergeMap,
  concatMap,
  distinctUntilChanged,
  catchError,
} from "rxjs/operators";
import { Component, OnDestroy } from "@angular/core";
import { getOrDefault, WidgetConfig } from "../../widget.configuration";
import {
  WidgetComponent,
  WidgetId,
  WidgetConfiguration,
  WidgetConfigure,
  WidgetInput,
  WidgetOutput,
} from "../../widget.metadata";
import { WidgetframeService } from "../../widgetframe/widgetframe.service";
import { TranslateService } from "@ngx-translate/core";
import { NgUnsubscribe } from "../../../ng-unsubscribe";
import * as uriTemplates_ from "uri-templates";
import { CurrentLocaleService } from "../../../components/i18n/currentLocale.service";
const uriTemplates = uriTemplates_;

export interface TimeSeriesChartConfiguration {
  header?: string;
  title?: string;
  cssClass?: string;
  showDataLabel?: boolean;
  showXAxis?: boolean;
  showYAxis?: boolean;
  showXAxisLabel?: boolean;
  showYAxisLabel?: boolean;
  showLegend?: boolean;
  colorScheme?: customColor[];
  xAxisInterval?: number;
  infoText?: string;
  infoWidth?: string;
  infoHeight?: string;
  wikiLink?: string;
  legendTitle?: boolean;
  yAxisLabel?: string;
  configurationColors?: customColor[];
  handleError?: boolean;
  chartInterval?: number;
}

@WidgetComponent("nm-time-series-chart")
@Component({
  selector: "nm-time-series-chart",
  templateUrl: "./time-series-chart.component.html",
  styleUrls: ["./time-series-chart.component.scss"],
})
export class TimeSeriesChartWidgetComponent implements OnDestroy {
  public results: any[];
  public header: string;
  public title: string;
  public cssClass: string;
  public showDataLabel: boolean;
  public showXAxis: boolean;
  public showYAxis: boolean;
  public showXAxisLabel: boolean;
  public showYAxisLabel: boolean;
  public showLegend: boolean;
  public xAxisTicks: any[];
  public chartType: string;
  public xAxisInterval: number;
  public xAxisLabel: string;
  public yAxisLabel: string;
  public wikiLink: string;
  public infotext: string;
  public legendTitle: string = "";
  public currentLocale: string;
  public handleError: boolean;
  public customColors: customColor[];
  private configurationColors: customColor[];
  public unitOfMeasurement: string;
  public yAxisLabelsFormat = this.formatNumber.bind(this);
  public chartInterval: number;
  public tooltipShowX: boolean;
  public tooltipShowY: boolean;

  colorScheme = {
    domain: ["#8093c7", "#abc378", "#e57e99", "#ffc699", "#A1B4BC"],
  };

  @WidgetConfiguration()
  public configuration: WidgetConfig<TimeSeriesChartConfiguration>;

  @WidgetInput()
  public chartUri = new Subject<string>();

  @WidgetInput()
  public chartBody = new Subject<any>();

  @WidgetInput()
  public resetChart = new Subject<boolean>();

  @WidgetInput()
  public measurementUnit = new Subject<any>();

  @WidgetInput()
  public customXLabel = new Subject<string>();

  @WidgetInput()
  public selectedUiLocale = new Subject<any>();

  @WidgetOutput()
  public errorHandler = new Subject<string>();

  @WidgetId()
  public widgetId: string;

  private unsubscribe = NgUnsubscribe.create();

  constructor(
    private widgetframeService: WidgetframeService,
    public translateService: TranslateService,
    private currentLocaleService: CurrentLocaleService
  ) {}

  @WidgetConfigure()
  protected configureWidget(configuration: WidgetConfig) {
    this.header = configuration.configuration.header;
    this.title = configuration.configuration.title;
    this.cssClass = configuration.configuration.cssClass || "";
    this.showDataLabel = configuration.configuration.showDataLabel;
    this.showXAxis = configuration.configuration.showXAxis;
    this.showYAxis = configuration.configuration.showYAxis;
    this.showXAxisLabel = configuration.configuration.showXAxisLabel;
    this.showYAxisLabel = configuration.configuration.showYAxisLabel;
    this.showLegend = configuration.configuration.showLegend;
    this.colorScheme = configuration.configuration.customColors
      ? configuration.configuration.customColors
      : this.colorScheme;

    this.xAxisInterval = configuration.configuration.xAxisInterval;
    this.infotext = configuration.configuration.infoText;
    this.wikiLink = configuration.configuration.wikiLink;
    this.legendTitle = configuration.configuration.legendTitle || "";
    this.yAxisLabel = configuration.configuration.yAxisLabel || "";
    this.configurationColors = configuration.configuration.customColorScheme;
    this.handleError = configuration.configuration.handleError;
    this.chartInterval = configuration.configuration.chartInterval || 1000;
    this.tooltipShowX = getOrDefault(
      configuration.configuration.tooltipShowX,
      true
    );
    this.tooltipShowY = getOrDefault(
      configuration.configuration.tooltipShowY,
      false
    );
    this.resetChart
      .asObservable()
      .pipe(takeUntil(this.unsubscribe))
      .subscribe((resetChart) => {
        if (resetChart) {
          this.results = [];
          this.xAxisTicks = [];
        }
      });

    combineLatest(
      timer(this.chartInterval),
      this.chartUri.asObservable(),
      this.chartBody.asObservable(),
      (interval, uri, body) => [uri, body]
    )
      .pipe(takeUntil(this.unsubscribe))
      .pipe(
        debounceTime(5),
        mergeMap((input) => {
          let url = input[0];
          let body = input[1];
          return this.widgetframeService.putData(url, body);
        }),
        catchError((error) => {
          this.handleException(error);
          return empty();
        })
      )
      .subscribe((data) => {
        if (data.message) {
          this.handleException(data.message);
        } else {
          this.populateChart(data);
        }
      });

    combineLatest(
      this.measurementUnit.asObservable(),
      this.currentLocaleService.getCurrentLocale()
    )
      .pipe(takeUntil(this.unsubscribe))
      .subscribe(([data, locale]) => {
        this.currentLocale = locale.toString();
        if (data) {
          this.yAxisLabel = data.unit;
          this.unitOfMeasurement = this.yAxisLabel;
        }
      });

    combineLatest(
      this.customXLabel.asObservable(),
      this.selectedUiLocale.asObservable()
    )
      .pipe(takeUntil(this.unsubscribe))
      .pipe(
        debounceTime(5),
        mergeMap(([customXLabel, selectedUiLocale]) =>
          this.translateService.get(customXLabel)
        )
      )
      .subscribe((label) => {
        this.xAxisLabel = label;
      });
  }

  populateChart(data) {
    this.unitOfMeasurement = data.unit;
    this.yAxisLabel = data.unit;
    this.chartType = data.chartType;
    if (this.configurationColors) {
      this.setCustomColors(data.values);
    }
    if (this.xAxisInterval) {
      this.xAxisTicks = [];
      if (data.values[0].hasOwnProperty("series")) {
        this.setMultipleSeriesChartTicks(data.values);
      } else {
        this.setSingleSeriesChartTicks(data.values);
      }
    } else {
      this.results = data.values;
      this.xAxisTicks = data.xAxisTicks;
    }
  }

  setSingleSeriesChartTicks(values) {
    let resultsLength = values.length;
    let breakpoint = Math.floor(resultsLength / this.xAxisInterval);
    for (let x = 0; x < resultsLength; x += breakpoint) {
      this.xAxisTicks.push(values[x].name);
    }
    this.results = values;
  }

  setMultipleSeriesChartTicks(values) {
    let maxSeriesLength = 0;
    let maxSeriesIndex = 0;
    let breakpoint;
    values.forEach((lineSeries, index) => {
      let resultsLength = lineSeries.series.length;
      if (resultsLength > maxSeriesLength) {
        maxSeriesLength = resultsLength;
        maxSeriesIndex = index;
      }
    });
    breakpoint = Math.floor(maxSeriesLength / this.xAxisInterval);
    this.xAxisTicks = [];
    for (let x = 0; x < maxSeriesLength; x += breakpoint) {
      this.xAxisTicks.push(values[maxSeriesIndex].series[x].name);
    }
    this.results = values;
  }

  setCustomColors(results: any[]) {
    this.customColors = [];
    results.forEach((value) => {
      let customColor = this.configurationColors.find(
        (color) => color.name === value.seriesColorIdentifier
      );
      if (customColor) {
        this.customColors.push({
          name: value.name,
          value: customColor.value,
        });
      }
    });
  }

  formatNumber(number) {
    return number.toLocaleString(this.currentLocale);
  }

  handleException(message: string) {
    this.results = [];
    if (this.handleError) {
      this.errorHandler.next(message);
    }
  }

  ngOnDestroy(): void {
    if (this.unsubscribe) {
      this.unsubscribe.destroy();
    }
  }
}

export interface customColor {
  name: string;
  value: string;
}

results matching ""

    No results matching ""