File

src/app/modules/dashboard/components/data-chart/data-chart.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs
Accessors

Constructor

constructor(resourceService: ResourceService, cdr: ChangeDetectorRef, toasterService: ToasterService, activatedRoute: ActivatedRoute, sanitizer: DomSanitizer, usageService: UsageService, reportService: ReportService, dialog: MatDialog)
Parameters :
Name Type Optional
resourceService ResourceService No
cdr ChangeDetectorRef No
toasterService ToasterService No
activatedRoute ActivatedRoute No
sanitizer DomSanitizer No
usageService UsageService No
reportService ReportService No
dialog MatDialog No

Inputs

chartInfo
Type : any
globalFilter
Type : any
hash
Type : string
hideElements
Type : boolean
Default value : false
isUserReportAdmin
Type : boolean
Default value : false
telemetryInteractObject
Type : IInteractEventObject

Outputs

openAddSummaryModal
Type : EventEmitter

Methods

Public addChartSummary
addChartSummary()
Returns : void
Private calculateBigNumber
calculateBigNumber(chartData)
Parameters :
Name Optional
chartData No
Returns : void
Private calculateGraphStats
calculateGraphStats()
Returns : void
changeChartType
changeChartType(chartType)
Parameters :
Name Optional
chartType No
Returns : void
checkFilterReferance
checkFilterReferance(element)
Parameters :
Name Optional
element No
Returns : boolean
Private checkForExternalChart
checkForExternalChart()
Returns : boolean
checkForStacking
checkForStacking()
Returns : boolean
closeDialog
closeDialog()
Returns : void
Public filterChanged
filterChanged(data: any)
Parameters :
Name Type Optional
data any No
Returns : void
filterModalPopup
filterModalPopup(operator)
Parameters :
Name Optional
operator No
Returns : void
getChartData
getChartData()
Returns : {}
Public getChartSummary
getChartSummary()
Returns : any
Private getData
getData(groupedDataBasedOnLabels, dataExpr, pickTopNElements: number)
Parameters :
Name Type Optional
groupedDataBasedOnLabels No
dataExpr No
pickTopNElements number No
Returns : any
getDataSetValue
getDataSetValue(chartData)
Parameters :
Name Optional Default value
chartData No this.chartData
Returns : void
Private getGoalsDataset
getGoalsDataset(chartData, goalValue: number)
Parameters :
Name Type Optional
chartData No
goalValue number No
Returns : any
getIframeURL
getIframeURL()
Returns : any
Public graphStatsChange
graphStatsChange(data: any)
Parameters :
Name Type Optional
data any No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
openDialog
openDialog()
Returns : void
prepareChart
prepareChart()
Returns : void
refreshChartDataAfterInterval
refreshChartDataAfterInterval(interval)
Parameters :
Name Optional
interval No
Returns : void
resetForm
resetForm()
Returns : void
setTelemetryCdata
setTelemetryCdata()
Returns : void
setTelemetryInteractEdata
setTelemetryInteractEdata(val)
Parameters :
Name Optional
val No
Private sortData
sortData(chartData, labelsExpr)
Parameters :
Name Optional
chartData No
labelsExpr No
Returns : any

Properties

Private _chartSummary
Type : string
Private _globalFilter
Public activatedRoute
Type : ActivatedRoute
alwaysShowCalendars
Type : boolean
availableChartTypeOptions
Type : []
Default value : ['Bar', 'Line']
bigNumberCharts
Type : Array<literal type>
Default value : []
chartCanvas
Decorators :
@ViewChild('chartCanvas')
chartColors
Type : any
chartConfig
Type : any
chartData
Type : any
chartDirective
Type : BaseChartDirective
Decorators :
@ViewChild(BaseChartDirective)
chartLabels
Type : any
Default value : []
chartOptions
Type : any
chartRootElement
Decorators :
@ViewChild('chartRootElement')
chartSummary$
Type : any
chartSummarylabel
Type : string
chartType
Type : any
currentFilters
Type : Array<literal type>
datasets
Type : any
dateFilterReferenceName
dateFilters
Type : Array<string>
datepicker
Type : ElementRef
Decorators :
@ViewChild('datePickerForFilters')
datePickerConfig
Type : any
Default value : { applyLabel: 'Set Date', format: 'DD-MM-YYYY' }
dialogRef
Type : any
filterOpen
Type : Boolean
Default value : false
filterPopup
Type : Boolean
Default value : false
filterPopUpMat
Type : TemplateRef<any>
Decorators :
@ViewChild('filterPopUpMat')
filters
Type : Array<literal type>
filtersSubscription
Type : Subscription
filterType
Type : string
Default value : 'chart-filter'
iframeDetails
Type : any
lastUpdatedOn
Type : any
legend
Type : any
loadash
Default value : _
noResultsFound
Type : Boolean
pickerMaxDate
Type : any
pickerMinDate
Type : any
resetFilters
Public resourceService
Type : ResourceService
resultStatistics
Type : object
Default value : {}
selectedEndDate
Type : any
selectedFilters
Type : literal type
selectedStartDate
Type : any
Private setChartLabels
Default value : () => {...}
showChart
Type : Boolean
Default value : false
showFilters
Type : Boolean
Default value : false
showGraphStats
Type : Boolean
Default value : false
showLastUpdatedOn
Type : Boolean
Default value : false
Private showPercentageInCharts
Default value : () => {...}
showStats
Type : Boolean
Default value : false
telemetryCdata
Type : Array<literal type>
Public unsubscribe
Default value : new Subject<void>()

