charthart

This commit is contained in:
string 2025-10-23 19:08:28 +05:30
parent 7461521a90
commit bc46735218
12 changed files with 285 additions and 289 deletions

View File

@ -8,6 +8,9 @@
<div style="display: inline;">
<button class="btn componentbtn" (click)="toggleMenu()"><clr-icon shape="plus"></clr-icon>component</button>
<button class="btn btn-primary" (click)="openCommonFilterModal()" style="margin-left: 10px;">
<clr-icon shape="filter"></clr-icon> Common Filter
</button>
<div style="display: inline;">
{{dashboardName}}
</div>
@ -208,8 +211,20 @@
<h5>Base API Filters</h5>
<div class="clr-subtext">Configure filters for the main API (applied regardless of drilldown settings)</div>
<!-- Common Filter Toggle -->
<div class="clr-form-control" style="margin-top: 10px;">
<div class="clr-control-container">
<div class="clr-checkbox-wrapper">
<input type="checkbox" id="commonFilterToggle" [(ngModel)]="gadgetsEditdata.commonFilterEnabled"
(change)="onCommonFilterToggle()" [ngModelOptions]="{standalone: true}" class="clr-checkbox" />
<label for="commonFilterToggle" class="clr-control-label">Use Common Filter</label>
</div>
</div>
</div>
<!-- Add Base Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addBaseFilter()" style="margin-top: 10px; margin-bottom: 10px;">
<button class="btn btn-sm btn-primary" (click)="addBaseFilter()" style="margin-top: 10px; margin-bottom: 10px;"
[disabled]="gadgetsEditdata.commonFilterEnabled">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
@ -218,14 +233,16 @@
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Filter {{i + 1}}</span>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)"
[disabled]="gadgetsEditdata.commonFilterEnabled">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-row" style="margin-top: 8px;">
<div class="clr-col-sm-5">
<select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select">
<select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select"
[disabled]="gadgetsEditdata.commonFilterEnabled">
<option value="">Select Field</option>
<!-- Base API filters should always use columnData, not drilldownColumnData -->
<option *ngFor="let column of getAvailableFields(gadgetsEditdata.baseFilters, i, columnData)" [value]="column">{{column}}</option>
@ -234,11 +251,13 @@
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" />
class="clr-input" placeholder="Filter Value"
[disabled]="gadgetsEditdata.commonFilterEnabled"/>
</div>
<div class="clr-col-sm-2">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)"
[disabled]="gadgetsEditdata.commonFilterEnabled">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
@ -324,12 +343,12 @@
<h5>Base Drilldown Filters</h5>
<div class="clr-subtext">Configure filters for the base drilldown level</div>
<!-- Add Base Drilldown Filter Button -->
<!-- Add Drilldown Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addDrilldownFilter()" style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
<!-- Base Drilldown Filter Fields List -->
<!-- Drilldown Filter Fields List -->
<div *ngFor="let filter of gadgetsEditdata.drilldownFilters; let i = index"
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
@ -508,3 +527,86 @@
</form>
</div>
</clr-modal>
<!-- Common Filter Modal -->
<clr-modal [(clrModalOpen)]="commonFilterModalOpen" [clrModalStaticBackdrop]="true" clrModalSize="lg">
<h3 class="modal-title">Configure Common Filter</h3>
<div class="modal-body">
<form [formGroup]="commonFilterForm" class="clr-form-horizontal">
<div class="clr-row">
<div class="clr-col-sm-12">
<label for="commonFilterConnection">Connection</label>
<select id="commonFilterConnection" formControlName="connection" [(ngModel)]="commonFilterData.connection" class="clr-select">
<option value="">Select Connection</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.connection_name || conn.id}}
</option>
</select>
</div>
</div>
<div class="clr-row">
<div class="clr-col-sm-12">
<label for="commonFilterApiUrl">API URL</label>
<div>
<input type="text" id="commonFilterApiUrl" formControlName="apiUrl" class="clr-input"
[(ngModel)]="commonFilterData.apiUrl" style="width:90%">&nbsp;
<span>
<button class="btn btn-icon btn-primary" style="margin: 0px;"
(click)="refreshCommonFilterColumns()" [disabled]="!commonFilterData.apiUrl">
<clr-icon shape="redo"></clr-icon>
</button>
</span>
</div>
</div>
</div>
<!-- Common Filter Fields List -->
<div class="clr-row" style="margin-top: 15px;">
<div class="clr-col-sm-12">
<h5>Common Filters</h5>
<!-- Add Common Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addCommonFilter()" style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
<!-- Common Filter Fields List -->
<div *ngFor="let filter of commonFilterData.filters; let i = index"
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Filter {{i + 1}}</span>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeCommonFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-row" style="margin-top: 8px;">
<div class="clr-col-sm-5">
<select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select">
<option value="">Select Field</option>
<option *ngFor="let column of commonFilterColumnData" [value]="column">{{column}}</option>
</select>
</div>
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" />
</div>
<div class="clr-col-sm-2">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeCommonFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="commonFilterModalOpen = false">Cancel</button>
<button type="button" class="btn btn-primary" (click)="saveCommonFilter()">Save</button>
</div>
</clr-modal>

