chart
This commit is contained in:
		
							parent
							
								
									b1dc16a67b
								
							
						
					
					
						commit
						fcbee92929
					
				| @ -1,5 +1,6 @@ | |||||||
| import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; | import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; | ||||||
| import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service'; | import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service'; | ||||||
|  | import { Subscription } from 'rxjs'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-bar-chart', |   selector: 'app-bar-chart', | ||||||
| @ -28,7 +29,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|   // @Input() baseFilters: any[] = []; // Removed base filters input
 |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -49,7 +50,11 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|    |    | ||||||
|   // Filter update timeout property removed
 |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
|  |    | ||||||
|  |   // Subscriptions to unsubscribe on destroy
 | ||||||
|  |   private subscriptions: Subscription[] = []; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -66,6 +71,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -73,10 +79,10 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Only fetch data if the actual chart configuration changed
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('Chart configuration changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
| @ -88,12 +94,15 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Filter parameters method removed
 |  | ||||||
| 
 |  | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -111,9 +120,23 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|       let url = `chart/getdashjson/bar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       let url = `chart/getdashjson/bar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Bar chart data URL:', url); |       console.log('Bar chart data URL:', url); | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       const subscription = this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received bar chart data:', data); |           console.log('Received bar chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -121,6 +144,8 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.barChartLabels = []; |             this.barChartLabels = []; | ||||||
|             this.barChartData = []; |             this.barChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -131,7 +156,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|             this.barChartLabels = data.chartLabels; |             this.barChartLabels = data.chartLabels; | ||||||
|             this.barChartData = data.chartData; |             this.barChartData = data.chartData; | ||||||
|             // Trigger change detection
 |             // Trigger change detection
 | ||||||
|             this.barChartData = [...this.barChartData]; |             // this.barChartData = [...this.barChartData];
 | ||||||
|             console.log('Updated bar chart with data:', { labels: this.barChartLabels, data: this.barChartData }); |             console.log('Updated bar chart with data:', { labels: this.barChartLabels, data: this.barChartData }); | ||||||
|           } else if (data && data.labels && data.datasets) { |           } else if (data && data.labels && data.datasets) { | ||||||
|             // Backend has already filtered the data, just display it
 |             // Backend has already filtered the data, just display it
 | ||||||
| @ -139,7 +164,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|             this.barChartLabels = data.labels; |             this.barChartLabels = data.labels; | ||||||
|             this.barChartData = data.datasets; |             this.barChartData = data.datasets; | ||||||
|             // Trigger change detection
 |             // Trigger change detection
 | ||||||
|             this.barChartData = [...this.barChartData]; |             // this.barChartData = [...this.barChartData];
 | ||||||
|             console.log('Updated bar chart with legacy data format:', { labels: this.barChartLabels, data: this.barChartData }); |             console.log('Updated bar chart with legacy data format:', { labels: this.barChartLabels, data: this.barChartData }); | ||||||
|           } else { |           } else { | ||||||
|             console.warn('Bar chart received data does not have expected structure', data); |             console.warn('Bar chart received data does not have expected structure', data); | ||||||
| @ -147,20 +172,29 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|             this.barChartLabels = []; |             this.barChartLabels = []; | ||||||
|             this.barChartData = []; |             this.barChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching bar chart data:', error); |           console.error('Error fetching bar chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.barChartLabels = []; |           this.barChartLabels = []; | ||||||
|           this.barChartData = []; |           this.barChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|  |        | ||||||
|  |       // Add subscription to array for cleanup
 | ||||||
|  |       this.subscriptions.push(subscription); | ||||||
|     } else { |     } else { | ||||||
|       console.log('Missing required data for bar chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); |       console.log('Missing required data for bar chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); | ||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.barChartLabels = []; |       this.barChartLabels = []; | ||||||
|       this.barChartData = []; |       this.barChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -249,9 +283,23 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     } |     } | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the parameter field and value
 |     // Backend handles filtering, we just pass the parameter field and value
 | ||||||
|     this.dashboardService.getChartData(actualApiUrl, 'bar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe( |     const subscription = this.dashboardService.getChartData(actualApiUrl, 'bar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -269,15 +317,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|           this.barChartLabels = data.chartLabels; |           this.barChartLabels = data.chartLabels; | ||||||
|           this.barChartData = data.chartData; |           this.barChartData = data.chartData; | ||||||
|           // Trigger change detection
 |           // Trigger change detection
 | ||||||
|           this.barChartData = [...this.barChartData]; |           // this.barChartData = [...this.barChartData];
 | ||||||
|           console.log('Updated bar chart with drilldown data:', { labels: this.barChartLabels, data: this.barChartData }); |           console.log('Updated bar chart with drilldown data:', { labels: this.barChartLabels, data: this.barChartData }); | ||||||
|         } else if (data && data.labels && data.datasets) { |         } else if (data && data.labels && data.datasets) { | ||||||
|           // Backend has already filtered the data, just display it
 |           // Backend has already filtered the data, just display it
 | ||||||
|           this.noDataAvailable = data.labels.length === 0; |           this.noDataAvailable = data.labels.length === 0; | ||||||
|           this.barChartLabels = data.labels; |           this.barChartLabels = data.labels; | ||||||
|           this.barChartData = data.datasets; |           this.barChartData = data.datasets; | ||||||
|           // Trigger change detection
 |  | ||||||
|           this.barChartData = [...this.barChartData]; |  | ||||||
|           console.log('Updated bar chart with drilldown legacy data format:', { labels: this.barChartLabels, data: this.barChartData }); |           console.log('Updated bar chart with drilldown legacy data format:', { labels: this.barChartLabels, data: this.barChartData }); | ||||||
|         } else { |         } else { | ||||||
|           console.warn('Drilldown received data does not have expected structure', data); |           console.warn('Drilldown received data does not have expected structure', data); | ||||||
| @ -294,6 +340,9 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|         // Keep current data in case of error
 |         // Keep current data in case of error
 | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|  |      | ||||||
|  |     // Add subscription to array for cleanup
 | ||||||
|  |     this.subscriptions.push(subscription); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   // Reset to original data (go back to base level)
 |   // Reset to original data (go back to base level)
 | ||||||
| @ -306,11 +355,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     this.drilldownStack = []; |     this.drilldownStack = []; | ||||||
|      |      | ||||||
|     if (this.originalBarChartLabels.length > 0) { |     if (this.originalBarChartLabels.length > 0) { | ||||||
|       this.barChartLabels = [...this.originalBarChartLabels]; |       // Create a deep copy to avoid reference issues
 | ||||||
|  |       this.barChartLabels = JSON.parse(JSON.stringify(this.originalBarChartLabels)); | ||||||
|       console.log('Restored original labels'); |       console.log('Restored original labels'); | ||||||
|     } |     } | ||||||
|     if (this.originalBarChartData.length > 0) { |     if (this.originalBarChartData.length > 0) { | ||||||
|       this.barChartData = [...this.originalBarChartData]; |       // Create a deep copy to avoid reference issues
 | ||||||
|  |       this.barChartData = JSON.parse(JSON.stringify(this.originalBarChartData)); | ||||||
|       console.log('Restored original data'); |       console.log('Restored original data'); | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -352,6 +403,29 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // Ensure labels and data arrays have the same length
 | ||||||
|  |   private syncLabelAndDataArrays(): void { | ||||||
|  |     // For bar charts, we need to ensure all datasets have the same number of data points
 | ||||||
|  |     if (this.barChartData && this.barChartData.length > 0 && this.barChartLabels) { | ||||||
|  |       const labelCount = this.barChartLabels.length; | ||||||
|  |        | ||||||
|  |       this.barChartData.forEach(dataset => { | ||||||
|  |         if (dataset.data) { | ||||||
|  |           // If dataset has more data points than labels, truncate the data
 | ||||||
|  |           if (dataset.data.length > labelCount) { | ||||||
|  |             dataset.data = dataset.data.slice(0, labelCount); | ||||||
|  |           } | ||||||
|  |           // If dataset has fewer data points than labels, pad with zeros
 | ||||||
|  |           else if (dataset.data.length < labelCount) { | ||||||
|  |             while (dataset.data.length < labelCount) { | ||||||
|  |               dataset.data.push(0); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // events
 |   // events
 | ||||||
|   public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Bar chart clicked:', e); |     console.log('Bar chart clicked:', e); | ||||||
| @ -369,8 +443,10 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
|         // Store original data before entering drilldown mode
 |         // Store original data before entering drilldown mode
 | ||||||
|         this.originalBarChartLabels = [...this.barChartLabels]; |         // Create a deep copy to avoid reference issues
 | ||||||
|         this.originalBarChartData = [...this.barChartData]; |         this.originalBarChartLabels = JSON.parse(JSON.stringify(this.barChartLabels)); | ||||||
|  |         // Create a deep copy to avoid reference issues
 | ||||||
|  |         this.originalBarChartData = JSON.parse(JSON.stringify(this.barChartData)); | ||||||
|         console.log('Stored original data for drilldown'); |         console.log('Stored original data for drilldown'); | ||||||
|       } |       } | ||||||
|        |        | ||||||
| @ -442,6 +518,22 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   } |   } | ||||||
|    |    | ||||||
|   ngOnDestroy() { |   ngOnDestroy() { | ||||||
|     // Cleanup method - no timeouts to clean up
 |     // Unsubscribe from all subscriptions to prevent memory leaks
 | ||||||
|  |     console.log('BarChartComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions'); | ||||||
|  |     this.subscriptions.forEach(subscription => { | ||||||
|  |       if (subscription && !subscription.closed) { | ||||||
|  |         subscription.unsubscribe(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     this.subscriptions = []; | ||||||
|  |      | ||||||
|  |     // Clear data to help with garbage collection
 | ||||||
|  |     this.barChartLabels = []; | ||||||
|  |     this.barChartData = []; | ||||||
|  |     this.drilldownStack = []; | ||||||
|  |     this.originalBarChartLabels = []; | ||||||
|  |     this.originalBarChartData = []; | ||||||
|  |      | ||||||
|  |     console.log('BarChartComponent destroyed and cleaned up'); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -29,6 +29,7 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -90,6 +91,9 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -105,6 +109,7 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -112,19 +117,24 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -135,19 +145,36 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/bubble?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/bubble?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Bubble chart data URL:', url); |       console.log('Bubble chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received bubble chart data:', data); |           console.log('Received bubble chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
|             console.warn('Bubble chart API returned null data. Check if the API endpoint is working correctly.'); |             console.warn('Bubble chart API returned null data. Check if the API endpoint is working correctly.'); | ||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.bubbleChartData = []; |             this.bubbleChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -168,17 +195,23 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.bubbleChartData = []; |             this.bubbleChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching bubble chart data:', error); |           console.error('Error fetching bubble chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.bubbleChartData = []; |           this.bubbleChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|     } else { |     } else { | ||||||
|       console.log('Missing required data for bubble chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); |       console.log('Missing required data for bubble chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); | ||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.bubbleChartData = []; |       this.bubbleChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -258,13 +291,27 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/bubble?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -300,6 +347,35 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|  |   // Transform chart data to bubble chart format
 | ||||||
|  |   private transformToBubbleData(labels: string[], datasets: any[]): ChartDataset[] { | ||||||
|  |     // For bubble charts, we need to transform the data into bubble format
 | ||||||
|  |     // Bubble charts expect data in the format: {x: number, y: number, r: number}
 | ||||||
|  |      | ||||||
|  |     // This is a simple transformation - in a real implementation, you might want to
 | ||||||
|  |     // create a more sophisticated mapping based on your data structure
 | ||||||
|  |     return datasets.map((dataset, index) => { | ||||||
|  |       // Create bubble data points
 | ||||||
|  |       const bubbleData = labels.map((label, i) => { | ||||||
|  |         // Use x-axis data as x coordinate, y-axis data as y coordinate, and a fixed radius
 | ||||||
|  |         const xValue = dataset.data[i] || 0; | ||||||
|  |         const yValue = i < datasets.length ? (datasets[i].data[index] || 0) : 0; | ||||||
|  |         const radius = 10; // Fixed radius for now
 | ||||||
|  |          | ||||||
|  |         return { x: xValue, y: yValue, r: radius }; | ||||||
|  |       }); | ||||||
|  |        | ||||||
|  |       return { | ||||||
|  |         data: bubbleData, | ||||||
|  |         label: dataset.label || `Dataset ${index + 1}`, | ||||||
|  |         backgroundColor: dataset.backgroundColor || `rgba(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, 0.6)`, | ||||||
|  |         borderColor: dataset.borderColor || 'rgba(0, 0, 0, 1)', | ||||||
|  |         hoverBackgroundColor: dataset.hoverBackgroundColor || 'rgba(255, 255, 255, 0.8)', | ||||||
|  |         hoverBorderColor: dataset.hoverBorderColor || 'rgba(0, 0, 0, 1)' | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |    | ||||||
|   // Reset to original data (go back to base level)
 |   // Reset to original data (go back to base level)
 | ||||||
|   resetToOriginalData(): void { |   resetToOriginalData(): void { | ||||||
|     console.log('Resetting to original data'); |     console.log('Resetting to original data'); | ||||||
| @ -351,70 +427,6 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private transformToBubbleData(labels: any[], chartData: any[]): ChartDataset[] { |  | ||||||
|     // Transform the API data into bubble chart format
 |  | ||||||
|     const datasets: ChartDataset[] = []; |  | ||||||
|      |  | ||||||
|     // Create a dataset for each data series
 |  | ||||||
|     chartData.forEach((series, index) => { |  | ||||||
|       // For bubble charts, we need x, y, and r values
 |  | ||||||
|       // We'll use the labels as x values and the data as y values
 |  | ||||||
|       // For radius (r), we'll use a default value or derive it from the data
 |  | ||||||
|        |  | ||||||
|       const bubbleData = labels.map((label, i) => { |  | ||||||
|         const xValue = isNaN(Number(label)) ? i : Number(label); |  | ||||||
|         const yValue = series.data && series.data[i] !== undefined ?  |  | ||||||
|           (isNaN(Number(series.data[i])) ? 0 : Number(series.data[i])) : 0; |  | ||||||
|         // Use a default radius or derive from data
 |  | ||||||
|         const radius = Math.abs(yValue) > 0 ? Math.abs(yValue) / 10 : 5; |  | ||||||
|          |  | ||||||
|         return { |  | ||||||
|           x: xValue, |  | ||||||
|           y: yValue, |  | ||||||
|           r: radius |  | ||||||
|         }; |  | ||||||
|       }); |  | ||||||
|        |  | ||||||
|       datasets.push({ |  | ||||||
|         data: bubbleData, |  | ||||||
|         label: series.label || `Series ${index + 1}`, |  | ||||||
|         backgroundColor: this.getBackgroundColor(index), |  | ||||||
|         borderColor: this.getBorderColor(index), |  | ||||||
|         hoverBackgroundColor: this.getHoverBackgroundColor(index), |  | ||||||
|         hoverBorderColor: this.getHoverBorderColor(index), |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
|      |  | ||||||
|     return datasets; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private getBackgroundColor(index: number): string { |  | ||||||
|     const colors = [ |  | ||||||
|       'rgba(255, 0, 0, 0.6)',    // Red
 |  | ||||||
|       'rgba(0, 255, 0, 0.6)',    // Green
 |  | ||||||
|       'rgba(0, 0, 255, 0.6)',    // Blue
 |  | ||||||
|       'rgba(255, 255, 0, 0.6)',  // Yellow
 |  | ||||||
|       'rgba(255, 0, 255, 0.6)',  // Magenta
 |  | ||||||
|       'rgba(0, 255, 255, 0.6)',  // Cyan
 |  | ||||||
|     ]; |  | ||||||
|     return colors[index % colors.length]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private getBorderColor(index: number): string { |  | ||||||
|     const colors = ['blue', 'green', 'red', 'orange', 'purple', 'cyan']; |  | ||||||
|     return colors[index % colors.length]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private getHoverBackgroundColor(index: number): string { |  | ||||||
|     const colors = ['purple', 'yellow', 'orange', 'red', 'blue', 'green']; |  | ||||||
|     return colors[index % colors.length]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   private getHoverBorderColor(index: number): string { |  | ||||||
|     const colors = ['red', 'blue', 'green', 'purple', 'yellow', 'orange']; |  | ||||||
|     return colors[index % colors.length]; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // events
 |   // events
 | ||||||
|   public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Bubble chart clicked:', e); |     console.log('Bubble chart clicked:', e); | ||||||
| @ -424,18 +436,16 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|       // Get the index of the clicked element
 |       // Get the index of the clicked element
 | ||||||
|       const clickedIndex = e.active[0].index; |       const clickedIndex = e.active[0].index; | ||||||
|        |        | ||||||
|       // Get the dataset index
 |       // Get the label of the clicked element
 | ||||||
|       const datasetIndex = e.active[0].datasetIndex; |       // For bubble charts, we might not have labels in the same way as other charts
 | ||||||
|  |       const clickedLabel = `Bubble ${clickedIndex}`; | ||||||
|        |        | ||||||
|       // Get the data point
 |       console.log('Clicked on bubble:', { index: clickedIndex, label: clickedLabel }); | ||||||
|       const dataPoint = this.bubbleChartData[datasetIndex].data[clickedIndex]; |  | ||||||
|        |  | ||||||
|       console.log('Clicked on bubble:', { datasetIndex: datasetIndex, index: clickedIndex, dataPoint: dataPoint }); |  | ||||||
|        |        | ||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
|         // Store original data before entering drilldown mode
 |         // Store original data before entering drilldown mode
 | ||||||
|         this.originalBubbleChartData = JSON.parse(JSON.stringify(this.bubbleChartData)); |         this.originalBubbleChartData = [...this.bubbleChartData]; | ||||||
|         console.log('Stored original data for drilldown'); |         console.log('Stored original data for drilldown'); | ||||||
|       } |       } | ||||||
|        |        | ||||||
| @ -474,16 +484,12 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|        |        | ||||||
|       // If there's a drilldown configuration for the next level, proceed
 |       // If there's a drilldown configuration for the next level, proceed
 | ||||||
|       if (hasDrilldownConfig) { |       if (hasDrilldownConfig) { | ||||||
|         // For bubble charts, we'll use the x value as the clicked value
 |  | ||||||
|         const clickedValue = dataPoint && (dataPoint as any).x !== undefined ?  |  | ||||||
|           (dataPoint as any).x.toString() : ''; |  | ||||||
|          |  | ||||||
|         // Add this click to the drilldown stack
 |         // Add this click to the drilldown stack
 | ||||||
|         const stackEntry = { |         const stackEntry = { | ||||||
|           level: nextDrilldownLevel, |           level: nextDrilldownLevel, | ||||||
|           datasetIndex: datasetIndex, |  | ||||||
|           clickedIndex: clickedIndex, |           clickedIndex: clickedIndex, | ||||||
|           clickedValue: clickedValue |           clickedLabel: clickedLabel, | ||||||
|  |           clickedValue: clickedLabel // Using label as value for now
 | ||||||
|         }; |         }; | ||||||
|          |          | ||||||
|         this.drilldownStack.push(stackEntry); |         this.drilldownStack.push(stackEntry); | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -91,6 +92,9 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -148,6 +152,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -155,11 +160,11 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -174,9 +179,14 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -187,13 +197,28 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/doughnut?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/doughnut?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Doughnut chart data URL:', url); |       console.log('Doughnut chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'doughnut', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'doughnut', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received doughnut chart data:', data); |           console.log('Received doughnut chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -201,6 +226,10 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.doughnutChartLabels = []; |             this.doughnutChartLabels = []; | ||||||
|             this.doughnutChartData = []; |             this.doughnutChartData = []; | ||||||
|  |             // Validate and sanitize data to show default data
 | ||||||
|  |             this.validateChartData(); | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -248,31 +277,34 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.doughnutChartLabels = []; |             this.doughnutChartLabels = []; | ||||||
|             this.doughnutChartData = []; |             this.doughnutChartData = []; | ||||||
|             // Validate and sanitize data
 |             // Validate and sanitize data to show default data
 | ||||||
|             this.validateChartData(); |             this.validateChartData(); | ||||||
|           } |           } | ||||||
|            |           // Reset flag after fetching
 | ||||||
|           // Log final state for debugging
 |           this.isFetchingData = false; | ||||||
|           console.log('Final doughnut chart state:', {  |  | ||||||
|             labels: this.doughnutChartLabels,  |  | ||||||
|             data: this.doughnutChartData,  |  | ||||||
|             labelsLength: this.doughnutChartLabels.length,  |  | ||||||
|             dataLength: this.doughnutChartData.length  |  | ||||||
|           }); |  | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching doughnut chart data:', error); |           console.error('Error fetching doughnut chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.doughnutChartLabels = []; |           this.doughnutChartLabels = []; | ||||||
|           this.doughnutChartData = []; |           this.doughnutChartData = []; | ||||||
|  |           // Validate and sanitize data to show default data
 | ||||||
|  |           this.validateChartData(); | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|     } else { |     } else { | ||||||
|       console.log('Missing required data for doughnut chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); |       console.log('Missing required data for doughnut chart, showing default data:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); | ||||||
|       // Don't set noDataAvailable to true when there's no required data
 |       // Don't set noDataAvailable to true when there's no required data
 | ||||||
|       // This allows static data to be displayed
 |       // This allows static data to be displayed
 | ||||||
|       // Only validate the chart data to ensure we have some data to display
 |       this.noDataAvailable = false; | ||||||
|  |       // Validate the chart data to ensure we have some data to display
 | ||||||
|       this.validateChartData(); |       this.validateChartData(); | ||||||
|  |       // Force a redraw to ensure the chart displays
 | ||||||
|  |       this.doughnutChartData = [...this.doughnutChartData]; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -354,13 +386,27 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/doughnut?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'doughnut', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -417,20 +463,13 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck | |||||||
|           // Validate and sanitize data
 |           // Validate and sanitize data
 | ||||||
|           this.validateChartData(); |           this.validateChartData(); | ||||||
|         } |         } | ||||||
|          |  | ||||||
|         // Log final state for debugging
 |  | ||||||
|         console.log('Final doughnut chart state:', {  |  | ||||||
|           labels: this.doughnutChartLabels,  |  | ||||||
|           data: this.doughnutChartData,  |  | ||||||
|           labelsLength: this.doughnutChartLabels.length,  |  | ||||||
|           dataLength: this.doughnutChartData.length  |  | ||||||
|         }); |  | ||||||
|       }, |       }, | ||||||
|       (error) => { |       (error) => { | ||||||
|         console.error('Error fetching drilldown data:', error); |         console.error('Error fetching drilldown data:', error); | ||||||
|         this.noDataAvailable = true; |         this.noDataAvailable = true; | ||||||
|         this.doughnutChartLabels = []; |         this.doughnutChartLabels = []; | ||||||
|         this.doughnutChartData = []; |         this.doughnutChartData = []; | ||||||
|  |         // Keep current data in case of error
 | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -30,6 +30,7 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -50,6 +51,7 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -57,12 +59,11 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -100,11 +101,19 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 	 | 	 | ||||||
| 	fetchChartData(): void { | 	fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -115,13 +124,28 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/dynamic?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/dynamic?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Dynamic chart data URL:', url); |       console.log('Dynamic chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'dynamic', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'dynamic', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received dynamic chart data:', data); |           console.log('Received dynamic chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -129,6 +153,8 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.dynamicChartLabels = []; |             this.dynamicChartLabels = []; | ||||||
|             this.dynamicChartData = []; |             this.dynamicChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -155,12 +181,16 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|             this.dynamicChartLabels = []; |             this.dynamicChartLabels = []; | ||||||
|             this.dynamicChartData = []; |             this.dynamicChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching dynamic chart data:', error); |           console.error('Error fetching dynamic chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.dynamicChartLabels = []; |           this.dynamicChartLabels = []; | ||||||
|           this.dynamicChartData = []; |           this.dynamicChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
| @ -169,6 +199,8 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.dynamicChartLabels = []; |       this.dynamicChartLabels = []; | ||||||
|       this.dynamicChartData = []; |       this.dynamicChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -250,13 +282,27 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/dynamic?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'dynamic', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -356,7 +402,7 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|       this.resetToOriginalData(); |       this.resetToOriginalData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   // events
 |   // events
 | ||||||
|   public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Dynamic chart clicked:', e); |     console.log('Dynamic chart clicked:', e); | ||||||
| @ -366,13 +412,10 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|       // Get the index of the clicked element
 |       // Get the index of the clicked element
 | ||||||
|       const clickedIndex = e.active[0].index; |       const clickedIndex = e.active[0].index; | ||||||
|        |        | ||||||
|       // Get the label of the clicked element (if available)
 |       // Get the label of the clicked element
 | ||||||
|       let clickedLabel = ''; |       const clickedLabel = this.dynamicChartLabels[clickedIndex]; | ||||||
|       if (this.dynamicChartLabels && this.dynamicChartLabels[clickedIndex]) { |  | ||||||
|         clickedLabel = this.dynamicChartLabels[clickedIndex]; |  | ||||||
|       } |  | ||||||
|        |        | ||||||
|       console.log('Clicked on dynamic chart element:', { index: clickedIndex, label: clickedLabel }); |       console.log('Clicked on dynamic chart point:', { index: clickedIndex, label: clickedLabel }); | ||||||
|        |        | ||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
| @ -445,11 +488,18 @@ export class DynamicChartComponent implements OnInit, OnChanges { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 	public chartHovered(e: any): void { |   public chartHovered(e: any): void { | ||||||
| 		console.log(e); |     console.log(e); | ||||||
| 	} |   } | ||||||
| 	 |    | ||||||
|   public randomize(): void { |   public randomize(): void { | ||||||
|     this.barChartType = this.barChartType === 'bar' ? 'line' : 'bar'; |     let _dynamicChartData: Array<any> = new Array(this.dynamicChartData.length); | ||||||
|  |     for (let i = 0; i < this.dynamicChartData.length; i++) { | ||||||
|  |       _dynamicChartData[i] = {data: new Array(this.dynamicChartData[i].data.length), label: this.dynamicChartData[i].label}; | ||||||
|  |       for (let j = 0; j < this.dynamicChartData[i].data.length; j++) { | ||||||
|  |         _dynamicChartData[i].data[j] = Math.floor((Math.random() * 100) + 1); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     this.dynamicChartData = _dynamicChartData; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -28,6 +28,7 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -46,6 +47,7 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -53,12 +55,11 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -80,10 +81,18 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|    |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
|  |    | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -94,13 +103,28 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/financial?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/financial?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Financial chart data URL:', url); |       console.log('Financial chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'financial', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'financial', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received financial chart data:', data); |           console.log('Received financial chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -108,6 +132,8 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.financialChartLabels = []; |             this.financialChartLabels = []; | ||||||
|             this.financialChartData = []; |             this.financialChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -146,12 +172,16 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|             this.financialChartLabels = []; |             this.financialChartLabels = []; | ||||||
|             this.financialChartData = []; |             this.financialChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching financial chart data:', error); |           console.error('Error fetching financial chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.financialChartLabels = []; |           this.financialChartLabels = []; | ||||||
|           this.financialChartData = []; |           this.financialChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
| @ -160,6 +190,8 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.financialChartLabels = []; |       this.financialChartLabels = []; | ||||||
|       this.financialChartData = []; |       this.financialChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -241,13 +273,27 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/financial?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'financial', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -359,7 +405,7 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|       this.resetToOriginalData(); |       this.resetToOriginalData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   // events
 |   // events
 | ||||||
|   public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Financial chart clicked:', e); |     console.log('Financial chart clicked:', e); | ||||||
| @ -369,13 +415,10 @@ export class FinancialChartComponent implements OnInit, OnChanges { | |||||||
|       // Get the index of the clicked element
 |       // Get the index of the clicked element
 | ||||||
|       const clickedIndex = e.active[0].index; |       const clickedIndex = e.active[0].index; | ||||||
|        |        | ||||||
|       // Get the label of the clicked element (if available)
 |       // Get the label of the clicked element
 | ||||||
|       let clickedLabel = ''; |       const clickedLabel = this.financialChartLabels[clickedIndex]; | ||||||
|       if (this.financialChartLabels && this.financialChartLabels[clickedIndex]) { |  | ||||||
|         clickedLabel = this.financialChartLabels[clickedIndex]; |  | ||||||
|       } |  | ||||||
|        |        | ||||||
|       console.log('Clicked on financial chart element:', { index: clickedIndex, label: clickedLabel }); |       console.log('Clicked on financial chart point:', { index: clickedIndex, label: clickedLabel }); | ||||||
|        |        | ||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -77,6 +78,9 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -93,6 +97,7 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -100,12 +105,11 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -117,9 +121,14 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -130,13 +139,28 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/line?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/line?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Chart data URL:', url); |       console.log('Chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'line', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'line', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received chart data:', data); |           console.log('Received chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -144,6 +168,8 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.lineChartLabels = []; |             this.lineChartLabels = []; | ||||||
|             this.lineChartData = []; |             this.lineChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -170,12 +196,16 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|             this.lineChartLabels = []; |             this.lineChartLabels = []; | ||||||
|             this.lineChartData = []; |             this.lineChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching chart data:', error); |           console.error('Error fetching chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.lineChartLabels = []; |           this.lineChartLabels = []; | ||||||
|           this.lineChartData = []; |           this.lineChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
| @ -184,6 +214,8 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.lineChartLabels = []; |       this.lineChartLabels = []; | ||||||
|       this.lineChartData = []; |       this.lineChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -265,13 +297,27 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/line?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'line', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -372,6 +418,29 @@ export class LineChartComponent implements OnInit, OnChanges { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // Ensure labels and data arrays have the same length
 | ||||||
|  |   private syncLabelAndDataArrays(): void { | ||||||
|  |     // For line charts, we need to ensure all datasets have the same number of data points
 | ||||||
|  |     if (this.lineChartData && this.lineChartData.length > 0 && this.lineChartLabels) { | ||||||
|  |       const labelCount = this.lineChartLabels.length; | ||||||
|  |        | ||||||
|  |       this.lineChartData.forEach(dataset => { | ||||||
|  |         if (dataset.data) { | ||||||
|  |           // If dataset has more data points than labels, truncate the data
 | ||||||
|  |           if (dataset.data.length > labelCount) { | ||||||
|  |             dataset.data = dataset.data.slice(0, labelCount); | ||||||
|  |           } | ||||||
|  |           // If dataset has fewer data points than labels, pad with zeros
 | ||||||
|  |           else if (dataset.data.length < labelCount) { | ||||||
|  |             while (dataset.data.length < labelCount) { | ||||||
|  |               dataset.data.push(0); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   public randomize(): void { |   public randomize(): void { | ||||||
|     let _lineChartData: Array<any> = new Array(this.lineChartData.length); |     let _lineChartData: Array<any> = new Array(this.lineChartData.length); | ||||||
|     for (let i = 0; i < this.lineChartData.length; i++) { |     for (let i = 0; i < this.lineChartData.length; i++) { | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -90,6 +91,9 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -117,6 +121,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -124,20 +129,24 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -148,13 +157,28 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/pie?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/pie?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Pie chart data URL:', url); |       console.log('Pie chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'pie', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'pie', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received pie chart data:', data); |           console.log('Received pie chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -164,6 +188,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|             this.pieChartData = []; |             this.pieChartData = []; | ||||||
|             // Validate and sanitize data to show default data
 |             // Validate and sanitize data to show default data
 | ||||||
|             this.validateChartData(); |             this.validateChartData(); | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -214,6 +240,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|             // Validate and sanitize data to show default data
 |             // Validate and sanitize data to show default data
 | ||||||
|             this.validateChartData(); |             this.validateChartData(); | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching pie chart data:', error); |           console.error('Error fetching pie chart data:', error); | ||||||
| @ -222,6 +250,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|           this.pieChartData = []; |           this.pieChartData = []; | ||||||
|           // Validate and sanitize data to show default data
 |           // Validate and sanitize data to show default data
 | ||||||
|           this.validateChartData(); |           this.validateChartData(); | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|     } else { |     } else { | ||||||
| @ -233,6 +263,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|       this.validateChartData(); |       this.validateChartData(); | ||||||
|       // Force a redraw to ensure the chart displays
 |       // Force a redraw to ensure the chart displays
 | ||||||
|       this.pieChartData = [...this.pieChartData]; |       this.pieChartData = [...this.pieChartData]; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -314,13 +346,27 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/pie?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -443,7 +489,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked { | |||||||
|       this.resetToOriginalData(); |       this.resetToOriginalData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    | 
 | ||||||
|   /** |   /** | ||||||
|    * Get color for legend item |    * Get color for legend item | ||||||
|    * @param index Index of the legend item |    * @param index Index of the legend item | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -46,6 +47,7 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -53,12 +55,11 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -79,10 +80,18 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|    |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
|  |    | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -93,13 +102,28 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/polar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/polar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Polar chart data URL:', url); |       console.log('Polar chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'polar', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'polar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received polar chart data:', data); |           console.log('Received polar chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -107,6 +131,8 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.polarAreaChartLabels = []; |             this.polarAreaChartLabels = []; | ||||||
|             this.polarAreaChartData = []; |             this.polarAreaChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -144,12 +170,16 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|             this.polarAreaChartLabels = []; |             this.polarAreaChartLabels = []; | ||||||
|             this.polarAreaChartData = []; |             this.polarAreaChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching polar chart data:', error); |           console.error('Error fetching polar chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.polarAreaChartLabels = []; |           this.polarAreaChartLabels = []; | ||||||
|           this.polarAreaChartData = []; |           this.polarAreaChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
| @ -158,6 +188,8 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.polarAreaChartLabels = []; |       this.polarAreaChartLabels = []; | ||||||
|       this.polarAreaChartData = []; |       this.polarAreaChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -239,13 +271,27 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/polar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'polar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -358,7 +404,7 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // events
 |   // events
 | ||||||
| 	public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Polar chart clicked:', e); |     console.log('Polar chart clicked:', e); | ||||||
|      |      | ||||||
|     // If drilldown is enabled and we have a valid click event
 |     // If drilldown is enabled and we have a valid click event
 | ||||||
| @ -369,7 +415,7 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|       // Get the label of the clicked element
 |       // Get the label of the clicked element
 | ||||||
|       const clickedLabel = this.polarAreaChartLabels[clickedIndex]; |       const clickedLabel = this.polarAreaChartLabels[clickedIndex]; | ||||||
|        |        | ||||||
|       console.log('Clicked on polar slice:', { index: clickedIndex, label: clickedLabel }); |       console.log('Clicked on polar area:', { index: clickedIndex, label: clickedLabel }); | ||||||
|        |        | ||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
| @ -440,10 +486,9 @@ export class PolarChartComponent implements OnInit, OnChanges { | |||||||
|     } else { |     } else { | ||||||
|       console.log('Drilldown not enabled or invalid click event'); |       console.log('Drilldown not enabled or invalid click event'); | ||||||
|     } |     } | ||||||
| 	} |   } | ||||||
| 
 |  | ||||||
| 	public chartHovered(e: any): void { |  | ||||||
| 		console.log(e); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
|  |   public chartHovered(e: any): void { | ||||||
|  |     console.log(e); | ||||||
|  |   } | ||||||
| } | } | ||||||
| @ -28,6 +28,7 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -56,6 +57,9 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
| 
 | 
 | ||||||
|   constructor(private dashboardService: Dashboard3Service) { } |   constructor(private dashboardService: Dashboard3Service) { } | ||||||
| 
 | 
 | ||||||
| @ -71,6 +75,7 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -78,19 +83,24 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -101,13 +111,28 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/radar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/radar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Radar chart data URL:', url); |       console.log('Radar chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'radar', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'radar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received radar chart data:', data); |           console.log('Received radar chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
| @ -115,6 +140,8 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.radarChartLabels = []; |             this.radarChartLabels = []; | ||||||
|             this.radarChartData = []; |             this.radarChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -155,12 +182,16 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|             this.radarChartLabels = []; |             this.radarChartLabels = []; | ||||||
|             this.radarChartData = []; |             this.radarChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching radar chart data:', error); |           console.error('Error fetching radar chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.radarChartLabels = []; |           this.radarChartLabels = []; | ||||||
|           this.radarChartData = []; |           this.radarChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|     } else { |     } else { | ||||||
| @ -168,6 +199,8 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.radarChartLabels = []; |       this.radarChartLabels = []; | ||||||
|       this.radarChartData = []; |       this.radarChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -249,13 +282,27 @@ export class RadarChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // 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}` : ''}`; |     const url = `chart/getdashjson/radar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the 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).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'radar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownXAxis: string; |   @Input() drilldownXAxis: string; | ||||||
|   @Input() drilldownYAxis: string; |   @Input() drilldownYAxis: string; | ||||||
|   @Input() drilldownParameter: string; // Add drilldown parameter input
 |   @Input() drilldownParameter: string; // Add drilldown parameter input
 | ||||||
|  |   @Input() baseFilters: any[] = []; // Add base filters input
 | ||||||
|   // Multi-layer drilldown configuration inputs
 |   // Multi-layer drilldown configuration inputs
 | ||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
| @ -47,6 +48,7 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; |     const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange; | ||||||
|     const tableChanged = changes.table && !changes.table.firstChange; |     const tableChanged = changes.table && !changes.table.firstChange; | ||||||
|     const connectionChanged = changes.connection && !changes.connection.firstChange; |     const connectionChanged = changes.connection && !changes.connection.firstChange; | ||||||
|  |     const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange; | ||||||
|     // Drilldown configuration changes
 |     // Drilldown configuration changes
 | ||||||
|     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; |     const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange; | ||||||
|     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; |     const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange; | ||||||
| @ -54,12 +56,11 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; |     const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange; | ||||||
|     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; |     const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange; | ||||||
|      |      | ||||||
|     // Respond to input changes
 |     // Only fetch data if the actual chart configuration changed and we're not already fetching
 | ||||||
|     if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||  |     if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || | ||||||
|         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || |         drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || | ||||||
|         drilldownLayersChanged) { |         drilldownLayersChanged)) { | ||||||
|       console.log('X or Y axis or table or connection or drilldown config changed, fetching new data'); |       console.log('Chart configuration changed, fetching new data'); | ||||||
|       // Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
 |  | ||||||
|       this.fetchChartData(); |       this.fetchChartData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -101,10 +102,18 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|    |    | ||||||
|  |   // Flag to prevent infinite loops
 | ||||||
|  |   private isFetchingData: boolean = false; | ||||||
|  |    | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|  |     // Set flag to prevent recursive calls
 | ||||||
|  |     this.isFetchingData = true; | ||||||
|  |      | ||||||
|     // If we're in drilldown mode, fetch the appropriate drilldown data
 |     // If we're in drilldown mode, fetch the appropriate drilldown data
 | ||||||
|     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { |     if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -115,19 +124,36 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|       // Convert yAxis to string if it's an array
 |       // Convert yAxis to string if it's an array
 | ||||||
|       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; |       const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis; | ||||||
|        |        | ||||||
|  |       // Convert baseFilters to filter parameters
 | ||||||
|  |       let filterParams = ''; | ||||||
|  |       if (this.baseFilters && this.baseFilters.length > 0) { | ||||||
|  |         const filterObj = {}; | ||||||
|  |         this.baseFilters.forEach(filter => { | ||||||
|  |           if (filter.field && filter.value) { | ||||||
|  |             filterObj[filter.field] = filter.value; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |         if (Object.keys(filterObj).length > 0) { | ||||||
|  |           filterParams = JSON.stringify(filterObj); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       console.log('Base filter parameters:', filterParams); | ||||||
|  |        | ||||||
|       // Log the URL that will be called
 |       // Log the URL that will be called
 | ||||||
|       const url = `chart/getdashjson/scatter?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; |       const url = `chart/getdashjson/scatter?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|       console.log('Scatter chart data URL:', url); |       console.log('Scatter chart data URL:', url); | ||||||
|        |        | ||||||
|       // Fetch data from the dashboard service with parameter field and value
 |       // Fetch data from the dashboard service with parameter field and value
 | ||||||
|       // For base level, we pass empty parameter and value
 |       // For base level, we pass empty parameter and value, but now also pass filters
 | ||||||
|       this.dashboardService.getChartData(this.table, 'scatter', this.xAxis, yAxisString, this.connection, '', '').subscribe( |       this.dashboardService.getChartData(this.table, 'scatter', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( | ||||||
|         (data: any) => { |         (data: any) => { | ||||||
|           console.log('Received scatter chart data:', data); |           console.log('Received scatter chart data:', data); | ||||||
|           if (data === null) { |           if (data === null) { | ||||||
|             console.warn('Scatter chart API returned null data. Check if the API endpoint is working correctly.'); |             console.warn('Scatter chart API returned null data. Check if the API endpoint is working correctly.'); | ||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.scatterChartData = []; |             this.scatterChartData = []; | ||||||
|  |             // Reset flag after fetching
 | ||||||
|  |             this.isFetchingData = false; | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|            |            | ||||||
| @ -148,11 +174,15 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.scatterChartData = []; |             this.scatterChartData = []; | ||||||
|           } |           } | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
|         (error) => { |         (error) => { | ||||||
|           console.error('Error fetching scatter chart data:', error); |           console.error('Error fetching scatter chart data:', error); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.scatterChartData = []; |           this.scatterChartData = []; | ||||||
|  |           // Reset flag after fetching
 | ||||||
|  |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |           // Keep default data in case of error
 | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
| @ -160,6 +190,8 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('Missing required data for scatter chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); |       console.log('Missing required data for scatter chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); | ||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.scatterChartData = []; |       this.scatterChartData = []; | ||||||
|  |       // Reset flag after fetching
 | ||||||
|  |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |    | ||||||
| @ -239,13 +271,27 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|       console.log('URL after angle bracket replacement:', actualApiUrl); |       console.log('URL after angle bracket replacement:', actualApiUrl); | ||||||
|     } |     } | ||||||
|      |      | ||||||
|  |     // Convert drilldown layer filters to filter parameters (if applicable)
 | ||||||
|  |     let filterParams = ''; | ||||||
|  |     if (drilldownConfig.filters && drilldownConfig.filters.length > 0) { | ||||||
|  |       const filterObj = {}; | ||||||
|  |       drilldownConfig.filters.forEach((filter: any) => { | ||||||
|  |         if (filter.field && filter.value) { | ||||||
|  |           filterObj[filter.field] = filter.value; | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |       if (Object.keys(filterObj).length > 0) { | ||||||
|  |         filterParams = JSON.stringify(filterObj); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // Log the URL that will be called
 |     // Log the URL that will be called
 | ||||||
|     const url = `chart/getdashjson/scatter?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; |     const url = `chart/getdashjson/scatter?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`; | ||||||
|     console.log('Drilldown data URL:', url); |     console.log('Drilldown data URL:', url); | ||||||
|      |      | ||||||
|     // Fetch data from the dashboard service with parameter field and value
 |     // Fetch data from the dashboard service with parameter field and value
 | ||||||
|     // Backend handles filtering, we just pass the parameter field and value
 |     // Backend handles filtering, we just pass the parameter field and value
 | ||||||
|     this.dashboardService.getChartData(actualApiUrl, 'scatter', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe( |     this.dashboardService.getChartData(actualApiUrl, 'scatter', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( | ||||||
|       (data: any) => { |       (data: any) => { | ||||||
|         console.log('Received drilldown data:', data); |         console.log('Received drilldown data:', data); | ||||||
|         if (data === null) { |         if (data === null) { | ||||||
| @ -282,6 +328,33 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|  |   // Transform chart data to scatter chart format
 | ||||||
|  |   private transformToScatterData(labels: string[], datasets: any[]): ChartDataset[] { | ||||||
|  |     // For scatter charts, we need to transform the data into scatter format
 | ||||||
|  |     // Scatter charts expect data in the format: {x: number, y: number}
 | ||||||
|  |      | ||||||
|  |     // This is a simple transformation - in a real implementation, you might want to
 | ||||||
|  |     // create a more sophisticated mapping based on your data structure
 | ||||||
|  |     return datasets.map((dataset, index) => { | ||||||
|  |       // Create scatter data points
 | ||||||
|  |       const scatterData = labels.map((label, i) => { | ||||||
|  |         // Use x-axis data as x coordinate, y-axis data as y coordinate
 | ||||||
|  |         const xValue = dataset.data[i] || 0; | ||||||
|  |         const yValue = i < datasets.length ? (datasets[i].data[index] || 0) : 0; | ||||||
|  |          | ||||||
|  |         return { x: xValue, y: yValue }; | ||||||
|  |       }); | ||||||
|  |        | ||||||
|  |       return { | ||||||
|  |         data: scatterData, | ||||||
|  |         label: dataset.label || `Dataset ${index + 1}`, | ||||||
|  |         backgroundColor: dataset.backgroundColor || `rgba(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, 0.6)`, | ||||||
|  |         borderColor: dataset.borderColor || 'rgba(0, 0, 0, 1)', | ||||||
|  |         pointRadius: dataset.pointRadius || 5 | ||||||
|  |       }; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |    | ||||||
|   // Reset to original data (go back to base level)
 |   // Reset to original data (go back to base level)
 | ||||||
|   resetToOriginalData(): void { |   resetToOriginalData(): void { | ||||||
|     console.log('Resetting to original data'); |     console.log('Resetting to original data'); | ||||||
| @ -332,48 +405,9 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|       this.resetToOriginalData(); |       this.resetToOriginalData(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|    |  | ||||||
|   private transformToScatterData(labels: any[], chartData: any[]): ChartDataset[] { |  | ||||||
|     // Transform the API data into scatter chart format
 |  | ||||||
|     const datasets: ChartDataset[] = []; |  | ||||||
|      |  | ||||||
|     // Create a dataset for each data series
 |  | ||||||
|     chartData.forEach((series, index) => { |  | ||||||
|       // For scatter charts, we need x and y values
 |  | ||||||
|       // We'll use the labels as x values and the data as y values
 |  | ||||||
|        |  | ||||||
|       const scatterData = labels.map((label, i) => { |  | ||||||
|         const xValue = isNaN(Number(label)) ? i : Number(label); |  | ||||||
|         const yValue = series.data && series.data[i] !== undefined ?  |  | ||||||
|           (isNaN(Number(series.data[i])) ? 0 : Number(series.data[i])) : 0; |  | ||||||
|          |  | ||||||
|         return { |  | ||||||
|           x: xValue, |  | ||||||
|           y: yValue |  | ||||||
|         }; |  | ||||||
|       }); |  | ||||||
|        |  | ||||||
|       datasets.push({ |  | ||||||
|         data: scatterData, |  | ||||||
|         label: series.label || `Series ${index + 1}`, |  | ||||||
|         pointRadius: 10, |  | ||||||
|         backgroundColor: this.getBackgroundColor(index), |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
|      |  | ||||||
|     return datasets; |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   private getBackgroundColor(index: number): string { |  | ||||||
|     const colors = [ |  | ||||||
|       'red', 'green', 'blue', 'purple', 'yellow',  |  | ||||||
|       'brown', 'magenta', 'cyan', 'orange', 'pink' |  | ||||||
|     ]; |  | ||||||
|     return colors[index % colors.length]; |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|    // events
 |   // events
 | ||||||
| 	public chartClicked(e: any): void { |   public chartClicked(e: any): void { | ||||||
|     console.log('Scatter chart clicked:', e); |     console.log('Scatter chart clicked:', e); | ||||||
|      |      | ||||||
|     // If drilldown is enabled and we have a valid click event
 |     // If drilldown is enabled and we have a valid click event
 | ||||||
| @ -381,18 +415,16 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|       // Get the index of the clicked element
 |       // Get the index of the clicked element
 | ||||||
|       const clickedIndex = e.active[0].index; |       const clickedIndex = e.active[0].index; | ||||||
|        |        | ||||||
|       // Get the dataset index
 |       // Get the label of the clicked element
 | ||||||
|       const datasetIndex = e.active[0].datasetIndex; |       // For scatter charts, we might not have labels in the same way as other charts
 | ||||||
|  |       const clickedLabel = `Point ${clickedIndex}`; | ||||||
|        |        | ||||||
|       // Get the data point
 |       console.log('Clicked on scatter point:', { index: clickedIndex, label: clickedLabel }); | ||||||
|       const dataPoint = this.scatterChartData[datasetIndex].data[clickedIndex]; |  | ||||||
|        |  | ||||||
|       console.log('Clicked on scatter point:', { datasetIndex: datasetIndex, index: clickedIndex, dataPoint: dataPoint }); |  | ||||||
|        |        | ||||||
|       // If we're not at the base level, store original data
 |       // If we're not at the base level, store original data
 | ||||||
|       if (this.currentDrilldownLevel === 0) { |       if (this.currentDrilldownLevel === 0) { | ||||||
|         // Store original data before entering drilldown mode
 |         // Store original data before entering drilldown mode
 | ||||||
|         this.originalScatterChartData = JSON.parse(JSON.stringify(this.scatterChartData)); |         this.originalScatterChartData = [...this.scatterChartData]; | ||||||
|         console.log('Stored original data for drilldown'); |         console.log('Stored original data for drilldown'); | ||||||
|       } |       } | ||||||
|        |        | ||||||
| @ -431,16 +463,12 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|        |        | ||||||
|       // If there's a drilldown configuration for the next level, proceed
 |       // If there's a drilldown configuration for the next level, proceed
 | ||||||
|       if (hasDrilldownConfig) { |       if (hasDrilldownConfig) { | ||||||
|         // For scatter charts, we'll use the x value as the clicked value
 |  | ||||||
|         const clickedValue = dataPoint && (dataPoint as any).x !== undefined ?  |  | ||||||
|           (dataPoint as any).x.toString() : ''; |  | ||||||
|          |  | ||||||
|         // Add this click to the drilldown stack
 |         // Add this click to the drilldown stack
 | ||||||
|         const stackEntry = { |         const stackEntry = { | ||||||
|           level: nextDrilldownLevel, |           level: nextDrilldownLevel, | ||||||
|           datasetIndex: datasetIndex, |  | ||||||
|           clickedIndex: clickedIndex, |           clickedIndex: clickedIndex, | ||||||
|           clickedValue: clickedValue |           clickedLabel: clickedLabel, | ||||||
|  |           clickedValue: clickedLabel // Using label as value for now
 | ||||||
|         }; |         }; | ||||||
|          |          | ||||||
|         this.drilldownStack.push(stackEntry); |         this.drilldownStack.push(stackEntry); | ||||||
| @ -461,9 +489,9 @@ export class ScatterChartComponent implements OnInit, OnChanges { | |||||||
|     } else { |     } else { | ||||||
|       console.log('Drilldown not enabled or invalid click event'); |       console.log('Drilldown not enabled or invalid click event'); | ||||||
|     } |     } | ||||||
| 	} |   } | ||||||
| 
 | 
 | ||||||
| 	public chartHovered(e: any): void { |   public chartHovered(e: any): void { | ||||||
| 		console.log(e); |     console.log(e); | ||||||
| 	} |   } | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user