Accessors

globalFilter
getglobalFilter()
setglobalFilter(val: any)
Parameters :
Name Type Optional
val any No
Returns : void
import { EventEmitter, Output } from '@angular/core';
import { UsageService, ReportService } from './../../services';
import { DomSanitizer } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
import { ResourceService, ToasterService } from '@sunbird/shared';
import { BaseChartDirective } from 'ng2-charts';
import { Component, OnInit, Input, ViewChild, OnDestroy, ElementRef, ChangeDetectorRef, TemplateRef } from '@angular/core';
import * as _ from 'lodash-es';
import { FormBuilder } from '@angular/forms';
import { Subscription, Subject, timer, of } from 'rxjs';
import { map, takeUntil, switchMap } from 'rxjs/operators';
import dayjs from 'dayjs';
import { IInteractEventObject } from '@sunbird/telemetry';
import { IBigNumberChart } from '../../interfaces/chartData';
import { MatDialog } from '@angular/material/dialog';

@Component({
  selector: 'app-data-chart',
  templateUrl: './data-chart.component.html',
  styleUrls: ['./data-chart.component.scss']
})
export class DataChartComponent implements OnInit, OnDestroy {

  @Input() chartInfo: any;
  @Input() telemetryInteractObject: IInteractEventObject;
  @Input() hideElements = false;
  @Input() isUserReportAdmin = false;
  @Output() openAddSummaryModal = new EventEmitter();
  @Input() hash: string;

  @ViewChild('filterPopUpMat') filterPopUpMat: TemplateRef<any>;


 public unsubscribe = new Subject<void>();
 // contains the chart configuration
  chartConfig: any;
  chartData: any;
  chartType: any;
  chartColors: any;
  legend: any;
  chartOptions: any;
  loadash = _;
  datasets: any;
  chartLabels: any = [];
  filters: Array<{}>;
  showFilters: Boolean = false;
  filtersSubscription: Subscription;
  noResultsFound: Boolean;
  showStats: Boolean = false;
  availableChartTypeOptions = ['Bar', 'Line'];
  pickerMinDate: any; // min date that can be selected in the datepicker
  pickerMaxDate: any; // max date that can be selected in datepicker

  selectedStartDate: any;
  selectedEndDate: any;

  datePickerConfig: any = { applyLabel: 'Set Date', format: 'DD-MM-YYYY' };
  alwaysShowCalendars: boolean;

  resultStatistics = {};
  selectedFilters: {};
  dateFilterReferenceName;
  telemetryCdata: Array<{}>;
  showGraphStats: Boolean = false;
  bigNumberCharts: Array<{}> = [];

  iframeDetails: any;
  lastUpdatedOn: any;
  showLastUpdatedOn: Boolean = false;
  showChart: Boolean = false;
  chartSummary$: any;
  private _chartSummary: string;
  private _globalFilter; // private property _item
  resetFilters;
  filterPopup: Boolean = false;
  filterOpen: Boolean = false;
  chartSummarylabel: string;
  currentFilters: Array<{}>;
  @ViewChild('datePickerForFilters') datepicker: ElementRef;
  @ViewChild('chartRootElement') chartRootElement;
  @ViewChild('chartCanvas') chartCanvas;
  filterType = 'chart-filter';
  dateFilters: Array<string>;
  dialogRef: any;

  @ViewChild(BaseChartDirective) chartDirective: BaseChartDirective;
  constructor(public resourceService: ResourceService, private cdr: ChangeDetectorRef,
    private toasterService: ToasterService, public activatedRoute: ActivatedRoute, private sanitizer: DomSanitizer,
    private usageService: UsageService, private reportService: ReportService, private dialog: MatDialog) {
    this.alwaysShowCalendars = true;
  }