View File

@ -40,7 +40,9 @@ export class EditnewdashComponent implements OnInit {
editId: number;
toggle: boolean;
modeledit: boolean = false;
commonFilterModalOpen: boolean = false; // Add common filter modal state
public entryForm: FormGroup;
public commonFilterForm: FormGroup; // Add common filter form
WidgetsMock: WidgetModel[] = [
{
@ -118,6 +120,17 @@ export class EditnewdashComponent implements OnInit {
model: any;
linesdata: any;
id: any;
// Add common filter data property
commonFilterData = {
connection: '',
apiUrl: '',
filters: [] as any[]
};
// Add common filter column data property
commonFilterColumnData: any[] = [];
gadgetsEditdata = {
donut: '',
chartlegend: '',
@ -146,12 +159,17 @@ export class EditnewdashComponent implements OnInit {
drilldownFilters: [] as any[], // Add separate drilldown filters
// Multi-layer drilldown configurations
drilldownLayers: [] as any[],
// Common filter property
commonFilterEnabled: false
};
// Add sureconnect data property
sureconnectData: any[] = [];
layerColumnData: { [key: number]: any[] } = {}; // Add layer column data property
// Add drilldown column data property
drilldownColumnData = []; // Add drilldown column data property
constructor(private route: ActivatedRoute,
private router: Router,
private dashboardService: Dashboard3Service,
@ -224,8 +242,17 @@ export class EditnewdashComponent implements OnInit {
// Note: Dynamic drilldown layers and filters will be handled separately since they're complex objects
});
// Initialize common filter form
this.commonFilterForm = this._fb.group({
connection: [''],
apiUrl: ['']
});
// Load sureconnect data first, then load dashboard data
this.loadSureconnectData();
// Load common filter data if it exists
this.loadCommonFilterData();
}
// Add method to load sureconnect data
@ -242,6 +269,13 @@ export class EditnewdashComponent implements OnInit {
});
}
// Add method to load common filter data
loadCommonFilterData() {
// In a real implementation, this would fetch common filter data from the server
// For now, we'll initialize with empty values
console.log('Loading common filter data');
}
toggleMenu() {
this.toggle = !this.toggle;
}
@ -499,6 +533,10 @@ export class EditnewdashComponent implements OnInit {
if (item.showlabel === undefined) { item.showlabel = true; }
if (item.chartcolor === undefined) { item.chartcolor = true; }
if (item.chartlegend === undefined) { item.chartlegend = true; }
// Initialize common filter property if not present
if (item['commonFilterEnabled'] === undefined) {
this.gadgetsEditdata['commonFilterEnabled'] = false;
}
this.getStores();
// Set default connection if none is set and we have connections
@ -662,6 +700,7 @@ export class EditnewdashComponent implements OnInit {
xyz.baseFilters = this.gadgetsEditdata.baseFilters; // Add base filters
xyz.drilldownFilters = this.gadgetsEditdata.drilldownFilters; // Add drilldown filters
xyz.drilldownLayers = this.gadgetsEditdata.drilldownLayers;
xyz.commonFilterEnabled = this.gadgetsEditdata.commonFilterEnabled; // Add common filter property
console.log(xyz);
return xyz;
@ -755,6 +794,7 @@ export class EditnewdashComponent implements OnInit {
updatedItem.baseFilters = this.gadgetsEditdata.baseFilters; // Add base filters
updatedItem.drilldownFilters = this.gadgetsEditdata.drilldownFilters; // Add drilldown filters
updatedItem.drilldownLayers = this.gadgetsEditdata.drilldownLayers;
updatedItem.commonFilterEnabled = this.gadgetsEditdata.commonFilterEnabled; // Add common filter property
console.log('Updated item:', updatedItem);
return updatedItem;
@ -820,7 +860,6 @@ export class EditnewdashComponent implements OnInit {
}
selectedyAxis;
columnData;
drilldownColumnData = []; // Add drilldown column data property
getColumns(id, table) {
const connectionId = this.gadgetsEditdata.connection ? parseInt(this.gadgetsEditdata.connection, 10) : undefined;
@ -1017,4 +1056,97 @@ export class EditnewdashComponent implements OnInit {
removeLayerFilter(layerIndex: number, filterIndex: number) {
this.gadgetsEditdata.drilldownLayers[layerIndex].filters.splice(filterIndex, 1);
}
// Add method to open common filter modal
openCommonFilterModal() {
this.commonFilterModalOpen = true;
}
// Add method to add a common filter
addCommonFilter() {
const newFilter = {
field: '',
value: ''
};
this.commonFilterData.filters.push(newFilter);
}
// Add method to remove a common filter
removeCommonFilter(index: number) {
this.commonFilterData.filters.splice(index, 1);
}
// Add method to refresh common filter columns
refreshCommonFilterColumns() {
if (this.commonFilterData.apiUrl) {
const connectionId = this.commonFilterData.connection ? parseInt(this.commonFilterData.connection, 10) : undefined;
this.alertService.getColumnfromurl(this.commonFilterData.apiUrl, connectionId).subscribe(data => {
console.log('Common filter column data:', data);
this.commonFilterColumnData = data;
}, (error) => {
console.log('Error fetching common filter columns:', error);
this.commonFilterColumnData = [];
});
}
}
// Add method to save common filter
saveCommonFilter() {
// Here we would typically make an API call to save the common filter
// For now, we'll just close the modal
console.log('Saving common filter:', this.commonFilterData);
// Update all charts that have common filter enabled
this.updateChartsWithCommonFilter();
this.commonFilterModalOpen = false;
}
// Add method to update charts with common filter data
updateChartsWithCommonFilter() {
// This method will be called when common filter is saved
// It will update all charts that have common filter enabled
console.log('Updating charts with common filter data');
// Update the dashboardArray to reflect changes
this.dashboardArray = this.dashboardArray.map(item => {
if (item.commonFilterEnabled) {
// Update the chart with common filter data
return {
...item,
table: this.commonFilterData.apiUrl,
connection: this.commonFilterData.connection,
baseFilters: [...this.commonFilterData.filters]
};
}
return item;
});
// Also update the dashboardCollection to persist changes
this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => {
if (item.commonFilterEnabled) {
// Update the chart with common filter data
return {
...item,
table: this.commonFilterData.apiUrl,
connection: this.commonFilterData.connection,
baseFilters: [...this.commonFilterData.filters]
} as DashboardContentModel;
}
return item;
});
}
// Add method to handle common filter toggle
onCommonFilterToggle() {
console.log('Common filter toggled:', this.gadgetsEditdata.commonFilterEnabled);
if (this.gadgetsEditdata.commonFilterEnabled) {
// When enabling common filter, save current values and apply common filter data
this.gadgetsEditdata.table = this.commonFilterData.apiUrl;
this.gadgetsEditdata.connection = this.commonFilterData.connection;
this.gadgetsEditdata.baseFilters = [...this.commonFilterData.filters];
}
// When disabling, the user can edit the filters normally
}
}

View File

@ -320,7 +320,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
drilldownConfig.apiUrl, 'bar',
this.drilldownXAxis, this.drilldownYAxis,
this.connection,
parameterField, parameterValue,
'', parameterValue,
drilldownFilterParams
).subscribe(
(data: any) => {

View File

@ -307,32 +307,13 @@ export class BubbleChartComponent implements OnInit, OnChanges {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/bubble?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -402,32 +402,13 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/doughnut?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'doughnut', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'doughnut', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -298,32 +298,13 @@ export class DynamicChartComponent implements OnInit, OnChanges {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/dynamic?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'dynamic', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'dynamic', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -289,32 +289,13 @@ export class FinancialChartComponent implements OnInit, OnChanges {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/financial?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'financial', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'financial', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -313,32 +313,13 @@ export class LineChartComponent implements OnInit, OnChanges {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/line?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'line', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'line', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -362,32 +362,13 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/pie?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -1,13 +1,12 @@
import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service';
import { Subscription } from 'rxjs';
import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
@Component({
selector: 'app-polar-chart',
templateUrl: './polar-chart.component.html',
styleUrls: ['./polar-chart.component.scss']
})
export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
export class PolarChartComponent implements OnInit, OnChanges {
@Input() xAxis: string;
@Input() yAxis: string | string[];
@Input() table: string;
@ -36,24 +35,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
constructor(private dashboardService: Dashboard3Service) { }
public polarAreaChartLabels: string[] = [ 'Download Sales', 'In-Store Sales', 'Mail Sales', 'Telesales', 'Corporate Sales' ];
public polarAreaChartData: any = [
{ data: [ 300, 500, 100, 40, 120 ], label: 'Series 1'}
];
public polarAreaChartType: string = 'polarArea';
// Multi-layer drilldown state tracking
drilldownStack: any[] = []; // Stack to track drilldown navigation history
currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
originalPolarAreaChartLabels: string[] = [];
originalPolarAreaChartData: any = [];
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
ngOnInit(): void {
// Initialize with default data
this.fetchChartData();
@ -85,6 +66,25 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
public polarAreaChartLabels: string[] = [ 'Download Sales', 'In-Store Sales', 'Mail Sales', 'Telesales', 'Corporate Sales' ];
public polarAreaChartData: any = [
{ data: [ 300, 500, 100, 40, 120 ], label: 'Series 1'}
];
public polarAreaChartType: string = 'polarArea';
// Multi-layer drilldown state tracking
drilldownStack: any[] = []; // Stack to track drilldown navigation history
currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
originalPolarAreaChartLabels: string[] = [];
originalPolarAreaChartData: any = [];
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
@ -133,8 +133,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
return;
@ -145,36 +143,26 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
// For polar charts, we need to extract the data differently
// The first dataset's data array contains the values for the polar chart
this.noDataAvailable = data.chartLabels.length === 0;
this.polarAreaChartLabels = data.chartLabels || [];
this.polarAreaChartLabels = data.chartLabels;
if (data.chartData && data.chartData.length > 0) {
this.polarAreaChartData = data.chartData[0].data.map(value => {
// Convert to number if it's not already
const numValue = Number(value);
return isNaN(numValue) ? 0 : numValue;
return isNaN(Number(value)) ? 0 : Number(value);
});
} else {
this.polarAreaChartData = [];
}
// Ensure labels and data arrays have the same length
this.syncLabelAndDataArrays();
// Validate and sanitize data
this.validateChartData();
// Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with data:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
} else if (data && data.labels && data.data) {
// Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0;
this.polarAreaChartLabels = data.labels || [];
this.polarAreaChartLabels = data.labels;
this.polarAreaChartData = data.data.map(value => {
// Convert to number if it's not already
const numValue = Number(value);
return isNaN(numValue) ? 0 : numValue;
return isNaN(Number(value)) ? 0 : Number(value);
});
// Ensure labels and data arrays have the same length
this.syncLabelAndDataArrays();
// Validate and sanitize data
this.validateChartData();
// Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
@ -183,8 +171,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Validate and sanitize data
this.validateChartData();
}
// Reset flag after fetching
this.isFetchingData = false;
@ -194,8 +180,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
@ -206,8 +190,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
}
@ -305,32 +287,13 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/polar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'polar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'polar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -346,36 +309,26 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
// For polar charts, we need to extract the data differently
// The first dataset's data array contains the values for the polar chart
this.noDataAvailable = data.chartLabels.length === 0;
this.polarAreaChartLabels = data.chartLabels || [];
this.polarAreaChartLabels = data.chartLabels;
if (data.chartData && data.chartData.length > 0) {
this.polarAreaChartData = data.chartData[0].data.map(value => {
// Convert to number if it's not already
const numValue = Number(value);
return isNaN(numValue) ? 0 : numValue;
return isNaN(Number(value)) ? 0 : Number(value);
});
} else {
this.polarAreaChartData = [];
}
// Ensure labels and data arrays have the same length
this.syncLabelAndDataArrays();
// Validate and sanitize data
this.validateChartData();
// Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with drilldown data:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
} else if (data && data.labels && data.data) {
// Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0;
this.polarAreaChartLabels = data.labels || [];
this.polarAreaChartLabels = data.labels;
this.polarAreaChartData = data.data.map(value => {
// Convert to number if it's not already
const numValue = Number(value);
return isNaN(numValue) ? 0 : numValue;
return isNaN(Number(value)) ? 0 : Number(value);
});
// Ensure labels and data arrays have the same length
this.syncLabelAndDataArrays();
// Validate and sanitize data
this.validateChartData();
// Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with drilldown legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
@ -384,8 +337,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Validate and sanitize data
this.validateChartData();
}
},
(error) => {
@ -454,58 +405,6 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
/**
* Validate and sanitize chart data
*/
private validateChartData(): void {
// Ensure we have valid arrays
if (!Array.isArray(this.polarAreaChartLabels)) {
this.polarAreaChartLabels = [];
}
if (!Array.isArray(this.polarAreaChartData)) {
this.polarAreaChartData = [];
}
// If we have no data, show default data
if (this.polarAreaChartLabels.length === 0 && this.polarAreaChartData.length === 0) {
// Add default data to ensure chart visibility
this.polarAreaChartLabels = ['Download Sales', 'In-Store Sales', 'Mail Sales', 'Telesales', 'Corporate Sales'];
this.polarAreaChartData = [300, 500, 100, 40, 120];
}
// Ensure we have matching arrays
if (this.polarAreaChartLabels.length !== this.polarAreaChartData.length) {
const maxLength = Math.max(this.polarAreaChartLabels.length, this.polarAreaChartData.length);
while (this.polarAreaChartLabels.length < maxLength) {
this.polarAreaChartLabels.push(`Label ${this.polarAreaChartLabels.length + 1}`);
}
while (this.polarAreaChartData.length < maxLength) {
this.polarAreaChartData.push(0);
}
}
}
// Ensure labels and data arrays have the same length
private syncLabelAndDataArrays(): void {
if (this.polarAreaChartLabels && this.polarAreaChartData) {
const labelCount = this.polarAreaChartLabels.length;
const dataCount = this.polarAreaChartData.length;
if (labelCount > dataCount) {
// Add zeros to data array
while (this.polarAreaChartData.length < labelCount) {
this.polarAreaChartData.push(0);
}
} else if (dataCount > labelCount) {
// Add labels to label array
while (this.polarAreaChartLabels.length < dataCount) {
this.polarAreaChartLabels.push(`Item ${this.polarAreaChartLabels.length + 1}`);
}
}
}
}
// events
public chartClicked(e: any): void {
console.log('Polar chart clicked:', e);
@ -594,8 +493,4 @@ export class PolarChartComponent implements OnInit, OnChanges, OnDestroy {
public chartHovered(e: any): void {
console.log(e);
}
ngOnDestroy(): void {
// Clean up any subscriptions if needed
}
}

View File

@ -298,32 +298,13 @@ export class RadarChartComponent implements OnInit, OnChanges {
}
}
// Convert drilldownFilters to filter parameters for drilldown level
let drilldownFilterParams = '';
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
const filterObj = {};
this.drilldownFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
drilldownFilterParams = JSON.stringify(filterObj);
}
}
console.log('Drilldown filter parameters:', drilldownFilterParams);
// Use drilldown filters if available, otherwise use layer filters
const finalFilterParams = drilldownFilterParams || filterParams;
console.log('Final filter parameters:', finalFilterParams);
// Log the URL that will be called
const url = `chart/getdashjson/radar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'radar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, finalFilterParams).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'radar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {