bubble
This commit is contained in:
		
							parent
							
								
									9b775a8c63
								
							
						
					
					
						commit
						ad57f11f8a
					
				| @ -279,19 +279,31 @@ | |||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|    |    | ||||||
|   <!-- No data message --> |   <!-- Chart container --> | ||||||
|   <div *ngIf="noDataAvailable" style="text-align: center; padding: 20px; color: #666; font-style: italic;"> |   <div style="position: relative; height: calc(100% - 50px); width: 100%;"> | ||||||
|     No data available |     <!-- Loading indicator --> | ||||||
|   </div> |     <div *ngIf="!dataLoaded" style="text-align: center; padding: 20px; color: #666; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; width: 100%;"> | ||||||
|    |       Loading data... | ||||||
|   <!-- Chart display --> |     </div> | ||||||
|   <div *ngIf="!noDataAvailable" style="position: relative; height: calc(100% - 50px);"> |      | ||||||
|  |     <!-- No data message --> | ||||||
|  |     <div *ngIf="dataLoaded && (noDataAvailable || !isChartDataValid())" style="text-align: center; padding: 20px; color: #666; font-style: italic; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; width: 100%;"> | ||||||
|  |       No data available | ||||||
|  |     </div> | ||||||
|  |      | ||||||
|  |     <!-- Chart display - Always render the canvas but conditionally show/hide with CSS --> | ||||||
|     <canvas baseChart |     <canvas baseChart | ||||||
|     [datasets]="bubbleChartData" |     [datasets]="bubbleChartData" | ||||||
|     [type]="bubbleChartType" |     [type]="bubbleChartType" | ||||||
|     [options]="bubbleChartOptions" |     [options]="bubbleChartOptions" | ||||||
|     (chartHover)="chartHovered($event)" |     (chartHover)="chartHovered($event)" | ||||||
|     (chartClick)="chartClicked($event)"> |     (chartClick)="chartClicked($event)" | ||||||
|  |     [style.visibility]="dataLoaded && !noDataAvailable && isChartDataValid() ? 'visible' : 'hidden'" | ||||||
|  |     [style.position]="'absolute'" | ||||||
|  |     [style.top]="'0'" | ||||||
|  |     [style.left]="'0'" | ||||||
|  |     [style.height]="'100%'" | ||||||
|  |     [style.width]="'100%'"> | ||||||
|   </canvas> |   </canvas> | ||||||
|   </div> |   </div> | ||||||
| </div> | </div> | ||||||
| @ -37,55 +37,43 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 |   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||||
| 
 | 
 | ||||||
