src/app/modules/dashboard/components/data-chart/data-chart.component.ts
OnInit
OnDestroy
selector | app-data-chart |
styleUrls | ./data-chart.component.scss |
templateUrl | ./data-chart.component.html |
constructor(resourceService: ResourceService, cdr: ChangeDetectorRef, toasterService: ToasterService, activatedRoute: ActivatedRoute, sanitizer: DomSanitizer, usageService: UsageService, reportService: ReportService, dialog: MatDialog)
|
|||||||||||||||||||||||||||
Parameters :
|
chartInfo | |
Type : any
|
|
globalFilter | |
Type : any
|
|
hash | |
Type : string
|
|
hideElements | |
Type : boolean
|
|
Default value : false
|
|
isUserReportAdmin | |
Type : boolean
|
|
Default value : false
|
|
telemetryInteractObject | |
Type : IInteractEventObject
|
|
openAddSummaryModal | |
Type : EventEmitter
|
|
Public addChartSummary |
addChartSummary()
|
Returns :
void
|
Private calculateBigNumber | ||||
calculateBigNumber(chartData)
|
||||
Parameters :
Returns :
void
|
Private calculateGraphStats |
calculateGraphStats()
|
Returns :
void
|
changeChartType | ||||
changeChartType(chartType)
|
||||
Parameters :
Returns :
void
|
checkFilterReferance | ||||
checkFilterReferance(element)
|
||||
Parameters :
Returns :
boolean
|
Private checkForExternalChart |
checkForExternalChart()
|
Returns :
boolean
|
checkForStacking |
checkForStacking()
|
Returns :
boolean
|
closeDialog |
closeDialog()
|
Returns :
void
|
Public filterChanged | ||||||
filterChanged(data: any)
|
||||||
Parameters :
Returns :
void
|
filterModalPopup | ||||
filterModalPopup(operator)
|
||||
Parameters :
Returns :
void
|
getChartData |
getChartData()
|
Returns :
{}
|
Public getChartSummary |
getChartSummary()
|
Returns :
any
|
Private getData | ||||||||||||
getData(groupedDataBasedOnLabels, dataExpr, pickTopNElements: number)
|
||||||||||||
Parameters :
Returns :
any
|
getDataSetValue | ||||||
getDataSetValue(chartData)
|
||||||
Parameters :
Returns :
void
|
Private getGoalsDataset | |||||||||
getGoalsDataset(chartData, goalValue: number)
|
|||||||||
Parameters :
Returns :
any
|
getIframeURL |
getIframeURL()
|
Returns :
any
|
Public graphStatsChange | ||||||
graphStatsChange(data: any)
|
||||||
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
openDialog |
openDialog()
|
Returns :
void
|
prepareChart |
prepareChart()
|
Returns :
void
|
refreshChartDataAfterInterval | ||||
refreshChartDataAfterInterval(interval)
|
||||
Parameters :
Returns :
void
|
resetForm |
resetForm()
|
Returns :
void
|
setTelemetryCdata |
setTelemetryCdata()
|
Returns :
void
|
setTelemetryInteractEdata | ||||
setTelemetryInteractEdata(val)
|
||||
Parameters :
Returns :
{ id: any; type: string; pageid: any; }
|
Private sortData | ||||||
sortData(chartData, labelsExpr)
|
||||||
Parameters :
Returns :
any
|
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>()
|
globalFilter | ||||||
getglobalFilter()
|
||||||
setglobalFilter(val: any)
|
||||||
Parameters :
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}} : </span> {{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>×</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);
}
}