  ngOnInit() {

    this.chartConfig = _.get(this.chartInfo, 'chartConfig');
    this.chartData = _.get(this.chartInfo, 'chartData');
    this.chartSummarylabel = 'Add ' + _.get(this.resourceService, 'frmelmnts.lbl.chartSummary');
    if (_.get(this.chartInfo, 'lastUpdatedOn')) {
      this.lastUpdatedOn = dayjs(_.get(this.chartInfo, 'lastUpdatedOn')).format('DD-MMMM-YYYY');
    }

    this.prepareChart();
    this.setTelemetryCdata();
    this.cdr.detectChanges();

  }



  private calculateBigNumber(chartData) {

    const bigNumbersConfig = _.get(this.chartConfig, 'bigNumbers');
    this.bigNumberCharts = [];
    if (bigNumbersConfig && bigNumbersConfig.length) {
      _.forEach(bigNumbersConfig, (config: IBigNumberChart) => {
        const bigNumberChartObj = {};
        if (_.get(config, 'dataExpr')) {
          bigNumberChartObj['header'] = _.get(config, 'header') || '';
          bigNumberChartObj['footer'] = _.get(config, 'footer') || _.get(config, 'dataExpr');
          bigNumberChartObj['data'] =
            (_.round(_.sumBy(chartData, data => _.toNumber( (data && data[_.get(config, 'dataExpr')]) ? data[_.get(config, 'dataExpr')] : 0  )))).toLocaleString('hi-IN');
          this.bigNumberCharts.push(bigNumberChartObj);
        }
      });
    }
  }

  private checkForExternalChart(): boolean {
    const iframeConfig = _.get(this.chartConfig, 'iframeConfig');
    if (iframeConfig) {
      if (_.get(iframeConfig, 'sourceUrl')) {
        return true;
      }
    }
    return false;
  }

  getIframeURL() {
    const url = `${_.get(this.iframeDetails, 'sourceUrl')}?qs=${Math.round(Math.random() * 10000000)}`; // to prevent browser caching
    return this.sanitizer.bypassSecurityTrustResourceUrl(url);
  }

  /**
   * @description show percentage in pie charts
   * @private
   * @memberof DataChartComponent
   */
  private showPercentageInCharts = () => {
    return {
      label: (tooltipItem, data) => {
        const dataset = data.datasets[tooltipItem.datasetIndex];
        const total = dataset.data.reduce((previousValue, currentValue, currentIndex, array) => {
          return previousValue + currentValue;
        });
        const currentVal = dataset.data[tooltipItem.index];
        const percentage = Math.floor(((currentVal / total) * 100) + 0.5);
        return `${data.labels[tooltipItem.index]}: ${currentVal}  ( ${percentage} % )`;
      }
    };
  }

  prepareChart() {
    if (!this.checkForExternalChart()) {

      this.chartOptions = _.get(this.chartConfig, 'options') || { responsive: true };
      this.chartColors = _.get(this.chartConfig, 'colors') || [];
      this.chartType = _.get(this.chartConfig, 'chartType');

      // shows percentage in pie chart if showPercentage config is enabled.
      if (this.chartType === 'pie' && _.get(this.chartOptions, 'showPercentage')) {
        (this.chartOptions.tooltips || (this.chartOptions.tooltips = {})).callbacks = this.showPercentageInCharts();
      }

      this.legend = (_.get(this.chartConfig, 'legend') === false) ? false : true;
      this.showLastUpdatedOn = false;
      this.showChart = false;
      if (_.get(this.chartConfig, 'options.showLastUpdatedOn') || this.lastUpdatedOn) {
        this.showLastUpdatedOn = true;
      }
      if ((_.get(this.chartConfig, 'labelsExpr') || _.get(this.chartConfig, 'labels')) && _.get(this.chartConfig, 'datasets')) {
        this.showChart = true;
      }
      this.showGraphStats = _.get(this.chartOptions, 'showGraphStats') || false;
      this.getDataSetValue();
    } else {
      this.iframeDetails = _.get(this.chartConfig, 'iframeConfig');
    }
    if (_.get(this.chartConfig, 'bigNumbers')) {
      this.calculateBigNumber(this.chartData);
    }
    const refreshInterval = _.get(this.chartConfig, 'options.refreshInterval');
    if (refreshInterval) {
       this.refreshChartDataAfterInterval(refreshInterval);
    }
    this.filters = _.get(this.chartConfig, 'filters') || [];
    this.chartSummary$ = this.getChartSummary();
  }

  refreshChartDataAfterInterval(interval) {
    timer(interval, interval).pipe(
      switchMap(val => {
        return this.usageService.getData(_.head(_.get(this.chartInfo, 'downloadUrl')).path);
      }),
      takeUntil(this.unsubscribe)
    ).subscribe(apiResponse => {
      if (_.get(apiResponse, 'responseCode') === 'OK') {
        const chartData = _.get(apiResponse, 'result.data');
        this.chartData = chartData;
        this.resetFilters = { data: chartData };

      }
    }, err => {
      console.log('failed to update chart data', err);
    });
  }

  private setChartLabels = (groupedDataBasedOnLabels) => {
    let labels = [];
    labels = _.keys(groupedDataBasedOnLabels);

    // if hard-codes labels are there use them.
    if (_.get(this.chartConfig, 'labels')) {
      labels = _.get(this.chartConfig, 'labels');
    }
    _.forEach(labels, (label, key) => {
      labels[key] = _.capitalize(label);
    });

    this.chartLabels = labels;
  }

  private sortData(chartData, labelsExpr) {
    return _.orderBy(chartData, data => {
      const date = dayjs(data[labelsExpr], 'DD-MM-YYYY');
      if (date.isValid()) { return date; }
      return data[labelsExpr];
    });
  }

  getDataSetValue(chartData = this.chartData) {

    let groupedDataBasedOnLabels;
    const labelsExpr = _.get(this.chartConfig, 'labelsExpr');
    if (labelsExpr) {
      const sortedData = this.sortData(chartData, labelsExpr);
      groupedDataBasedOnLabels = _.groupBy(sortedData, (data) =>  ( data[labelsExpr] ? (_.trim(data[labelsExpr].toLowerCase()) ) : ''  ));
    }
    this.setChartLabels(groupedDataBasedOnLabels);
    this.datasets = [];
    const isStackingEnabled = this.checkForStacking();
    _.forEach(this.chartConfig.datasets, dataset => {
      const hidden = _.get(dataset, 'hidden') || false;
      const fill = _.isBoolean(_.get(dataset, 'fill')) ? _.get(dataset, 'fill') : true;
      const type = _.get(dataset, 'type');
      const lineThickness = _.get(dataset, 'lineThickness');
      const goalValue = _.get(dataset, 'goal');
      this.datasets.push({
        label: dataset.label,
        data: (goalValue && this.getGoalsDataset(chartData, +goalValue)) || (_.get(dataset, 'data') ||
          this.getData(groupedDataBasedOnLabels, dataset['dataExpr'], +_.get(dataset, 'top'))),
        hidden,
        fill,
        ...(isStackingEnabled) && { stack: _.get(dataset, 'stack') || 'default' },
        ...(type && { type }),
        ...(lineThickness) && { borderWidth: lineThickness }
      });
    });
    if (this.showGraphStats) {
      this.calculateGraphStats();
    }
  }

  private getGoalsDataset(chartData, goalValue: number) {
    return _.fill(chartData, goalValue);
  }

  private calculateGraphStats() {
    _.forEach(this.datasets, dataset => {
      this.resultStatistics[dataset.label] = {
        sum: _.sumBy(dataset.data, (val) => _.toNumber(val)).toFixed(2),
        min: _.minBy(dataset.data, (val) => _.toNumber(val)),
        max: _.maxBy(dataset.data, (val) => _.toNumber(val)),
        avg: dataset.data.length > 0 ? (_.sumBy(dataset.data, (val) => _.toNumber(val)) / dataset.data.length).toFixed(2) : 0
      };
    });
  }