|   public bubbleChartOptions: ChartConfiguration['options'] = { |   public bubbleChartOptions: ChartConfiguration['options'] = { | ||||||
|     // scales: {
 |     responsive: true, | ||||||
|     //   x: {
 |     maintainAspectRatio: false, | ||||||
|     //     min: 0,
 |     scales: { | ||||||
|     //     max: 30,
 |       x: { | ||||||
|     //     ticks: {}
 |         beginAtZero: true, | ||||||
|     //   },
 |         title: { | ||||||
|     //   y: {
 |           display: true, | ||||||
|     //     min: 0,
 |           text: 'X Axis' | ||||||
|     //     max: 30,
 |         } | ||||||
|     //     ticks: {}
 |       }, | ||||||
|     //   },
 |       y: { | ||||||
|     //   plugins: {
 |         beginAtZero: true, | ||||||
|     //     title: {
 |         title: { | ||||||
|     //       display: true,
 |           display: true, | ||||||
|     //       text: 'Bubble Chart'
 |           text: 'Y Axis' | ||||||
|     //     }
 |         } | ||||||
|     //   }
 |       } | ||||||
|     // }
 |     }, | ||||||
|  |     plugins: { | ||||||
|  |       legend: { | ||||||
|  |         display: true, | ||||||
|  |         position: 'top', | ||||||
|  |       }, | ||||||
|  |       tooltip: { | ||||||
|  |         enabled: true, | ||||||
|  |         mode: 'point', | ||||||
|  |         intersect: false | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     animation: { | ||||||
|  |       duration: 800, | ||||||
|  |       easing: 'easeInOutQuart' | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   public bubbleChartType: string = 'bubble'; |   public bubbleChartType: string = 'bubble'; | ||||||
|   public bubbleChartData: ChartDataset[] = [ |   public bubbleChartData: ChartDataset[] = []; | ||||||
|     { |  | ||||||
|       data: [ |  | ||||||
|         { x: 10, y: 10, r: 10 }, |  | ||||||
|         { x: 15, y: 5, r: 15 }, |  | ||||||
|         { x: 26, y: 12, r: 23 }, |  | ||||||
|         { x: 7, y: 8, r: 8 }, |  | ||||||
|       ], |  | ||||||
|       label: 'Investment Equities', |  | ||||||
|       backgroundColor: 'rgba(255, 0, 0, 0.6)', // Red
 |  | ||||||
|       borderColor: 'blue', |  | ||||||
|       hoverBackgroundColor: 'purple', |  | ||||||
|       hoverBorderColor: 'red', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       data: [ |  | ||||||
|         { x: 5, y: 15, r: 12 }, |  | ||||||
|         { x: 20, y: 7, r: 8 }, |  | ||||||
|         { x: 12, y: 18, r: 15 }, |  | ||||||
|         { x: 8, y: 6, r: 10 }, |  | ||||||
|       ], |  | ||||||
|       label: 'Investment Bonds', |  | ||||||
|       backgroundColor: 'rgba(0, 255, 0, 0.6)', // Green
 |  | ||||||
|       borderColor: 'green', |  | ||||||
|       hoverBackgroundColor: 'yellow', |  | ||||||
|       hoverBorderColor: 'blue', |  | ||||||
|     }, |  | ||||||
|   ]; |  | ||||||
|    |    | ||||||
|   // Multi-layer drilldown state tracking
 |   // Multi-layer drilldown state tracking
 | ||||||
|   drilldownStack: any[] = []; // Stack to track drilldown navigation history
 |   drilldownStack: any[] = []; // Stack to track drilldown navigation history
 | ||||||
| @ -94,6 +82,7 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|    |    | ||||||
|   // No data state
 |   // No data state
 | ||||||
|   noDataAvailable: boolean = false; |   noDataAvailable: boolean = false; | ||||||
|  |   dataLoaded: boolean = false; // Track if data has been loaded
 | ||||||
|    |    | ||||||
|   // Flag to prevent infinite loops
 |   // Flag to prevent infinite loops
 | ||||||
|   private isFetchingData: boolean = false; |   private isFetchingData: boolean = false; | ||||||
| @ -471,39 +460,126 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     // Bubble charts expect data in the format: {x: number, y: number, r: number}
 |     // Bubble charts expect data in the format: {x: number, y: number, r: number}
 | ||||||
|     console.log('Transforming data to bubble format:', { labels, data }); |     console.log('Transforming data to bubble format:', { labels, data }); | ||||||
|      |      | ||||||
|  |     // Handle null/undefined data
 | ||||||
|  |     if (!labels || !data) { | ||||||
|  |       console.log('Labels or data is null/undefined, returning empty dataset'); | ||||||
|  |       return []; | ||||||
|  |     } | ||||||
|  |      | ||||||
|     // If we have the expected bubble data format, return it as is
 |     // If we have the expected bubble data format, return it as is
 | ||||||
|     if (data && data.length > 0 && data[0].data && data[0].data.length > 0 &&  |     if (data && data.length > 0 && data[0].data && data[0].data.length > 0 &&  | ||||||
|         typeof data[0].data[0] === 'object' && data[0].data[0].hasOwnProperty('x') &&  |         typeof data[0].data[0] === 'object' && data[0].data[0].hasOwnProperty('x') &&  | ||||||
|         data[0].data[0].hasOwnProperty('y') && data[0].data[0].hasOwnProperty('r')) { |         data[0].data[0].hasOwnProperty('y') && data[0].data[0].hasOwnProperty('r')) { | ||||||
|  |       console.log('Data is already in bubble format, returning as is'); | ||||||
|       return data; |       return data; | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     // Otherwise, create a default bubble dataset
 |     // Transform the data properly for bubble chart
 | ||||||
|     const bubbleDatasets: ChartDataset[] = [ |     // Assuming labels are x-values and data[0].data are y-values
 | ||||||
|       { |     if (labels && data && data.length > 0 && data[0].data) { | ||||||
|         data: [ |       console.log('Transforming regular data to bubble format'); | ||||||
|           { x: 10, y: 10, r: 10 }, |       const yValues = data[0].data; | ||||||
|           { x: 15, y: 5, r: 15 }, |       const label = data[0].label || 'Dataset 1'; | ||||||
|           { x: 26, y: 12, r: 23 }, |        | ||||||
|           { x: 7, y: 8, r: 8 }, |       // Handle case where yValues might not be an array
 | ||||||
|         ], |       if (!Array.isArray(yValues)) { | ||||||
|         label: 'Dataset 1', |         console.log('yValues is not an array, returning empty dataset'); | ||||||
|         backgroundColor: 'rgba(255, 0, 0, 0.6)', |         return []; | ||||||
|         borderColor: 'blue', |  | ||||||
|         hoverBackgroundColor: 'purple', |  | ||||||
|         hoverBorderColor: 'red', |  | ||||||
|       } |       } | ||||||
|     ]; |        | ||||||
|  |       console.log('yValues type:', typeof yValues); | ||||||
|  |       console.log('yValues length:', yValues.length); | ||||||
|  |       console.log('First few yValues:', yValues.slice(0, 5)); | ||||||
|  |        | ||||||
|  |       // Create bubble points from labels (x) and data (y)
 | ||||||
|  |       const bubblePoints = []; | ||||||
|  |       const minLength = Math.min(labels.length, yValues.length); | ||||||
|  |        | ||||||
|  |       console.log('Processing data points:', { labels, yValues, minLength }); | ||||||
|  |        | ||||||
|  |       for (let i = 0; i < minLength; i++) { | ||||||
|  |         // Log each point for debugging
 | ||||||
|  |         console.log(`Processing point ${i}: label=${labels[i]}, yValue=${yValues[i]}, type=${typeof yValues[i]}`); | ||||||
|  |          | ||||||
|  |         // Convert y to number if it's a string
 | ||||||
|  |         let y; | ||||||
|  |         if (typeof yValues[i] === 'string') { | ||||||
|  |           y = parseFloat(yValues[i]); | ||||||
|  |           console.log(`Converted string yValue to number: ${yValues[i]} -> ${y}`); | ||||||
|  |         } else { | ||||||
|  |           y = yValues[i]; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Handle NaN values
 | ||||||
|  |         if (isNaN(y)) { | ||||||
|  |           console.log(`Skipping point ${i} due to NaN y value: ${yValues[i]}`); | ||||||
|  |           continue; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Calculate radius based on the y-value
 | ||||||
|  |         const r = Math.max(5, Math.min(30, Math.abs(y) / 10)); | ||||||
|  |          | ||||||
|  |         // For x-value, we'll use the index position since labels are strings
 | ||||||
|  |         const x = i; | ||||||
|  |          | ||||||
|  |         // Add the point
 | ||||||
|  |         const point = {  | ||||||
|  |           x,  | ||||||
|  |           y,  | ||||||
|  |           r | ||||||
|  |         }; | ||||||
|  |         console.log(`Adding point ${i}:`, point); | ||||||
|  |         bubblePoints.push(point); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       console.log('Generated bubble points:', bubblePoints); | ||||||
|  |       console.log('Generated bubble points count:', bubblePoints.length); | ||||||
|  |        | ||||||
|  |       // If we have no valid points, return empty array
 | ||||||
|  |       if (bubblePoints.length === 0) { | ||||||
|  |         console.log('No valid bubble points generated, returning empty dataset'); | ||||||
|  |         return []; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Create a single dataset with all bubble points
 | ||||||
|  |       const bubbleDatasets: ChartDataset[] = [ | ||||||
|  |         { | ||||||
|  |           data: bubblePoints, | ||||||
|  |           label: label, | ||||||
|  |           backgroundColor: 'rgba(255, 99, 132, 0.6)', | ||||||
|  |           borderColor: 'rgba(255, 99, 132, 1)', | ||||||
|  |           hoverBackgroundColor: 'rgba(255, 99, 132, 0.8)', | ||||||
|  |           hoverBorderColor: 'rgba(255, 99, 132, 1)', | ||||||
|  |           borderWidth: 1, | ||||||
|  |           pointHoverRadius: 10, | ||||||
|  |         } | ||||||
|  |       ]; | ||||||
|  |        | ||||||
|  |       console.log('Transformed bubble data:', bubbleDatasets); | ||||||
|  |       return bubbleDatasets; | ||||||
|  |     } | ||||||
|      |      | ||||||
|     return bubbleDatasets; |     console.log('Could not transform data, returning empty dataset'); | ||||||
|  |     // Return empty dataset instead of default data
 | ||||||
|  |     return []; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   fetchChartData(): void { |   fetchChartData(): void { | ||||||
|     // Set flag to prevent recursive calls
 |     // Set flag to prevent recursive calls
 | ||||||
|     this.isFetchingData = true; |     this.isFetchingData = true; | ||||||
|  |     this.dataLoaded = false; // Mark data as not loaded yet
 | ||||||
|  |     this.noDataAvailable = false; // Reset no data flag
 | ||||||
|  |      | ||||||
|  |     console.log('Starting fetchChartData, current state:', { | ||||||
|  |       table: this.table, | ||||||
|  |       xAxis: this.xAxis, | ||||||
|  |       yAxis: this.yAxis, | ||||||
|  |       connection: this.connection | ||||||
|  |     }); | ||||||
|      |      | ||||||
|     // 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) { | ||||||
|  |       console.log('Fetching drilldown data'); | ||||||
|       this.fetchDrilldownData(); |       this.fetchDrilldownData(); | ||||||
|       // Reset flag after fetching
 |       // Reset flag after fetching
 | ||||||
|       this.isFetchingData = false; |       this.isFetchingData = false; | ||||||
| @ -583,32 +659,82 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|       this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '', filterParams).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) { |  | ||||||
|             console.warn('Bubble chart API returned null data. Check if the API endpoint is working correctly.'); |  | ||||||
|             this.noDataAvailable = true; |  | ||||||
|             this.bubbleChartData = []; |  | ||||||
|             // Reset flag after fetching
 |  | ||||||
|             this.isFetchingData = false; |  | ||||||
|             return; |  | ||||||
|           } |  | ||||||
|            |            | ||||||
|           // Handle the actual data structure returned by the API
 |           // Reset chart data to empty first
 | ||||||
|           if (data && data.chartLabels && data.chartData) { |           this.bubbleChartData = []; | ||||||
|  |            | ||||||
|  |           if (data === null || data === undefined) { | ||||||
|  |             console.warn('Bubble chart API returned null/undefined data. Check if the API endpoint is working correctly.'); | ||||||
|  |             this.noDataAvailable = true; | ||||||
|  |           } else if (data && data.chartLabels && data.chartData) { | ||||||
|             // For bubble charts, we need to transform the data into bubble format
 |             // 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}
 |             // Bubble charts expect data in the format: {x: number, y: number, r: number}
 | ||||||
|             this.noDataAvailable = data.chartLabels.length === 0; |             console.log('Processing chartLabels and chartData format'); | ||||||
|             this.bubbleChartData = this.transformToBubbleData(data.chartLabels, data.chartData); |             const transformedData = this.transformToBubbleData(data.chartLabels, data.chartData); | ||||||
|             console.log('Updated bubble chart with data:', this.bubbleChartData); |             console.log('Transformed data:', transformedData); | ||||||
|  |              | ||||||
|  |             // Check if we have valid data
 | ||||||
|  |             let hasValidData = false; | ||||||
|  |             if (transformedData && transformedData.length > 0) { | ||||||
|  |               for (const dataset of transformedData) { | ||||||
|  |                 if (dataset.data && dataset.data.length > 0) { | ||||||
|  |                   hasValidData = true; | ||||||
|  |                   break; | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (hasValidData) { | ||||||
|  |               // Create a new array reference to trigger change detection
 | ||||||
|  |               this.bubbleChartData = [...transformedData]; | ||||||
|  |               this.noDataAvailable = false; | ||||||
|  |               console.log('Updated bubble chart with data:', this.bubbleChartData); | ||||||
|  |             } else { | ||||||
|  |               console.log('No valid data after transformation'); | ||||||
|  |               this.noDataAvailable = true; | ||||||
|  |             } | ||||||
|           } else if (data && data.labels && data.datasets) { |           } else if (data && data.labels && data.datasets) { | ||||||
|             // Handle the original expected format as fallback
 |             // Handle the original expected format as fallback
 | ||||||
|             this.noDataAvailable = data.labels.length === 0; |             console.log('Processing labels and datasets format'); | ||||||
|             this.bubbleChartData = data.datasets; |             // Check if we have valid data
 | ||||||
|             console.log('Updated bubble chart with legacy data format:', this.bubbleChartData); |             let hasValidData = false; | ||||||
|  |             if (data.datasets && data.datasets.length > 0) { | ||||||
|  |               for (const dataset of data.datasets) { | ||||||
|  |                 if (dataset.data && dataset.data.length > 0) { | ||||||
|  |                   hasValidData = true; | ||||||
|  |                   break; | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (hasValidData) { | ||||||
|  |               // Create a new array reference to trigger change detection
 | ||||||
|  |               this.bubbleChartData = [...data.datasets]; | ||||||
|  |               this.noDataAvailable = false; | ||||||
|  |               console.log('Updated bubble chart with legacy data format:', this.bubbleChartData); | ||||||
|  |             } else { | ||||||
|  |               console.log('No valid data in legacy format'); | ||||||
|  |               this.noDataAvailable = true; | ||||||
|  |             } | ||||||
|           } else { |           } else { | ||||||
|             console.warn('Bubble chart received data does not have expected structure', data); |             console.warn('Bubble chart received data does not have expected structure', data); | ||||||
|             this.noDataAvailable = true; |             this.noDataAvailable = true; | ||||||
|             this.bubbleChartData = []; |  | ||||||
|           } |           } | ||||||
|  |            | ||||||
|  |           this.dataLoaded = true; // Mark data as loaded
 | ||||||
|  |            | ||||||
|  |           console.log('Final state after data fetch:', { | ||||||
|  |             noDataAvailable: this.noDataAvailable, | ||||||
|  |             dataLoaded: this.dataLoaded, | ||||||
|  |             bubbleChartDataLength: this.bubbleChartData.length, | ||||||
|  |             isChartDataValid: this.isChartDataValid() | ||||||
|  |           }); | ||||||
|  |            | ||||||
|  |           // Trigger change detection with a small delay to ensure proper rendering
 | ||||||
|  |           setTimeout(() => { | ||||||
|  |             this.forceChartUpdate(); | ||||||
|  |           }, 100); | ||||||
|  |            | ||||||
|           // Reset flag after fetching
 |           // Reset flag after fetching
 | ||||||
|           this.isFetchingData = false; |           this.isFetchingData = false; | ||||||
|         }, |         }, | ||||||
| @ -616,15 +742,24 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|           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 = []; | ||||||
|  |           this.dataLoaded = true; | ||||||
|  |           // Trigger change detection
 | ||||||
|  |           setTimeout(() => { | ||||||
|  |             this.forceChartUpdate(); | ||||||
|  |           }, 100); | ||||||
|           // Reset flag after fetching
 |           // Reset flag after fetching
 | ||||||
|           this.isFetchingData = false; |           this.isFetchingData = false; | ||||||
|           // Keep default data in case of error
 |  | ||||||
|         } |         } | ||||||
|       ); |       ); | ||||||
|     } 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 = []; | ||||||
|  |       this.dataLoaded = true; | ||||||
|  |       // Trigger change detection
 | ||||||
|  |       setTimeout(() => { | ||||||
|  |         this.forceChartUpdate(); | ||||||
|  |       }, 100); | ||||||
|       // Reset flag after fetching
 |       // Reset flag after fetching
 | ||||||
|       this.isFetchingData = false; |       this.isFetchingData = false; | ||||||
|     } |     } | ||||||
| @ -654,6 +789,10 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|         console.warn('Invalid drilldown layer index:', layerIndex); |         console.warn('Invalid drilldown layer index:', layerIndex); | ||||||
|         this.noDataAvailable = true; |         this.noDataAvailable = true; | ||||||
|         this.bubbleChartData = []; |         this.bubbleChartData = []; | ||||||
|  |         this.dataLoaded = true; | ||||||
|  |         setTimeout(() => { | ||||||
|  |           this.forceChartUpdate(); | ||||||
|  |         }, 100); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -665,6 +804,10 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|       console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel); |       console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel); | ||||||
|       this.noDataAvailable = true; |       this.noDataAvailable = true; | ||||||
|       this.bubbleChartData = []; |       this.bubbleChartData = []; | ||||||
|  |       this.dataLoaded = true; | ||||||
|  |       setTimeout(() => { | ||||||
|  |         this.forceChartUpdate(); | ||||||
|  |       }, 100); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @ -758,35 +901,84 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|     this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).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) { |  | ||||||
|           console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.'); |  | ||||||
|           this.noDataAvailable = true; |  | ||||||
|           this.bubbleChartData = []; |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         // Handle the actual data structure returned by the API
 |         // Reset chart data to empty first
 | ||||||
|         if (data && data.chartLabels && data.chartData) { |         this.bubbleChartData = []; | ||||||
|  |          | ||||||
|  |         if (data === null || data === undefined) { | ||||||
|  |           console.warn('Drilldown API returned null/undefined data. Check if the API endpoint is working correctly.'); | ||||||
|  |           this.noDataAvailable = true; | ||||||
|  |         } else if (data && data.chartLabels && data.chartData) { | ||||||
|           // For bubble charts, we need to transform the data into bubble format
 |           // For bubble charts, we need to transform the data into bubble format
 | ||||||
|           this.noDataAvailable = data.chartLabels.length === 0; |           const transformedData = this.transformToBubbleData(data.chartLabels, data.chartData); | ||||||
|           this.bubbleChartData = this.transformToBubbleData(data.chartLabels, data.chartData); |            | ||||||
|           console.log('Updated bubble chart with drilldown data:', this.bubbleChartData); |           // Check if we have valid data
 | ||||||
|  |           let hasValidData = false; | ||||||
|  |           if (transformedData && transformedData.length > 0) { | ||||||
|  |             for (const dataset of transformedData) { | ||||||
|  |               if (dataset.data && dataset.data.length > 0) { | ||||||
|  |                 hasValidData = true; | ||||||
|  |                 break; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           if (hasValidData) { | ||||||
|  |             this.bubbleChartData = transformedData; | ||||||
|  |             this.noDataAvailable = false; | ||||||
|  |             console.log('Updated bubble chart with drilldown data:', this.bubbleChartData); | ||||||
|  |           } else { | ||||||
|  |             console.log('No valid data after transformation in drilldown'); | ||||||
|  |             this.noDataAvailable = true; | ||||||
|  |           } | ||||||
|         } else if (data && data.labels && data.datasets) { |         } else if (data && data.labels && data.datasets) { | ||||||
|           // Handle the original expected format as fallback
 |           // Handle the original expected format as fallback
 | ||||||
|           this.noDataAvailable = data.labels.length === 0; |           // Check if we have valid data
 | ||||||
|           this.bubbleChartData = data.datasets; |           let hasValidData = false; | ||||||
|           console.log('Updated bubble chart with drilldown legacy data format:', this.bubbleChartData); |           if (data.datasets && data.datasets.length > 0) { | ||||||
|  |             for (const dataset of data.datasets) { | ||||||
|  |               if (dataset.data && dataset.data.length > 0) { | ||||||
|  |                 hasValidData = true; | ||||||
|  |                 break; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           if (hasValidData) { | ||||||
|  |             this.bubbleChartData = data.datasets; | ||||||
|  |             this.noDataAvailable = false; | ||||||
|  |             console.log('Updated bubble chart with drilldown legacy data format:', this.bubbleChartData); | ||||||
|  |           } else { | ||||||
|  |             console.log('No valid data in legacy format in drilldown'); | ||||||
|  |             this.noDataAvailable = true; | ||||||
|  |           } | ||||||
|         } else { |         } else { | ||||||
|           console.warn('Drilldown received data does not have expected structure', data); |           console.warn('Drilldown received data does not have expected structure', data); | ||||||
|           this.noDataAvailable = true; |           this.noDataAvailable = true; | ||||||
|           this.bubbleChartData = []; |  | ||||||
|         } |         } | ||||||
|  |          | ||||||
|  |         this.dataLoaded = true; // Mark data as loaded
 | ||||||
|  |          | ||||||
|  |         console.log('Final state after drilldown data fetch:', { | ||||||
|  |           noDataAvailable: this.noDataAvailable, | ||||||
|  |           dataLoaded: this.dataLoaded, | ||||||
|  |           bubbleChartDataLength: this.bubbleChartData.length, | ||||||
|  |           isChartDataValid: this.isChartDataValid() | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         // Trigger change detection
 | ||||||
|  |         setTimeout(() => { | ||||||
|  |           this.forceChartUpdate(); | ||||||
|  |         }, 100); | ||||||
|       }, |       }, | ||||||
|       (error) => { |       (error) => { | ||||||
|         console.error('Error fetching drilldown data:', error); |         console.error('Error fetching drilldown data:', error); | ||||||
|         this.noDataAvailable = true; |         this.noDataAvailable = true; | ||||||
|         this.bubbleChartData = []; |         this.bubbleChartData = []; | ||||||
|         // Keep current data in case of error
 |         this.dataLoaded = true; | ||||||
|  |         setTimeout(() => { | ||||||
|  |           this.forceChartUpdate(); | ||||||
|  |         }, 100); | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| @ -933,4 +1125,52 @@ export class BubbleChartComponent implements OnInit, OnChanges { | |||||||
|   public chartHovered(e: any): void { |   public chartHovered(e: any): void { | ||||||
|     console.log('Bubble chart hovered:', e); |     console.log('Bubble chart hovered:', e); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   // Method to check if chart data is valid
 | ||||||
|  |   public isChartDataValid(): boolean { | ||||||
|  |     console.log('Checking if chart data is valid:', this.bubbleChartData); | ||||||
|  |     if (!this.bubbleChartData || this.bubbleChartData.length === 0) { | ||||||
|  |       console.log('Chart data is null or empty'); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check if any dataset has data
 | ||||||
|  |     for (const dataset of this.bubbleChartData) { | ||||||
|  |       console.log('Checking dataset:', dataset); | ||||||
|  |       if (dataset.data && dataset.data.length > 0) { | ||||||
|  |         console.log('Dataset has data, length:', dataset.data.length); | ||||||
|  |         // For bubble charts, check if data points have x, y, r properties
 | ||||||
|  |         for (const point of dataset.data) { | ||||||
|  |           console.log('Checking point:', point); | ||||||
|  |           if (typeof point === 'object' && point.hasOwnProperty('x') && point.hasOwnProperty('y') && point.hasOwnProperty('r')) { | ||||||
|  |             // Valid bubble point
 | ||||||
|  |             console.log('Found valid bubble point'); | ||||||
|  |             return true; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     console.log('No valid chart data found'); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Method to force chart update
 | ||||||
|  |   private forceChartUpdate(): void { | ||||||
|  |     console.log('Forcing chart update'); | ||||||
|  |     console.log('Current bubbleChartData:', this.bubbleChartData); | ||||||
|  |     console.log('Current bubbleChartData length:', this.bubbleChartData ? this.bubbleChartData.length : 0); | ||||||
|  |     if (this.bubbleChartData && this.bubbleChartData.length > 0) { | ||||||
|  |       console.log('First dataset data length:', this.bubbleChartData[0].data ? this.bubbleChartData[0].data.length : 0); | ||||||
|  |     } | ||||||
|  |     // Create a new reference to trigger change detection
 | ||||||
|  |     if (this.bubbleChartData) { | ||||||
|  |       this.bubbleChartData = [...this.bubbleChartData]; | ||||||
|  |     } | ||||||
|  |     // Also update noDataAvailable to trigger UI changes
 | ||||||
|  |     this.noDataAvailable = this.noDataAvailable; | ||||||
|  |     console.log('Chart update forced, noDataAvailable:', this.noDataAvailable); | ||||||
|  |     console.log('Chart update forced, bubbleChartData length:', this.bubbleChartData ? this.bubbleChartData.length : 0); | ||||||
|  |     console.log('Chart update forced, isChartDataValid:', this.isChartDataValid()); | ||||||
|  |   } | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user