  private getData(groupedDataBasedOnLabels, dataExpr, pickTopNElements: number) {

    const data = _.mapValues(groupedDataBasedOnLabels, value => {
      value = value.filter(element => {
        if (element[dataExpr]) {
          return element;
        }
      });
      return _.sumBy(value, (o) => +o[dataExpr]);
    });

    // Currently enabled for only pie charts
    if (this.chartType === 'pie' && pickTopNElements) {
      const sortedDataInDescOrder = _.orderBy(_.map(data, (val, key) => ({ key, val })), 'val', 'desc');
      const topNData = _.slice(sortedDataInDescOrder, 0, pickTopNElements);
      const restOfTheData = _.slice(sortedDataInDescOrder, pickTopNElements);
      const result = _.mapValues(_.keyBy(topNData, 'key'), 'val');
      result['others'] = _.sumBy(restOfTheData, 'val');
      this.setChartLabels(result); // set the labels as per the new dataset.
      return _.values(result);
    }
    return _.values(data);
  }

  ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete();
  }

  setTelemetryCdata() {
    this.telemetryCdata = [
      {
        id: 'dashboard:filter',
        type: 'Feature'
      }
      , {
        id: 'SB-13051',
        type: 'Task'
      }];
  }

  setTelemetryInteractEdata(val) {
    return {
      id: _.join(_.split(val, ' '), '-').toLowerCase(),
      type: 'click',
      pageid: this.activatedRoute.snapshot.data.telemetry.pageid
    };
  }

  checkForStacking(): boolean {
    if (_.includes(['bar', 'horizontalbar'], _.toLower(this.chartType))) {
      // in case of bar chart check both the axes
      return _.get(this.chartOptions, 'scales.yAxes') && _.get(this.chartOptions, 'scales.xAxes') &&
        _.every(this.chartOptions.scales.yAxes, 'stacked') && _.every(this.chartOptions.scales.xAxes, 'stacked');
    } else if (_.toLower(this.chartType) === 'line') {
      // check for y axis only in case of line area chart
      return _.get(this.chartOptions, 'scales.yAxes') && _.every(this.chartOptions.scales.yAxes, 'stacked');
    }
    return false;
  }

  public addChartSummary(): void {
    const chartId = _.get(this.chartConfig, 'id');
    if (chartId) {
      this.openAddSummaryModal.emit({
        title: this.chartSummarylabel,
        type: 'chart',
        chartId,
        ...(this._chartSummary && { summary: this._chartSummary })
      });
    } else {
      this.toasterService.error('Chart id is not present');
    }
  }

  public getChartSummary() {
    const chartId = _.get(this.chartConfig, 'id');
    if (_.get(this.chartConfig, 'id')) {
      return this.reportService.getLatestSummary({
        reportId: this.activatedRoute.snapshot.params.reportId, chartId,
        ...(this.hash && { hash: this.hash })
      }).pipe(
        map(chartSummary => {
          this._chartSummary = '';
          return _.map(chartSummary, summaryObj => {
            const summary = _.get(summaryObj, 'summary');
            this._chartSummary = summary;

            if (summary) {
              this.chartSummarylabel = _.get(this.resourceService, 'frmelmnts.lbl.updateChartSummary');
            }

            return {
              label: _.get(this.resourceService, 'frmelmnts.lbl.chartSummary'),
              text: [summary],
              createdOn: _.get(summaryObj, 'createdon')
            };
          });
        })
      );
    } else {
      return of([]);
    }
  }

   // use getter setter to define the property
   get globalFilter(): any {
    return this._globalFilter;
  }

  @Input()
  set globalFilter(val: any) {
    if (val && val.chartData) {
      const updatedChartData = val.chartData.filter(chart => {
        if (chart && chart.id) {
          if (this.chartConfig['id'] == chart.id) {
            return chart.data;
          }
        }
      });

      if (updatedChartData && updatedChartData[0] &&  updatedChartData[0].data) {
        delete updatedChartData[0].data['selectedFilters'];
        this.chartData = updatedChartData[0].data;
        this.cdr.detectChanges();
        this.getDataSetValue(updatedChartData[0].data);
        this.calculateBigNumber(updatedChartData[0].data);
        this.resetForm();

      }

    }
  }

  public filterChanged(data: any): void {
    this.cdr.detectChanges();
    this.currentFilters = data.filters;
    const keys = Object.keys(this.currentFilters);
    this.dateFilters = [];
    this.filters.map(ele => {
        if (ele && ele['controlType'].toLowerCase() == 'date') {
          keys.map(item => {
            if (item == ele['reference']) {
              this.dateFilters.push(item);
            }
          });
        }
    });

    if (data.filters) {
      this.chartData['selectedFilters'] = data.filters;
    } else {
      this.chartData['selectedFilters'] = {};
    }
    this.getDataSetValue(data.chartData[0].data);
    this.calculateBigNumber(data.chartData[0].data);
  }
  public graphStatsChange(data: any): void {
    this.showStats = data;
  }
  changeChartType(chartType) {
    this.chartType = _.lowerCase(_.get(chartType, 'value'));
  }
  filterModalPopup(operator) {

    if (operator == false) {
      this.closeDialog();
      this.cdr.detectChanges();
    } else {
      if (this.currentFilters) {
        this.chartData['selectedFilters'] = this.currentFilters;
        this.resetFilters = { data: this.chartData, reset: true };
      } else {
        this.chartData['selectedFilters'] = {};
      }
      this.cdr.detectChanges();
      this.openDialog();
    }

  }

  resetForm() {
    this.chartData['selectedFilters'] = {};
    this.resetFilters = { data: this.chartData, reset: true };
    this.currentFilters = [];
  }
  checkFilterReferance(element) {
    if (this.dateFilters && this.dateFilters.includes(element)) {
      return true;
    } else {
      return false;
    }
  }
  getChartData() {
    return [{ id: this.chartConfig.id , data: this.chartData , selectedFilters: this.currentFilters }];
  }
  openDialog() {
    if (this.filterPopUpMat) {
      this.dialogRef = this.dialog.open(this.filterPopUpMat, {
        data: this.chartData['selectedFilters'],
      });
    }
  }
  closeDialog() {
    if (this.dialogRef) {
      this.dialogRef.close();
    }
  }
}
<div class="graph-filters" #chartRootElement>

  <div class="d-flex pb-10">
    <div class="d-flex flex-dc flex-basis-1 mr-32 min-w-0">
      <label class="pad5 col-6 chart-title"> {{ this.chartOptions?.title?.text }} </label>
      <div class="sb-last-update-status" *ngIf="showLastUpdatedOn && lastUpdatedOn">
        <span>{{resourceService?.frmelmnts?.lbl?.lastUpdatedOn}}&nbsp;: </span> &nbsp; {{lastUpdatedOn}}
      </div>
    </div>
    <div class="d-flex flex-w-wrap selection-block">


      <div class="d-flex flex-w-wrap reset-filter-section">
        <div *ngIf="showGraphStats" class="d-flex flex-ai-center">{{resourceService?.frmelmnts?.lbl?.graphStat }}:
          <mat-slide-toggle (change)="graphStatsChange($event.checked)" appTelemetryInteract
            [telemetryInteractObject]="telemetryInteractObject"
            [telemetryInteractEdata]="setTelemetryInteractEdata('graph-statistics')"
            [telemetryInteractCdata]="telemetryCdata">
          </mat-slide-toggle>
        </div>
      </div>

      <div class="mr-8" *ngIf="chartType === 'bar' || chartType === 'line'" [ngClass]="{'hide': hideElements}">
        <!-- <button (click)="addChartSummary()" *ngIf="chartConfig.id && isUserReportAdmin" type="button"
          appTelemetryInteract [telemetryInteractObject]="telemetryInteractObject"
          [telemetryInteractCdata]="[{id: chartConfig?.id, type: 'Chart'}]"
          [telemetryInteractEdata]="{id: 'report-chart', type: 'chart-summary', pageid: activatedRoute.snapshot.data.telemetry.pageid}"
          class="mr-8 sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn"><i class="add icon"></i>Add
          {{ resourceService?.frmelmnts?.lbl?.chartSummary}}</button> -->
        <label>
          <mat-form-field appearance="fill" class="sb-mat__dropdown">
            <mat-label>Select ChartType</mat-label>
            <mat-select role="listbox" aria-label="Select ChartType" [(value)]="selectedLanguage" class="selection"
              (selectionChange)="changeChartType($event)">
              <mat-option class="mat-dropdown__options" role="option" *ngFor="let option of availableChartTypeOptions" [value]="option"
              appTelemetryInteract [telemetryInteractObject]="telemetryInteractObject"
              [telemetryInteractEdata]="setTelemetryInteractEdata('chart-type-filter')"
              [telemetryInteractCdata]="telemetryCdata"
              attr.aria-label="{{option}}">{{option}}</mat-option>
            </mat-select>
          </mat-form-field>
        </label>
      </div>

      <button *ngIf="isUserReportAdmin && chartConfig.id" [ngClass]="{'hide': hideElements}" appTelemetryInteract
        [telemetryInteractObject]="telemetryInteractObject"
        [telemetryInteractCdata]="[{id: chartConfig?.id, type: 'Chart'}]"
        [telemetryInteractEdata]="{id: 'report-chart', type: 'chart-summary', pageid: activatedRoute.snapshot.data.telemetry.pageid}"
        (click)="addChartSummary()" type="button" tabindex="0"
        class="sb-btn sb-btn-normal sb-btn-outline-primary mr-8"><i class="add icon"></i>
        {{ chartSummarylabel }}
      </button>



      <button class="sb-btn sb-btn-normal sb-btn-primary filter-btn" (click)="filterModalPopup(true)" tabindex="0"
        *ngIf="filters?.length > 0" [ngClass]="{'hide': hideElements}">
        {{ resourceService?.frmelmnts?.lbl?.filters }}
      </button>
    </div>
  </div>

  <div class="sb-filter-label pt-16 pb-8" *ngIf="currentFilters">
    <div *ngFor="let key of loadash.keys(currentFilters)" class="d-inline-flex flex-w-wrap pr-10">

      <span *ngIf="checkFilterReferance(key)">
        <span class="sb-label-name mb-4">{{key}}:</span>
        <span class="date-range-label" *ngIf="currentFilters[key]?.length>0">
          {{currentFilters[key][0]}} - {{currentFilters[key][currentFilters[key].length-1]}}
        </span>
      </span>
      <span *ngIf="!checkFilterReferance(key)">
        <span class="sb-label-name mb-4">{{key}}:</span><span class="sb-label-value"
          *ngFor="let val of currentFilters[key]">{{val}}
          <!-- <i class="close icon mr-0 pl-4"></i> -->
        </span>
      </span>

    </div>
  </div>

  <div *ngIf="showStats">
    <div _ngcontent-c14="" class="graph-statistics py-16" *ngFor="let stat of loadash.keys(resultStatistics)">
      {{stat}} <div class="sb-label sb-label-table sb-label-primary-100 mr-4"
        *ngFor="let op of loadash.keys(resultStatistics[stat])"> {{op}} : {{resultStatistics[stat][op]}}
      </div>
    </div>
  </div>

  <div class="dashboard-graph-statistics py-24" *ngIf="bigNumberCharts.length">
    <div class="graph-stat-block" *ngFor="let bigNumberChart of bigNumberCharts">
      <div class="graph-stat-label">{{bigNumberChart?.header}}</div>
      <div class="graph-stat-value">{{bigNumberChart?.data}} </div>
      <div class="graph-stat-info"> {{bigNumberChart?.footer}} </div>
    </div>
  </div>
  <ng-container *ngIf="showChart && !iframeDetails">
    <canvas #chartCanvas baseChart [datasets]="datasets" [labels]="chartLabels" [options]="chartOptions"
      [chartType]="chartType" [legend]="legend" [colors]="chartColors"></canvas>
  </ng-container>
  <ng-container *ngIf="iframeDetails">
    <iframe frameborder="0" class="dashboard-iframe" [src]="getIframeURL()">
    </iframe>
  </ng-container>
  <div class="my-16" *ngIf="chartSummary$ | async as summary">
    <app-report-summary *ngIf="summary.length" [inputData]="summary"></app-report-summary>
  </div>
</div>

<ng-template #filterPopUpMat >
  <div class="sb-modal sb-modal-addsummary">
    <div class="transition ui dimmer page modals active visible">
      <div class="ui modal transition active visible normal">
      <!--Header-->
      <div mat-dialog-title class="mb-0">
        <button aria-label="close dialog" (click)=" closeDialog()" mat-dialog-close class="mat-close-btn">
          <span>&times;</span>
        </button>
      </div>
      <!--/Header-->
      <!--content-->
      <mat-dialog-content align="left" >
        <div class="sb-modal-header">
          {{ resourceService?.frmelmnts?.lbl?.selectFilters }} 
        </div>
        <div class="sb-filter mb-10px">
          <div class="sb-filter__container">
            <div class="sb-filter__content" >
              <app-filter [filterType] ="filterType" [resetFilters]="resetFilters"  [hideElements]="hideElements" [selectedFilter]="selectedFilters" [filters]="filters" (filterChanged)="filterChanged($event)" [chartData]="getChartData()"
              [telemetryInteractObject]="telemetryInteractObject">
            </app-filter>
            </div>

          </div>
        </div>
      </mat-dialog-content>
       <!--/content-->
      <!--Actions-->
      <mat-dialog-actions align="center" class="mb-0">
          <div class="sb-modal-actions p-0">
            <button (click)="resetForm()" class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0">
              {{resourceService?.frmelmnts?.btn?.reset}} {{resourceService?.frmelmnts?.lbl?.filters  }}
            </button>
          </div>
      </mat-dialog-actions>
      <!--/Actions-->
    </div>
  </div>
</div>
</ng-template>

./data-chart.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;


.graph-statistics {
  border-bottom: calculateRem(1px) solid var(--rc-dddddd);
}

.sb-last-update-status {
  font-size: calculateRem(12px);
  font-weight: bold;
}

.dashboard-graph-statistics {
  border-bottom: calculateRem(1px) solid var(--rc-dddddd);
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: calculateRem(24px);

  .graph-stat-block {
    flex: 1;
    border-right: calculateRem(1px) solid var(--gray-100) !important;

    .graph-stat-label {
      font-size: calculateRem(18px);
    }

    .graph-stat-value {
      font-weight: bold;
      font-size: calculateRem(40px);
    }

    .graph-stat-info {
      color: var(--gray-200);
      font-size: calculateRem(18px);
    }

    &:nth-child(3n + 3) {
      border-right: 0px solid var(--gray-100) !important;
    }
  }
}

.dashboard-iframe {
  width: 100%;
  height: calculateRem(700px);
}


@include respond-below(md) {
  .dashboard-graph-statistics {
    border-bottom: calculateRem(1px) solid var(--rc-dddddd);

    .graph-stat-block {
      .graph-stat-label {
        font-size: calculateRem(14px);
      }

      .graph-stat-value {
        font-size: calculateRem(28px);
      }

      .graph-stat-info {
        font-size: calculateRem(14px);
      }
    }
  }
}

.pad5 {
  padding-top: calculateRem(5px);
  padding-bottom: calculateRem(5px);
}

.filter-btn {
  min-width: calculateRem(96px);
}

.sb-btn-normal {
  min-width: calculateRem(96px) !important;
  font-weight: 500 !important;
  font-size: calculateRem(15px) !important;
  padding-left: calculateRem(18px) !important;
  padding-right: calculateRem(18px) !important;

}

.sb-label-value {
  border-radius: calculateRem(24px);
  padding: calculateRem(7px);
  padding-right: calculateRem(9px);
  padding-left: calculateRem(9px);
  background-color: var(--rc-e9e8d9) !important;
  box-shadow: calculateRem(4px) calculateRem(4px) calculateRem(3px) 0 var(--gray-100) !important;
  color: var(--gray-800);
  margin-bottom: 0.25rem;
  margin-right: 0.25rem;

}

.chart-title {
  font-size: calculateRem(16px);
  font-weight: 500;
  margin-bottom: 0px !important;
  padding-top: calculateRem(5px);
}

.sb-label-name {
  font-size: calculateRem(16px);
}

::ng-deep {
  
  .sb-hawkeye-modal.sb-modal {
    .ui.modal {
      margin: 0 auto 0 !important;
      top: 50%;
      transform: translateY(-50%);
    }
  }
}

.selection-block {
  margin-bottom: calculateRem(8px);
}

.filter-select-title {
  font-size: calculateRem(20px);
  font-weight: 600;
}


.sb-label-primary-100 {
  padding: calculateRem(7px) !important;
  padding-left: calculateRem(9px) !important;
  padding-right: calculateRem(9px) !important;
  color: var(--gray-800) !important;
  border-radius: calculateRem(24px);
}

.date-range-label {
  padding: calculateRem(7px) !important;
  padding-left: calculateRem(9px) !important;
  padding-right: calculateRem(9px) !important;
  color: var(--gray-800) !important;
  border-radius: calculateRem(24px);
  background-color: var(---rc-e9e8d9) !important;
}


.sb-filter {
  &__container {
    width: 100%;
    height: 100vh;
    min-height: calculateRem(400px);
    background-color: var(--sbt-body-bg) !important;
    padding: calculateRem(24px);
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    position: relative;
    overflow-y: auto;

    @include respond-above(sm) {
      border-radius: calculateRem(8px);
      max-width: calculateRem(1008px);
      // min-height: calculateRem(610px);
      height: auto;
    }
  }

  &__header {
    width: 100%;
    text-align: center;
    max-width: calculateRem(328px);


  }

  &__content {
    width: calculateRem(648px);
    max-width: 100%;
    margin-bottom: auto;
  }

  &__footer {
    margin-top: calculateRem(16px);
    width: 100%;
    text-align: center;

    @include respond-above(sm) {
      max-width: 80%;
    }
  }
}

::ng-deep {
  .sb-filter-modal {
    @include respond-below(sm) {
      .ui.modal {
        width: 95%;
        margin: 0 0 0 0;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
      }

      .ui.modal.scroll {
        position: fixed !important;
        margin-top: o !important;
        margin-bottom: 0px !important;
        top: 0;
        width: 100%;
        left: 0px;
        right: 0px;
        margin: 0 !important;
      }
    }
  }
}

.sb-filter__content {
  ::ng-deep {
    .sb-prominent-filter-field {
      width: 48%;
      margin-bottom: calculateRem(10px);
    }

  }
}

::ng-deep {
  .mat-dialog-container {
      background-color: var(---rc-e9e8d9) !important;
      border-radius: calculateRem(24px);
  }
}


Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""