filter
This commit is contained in:
		
							parent
							
								
									6c01e71d04
								
							
						
					
					
						commit
						aade12d6ff
					
				| @ -1,7 +1,9 @@ | ||||
| .chart-wrapper { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   box-sizing: border-box; | ||||
|    | ||||
|   .chart-header { | ||||
|     padding: 10px 15px; | ||||
| @ -12,6 +14,9 @@ | ||||
|       margin: 0; | ||||
|       color: #333; | ||||
|       font-size: 16px; | ||||
|       white-space: nowrap; | ||||
|       overflow: hidden; | ||||
|       text-overflow: ellipsis; | ||||
|     } | ||||
|   } | ||||
|    | ||||
| @ -19,5 +24,45 @@ | ||||
|     flex: 1; | ||||
|     padding: 15px; | ||||
|     overflow: auto; | ||||
|     position: relative; | ||||
|      | ||||
|     // Ensure chart containers fill available space | ||||
|     ::ng-deep canvas { | ||||
|       max-width: 100%; | ||||
|       max-height: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Responsive adjustments | ||||
| @media (max-width: 768px) { | ||||
|   .chart-wrapper { | ||||
|     .chart-header { | ||||
|       padding: 8px 12px; | ||||
|        | ||||
|       h5 { | ||||
|         font-size: 14px; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     .chart-container { | ||||
|       padding: 10px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 480px) { | ||||
|   .chart-wrapper { | ||||
|     .chart-header { | ||||
|       padding: 6px 10px; | ||||
|        | ||||
|       h5 { | ||||
|         font-size: 13px; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     .chart-container { | ||||
|       padding: 8px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| import { Component, Input, OnInit, OnDestroy, ComponentRef, ViewChild, ViewContainerRef } from '@angular/core'; | ||||
| import { Component, Input, OnInit, OnDestroy, ComponentRef, ViewChild, ViewContainerRef, HostListener } from '@angular/core'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| import { FilterService } from './filter.service'; | ||||
| 
 | ||||
| @ -41,6 +41,27 @@ export class ChartWrapperComponent implements OnInit, OnDestroy { | ||||
|       this.componentRef.destroy(); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // Handle window resize events
 | ||||
|   @HostListener('window:resize', ['$event']) | ||||
|   onResize(event: any) { | ||||
|     // Notify the chart component to resize if it has a resize method
 | ||||
|     if (this.componentRef && this.componentRef.instance) { | ||||
|       const chartInstance = this.componentRef.instance; | ||||
|        | ||||
|       // If it's a chart component with an onResize method, call it
 | ||||
|       if (chartInstance.onResize && typeof chartInstance.onResize === 'function') { | ||||
|         chartInstance.onResize(); | ||||
|       } | ||||
|        | ||||
|       // If it's a chart component with a chart property (from BaseChartDirective), resize it
 | ||||
|       if (chartInstance.chart && typeof chartInstance.chart.resize === 'function') { | ||||
|         setTimeout(() => { | ||||
|           chartInstance.chart.resize(); | ||||
|         }, 100); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private loadChartComponent(): void { | ||||
|     if (this.chartContainer && this.chartComponent) { | ||||
|  | ||||
| @ -4,16 +4,26 @@ | ||||
|   border: 1px solid #ddd; | ||||
|   border-radius: 4px; | ||||
|   margin-bottom: 20px; | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   box-sizing: border-box; | ||||
| 
 | ||||
|   .filter-header { | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|     margin-bottom: 15px; | ||||
|     flex-wrap: wrap; | ||||
|     gap: 10px; | ||||
| 
 | ||||
|     h4 { | ||||
|       margin: 0; | ||||
|       color: #333; | ||||
|       flex: 1; | ||||
|     } | ||||
|      | ||||
|     .btn { | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -24,21 +34,44 @@ | ||||
|       display: flex; | ||||
|       gap: 10px; | ||||
|       align-items: center; | ||||
|       flex-wrap: wrap; | ||||
|        | ||||
|       select { | ||||
|         flex: 1; | ||||
|         min-width: 150px; | ||||
|       } | ||||
|        | ||||
|       .btn { | ||||
|         white-space: nowrap; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .save-preset-section { | ||||
|     margin-bottom: 15px; | ||||
|      | ||||
|     .clr-input-group { | ||||
|       display: flex; | ||||
|       flex-wrap: wrap; | ||||
|       gap: 10px; | ||||
|        | ||||
|       .clr-input { | ||||
|         flex: 1; | ||||
|         min-width: 150px; | ||||
|       } | ||||
|        | ||||
|       .clr-input-group-btn { | ||||
|         .btn { | ||||
|           white-space: nowrap; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .filters-form { | ||||
|     .filters-grid { | ||||
|       display: grid; | ||||
|       grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | ||||
|       grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); | ||||
|       gap: 15px; | ||||
|        | ||||
|       .filter-item { | ||||
| @ -46,6 +79,8 @@ | ||||
|         border: 1px solid #e0e0e0; | ||||
|         border-radius: 4px; | ||||
|         padding: 15px; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|          | ||||
|         .filter-header { | ||||
|           display: flex; | ||||
| @ -56,6 +91,10 @@ | ||||
|           .filter-label { | ||||
|             font-weight: bold; | ||||
|             color: #333; | ||||
|             flex: 1; | ||||
|             white-space: nowrap; | ||||
|             overflow: hidden; | ||||
|             text-overflow: ellipsis; | ||||
|           } | ||||
|         } | ||||
|          | ||||
| @ -69,22 +108,29 @@ | ||||
|            | ||||
|           input, select, textarea { | ||||
|             width: 100%; | ||||
|             min-width: 0; // Allow flexbox to shrink items | ||||
|           } | ||||
|         } | ||||
|          | ||||
|         .date-range-controls { | ||||
|           display: flex; | ||||
|           gap: 10px; | ||||
|           flex-direction: column; | ||||
|            | ||||
|           .clr-form-control { | ||||
|             flex: 1; | ||||
|           } | ||||
|            | ||||
|           @media (min-width: 480px) { | ||||
|             flex-direction: row; | ||||
|           } | ||||
|         } | ||||
|          | ||||
|         .toggle-control { | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           gap: 8px; | ||||
|           flex-wrap: wrap; | ||||
|         } | ||||
|          | ||||
|         .multiselect { | ||||
| @ -100,4 +146,47 @@ | ||||
|     color: #666; | ||||
|     font-style: italic; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Responsive design for smaller screens | ||||
| @media (max-width: 768px) { | ||||
|   .common-filter-container { | ||||
|     padding: 10px; | ||||
|      | ||||
|     .filters-form { | ||||
|       .filters-grid { | ||||
|         grid-template-columns: 1fr; | ||||
|         gap: 10px; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     .filter-header { | ||||
|       flex-direction: column; | ||||
|       align-items: stretch; | ||||
|     } | ||||
|      | ||||
|     .presets-section { | ||||
|       .preset-controls { | ||||
|         flex-direction: column; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     .save-preset-section { | ||||
|       .clr-input-group { | ||||
|         flex-direction: column; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 480px) { | ||||
|   .common-filter-container { | ||||
|     .date-range-controls { | ||||
|       flex-direction: column; | ||||
|     } | ||||
|      | ||||
|     .filter-item { | ||||
|       padding: 10px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| import { Component, OnInit, OnDestroy, Input } from '@angular/core'; | ||||
| import { Component, OnInit, OnDestroy, Input, HostListener } from '@angular/core'; | ||||
| import { FormBuilder, FormGroup } from '@angular/forms'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| import { Filter, FilterService, FilterType } from './filter.service'; | ||||
| @ -60,6 +60,16 @@ export class CommonFilterComponent implements OnInit, OnDestroy { | ||||
|   ngOnDestroy(): void { | ||||
|     this.subscriptions.forEach(sub => sub.unsubscribe()); | ||||
|   } | ||||
|    | ||||
|   // Handle window resize events
 | ||||
|   @HostListener('window:resize', ['$event']) | ||||
|   onResize(event: any) { | ||||
|     // Trigger change detection to reflow the layout
 | ||||
|     setTimeout(() => { | ||||
|       // This will cause the grid to recalculate its layout
 | ||||
|       this.filters = [...this.filters]; | ||||
|     }, 100); | ||||
|   } | ||||
| 
 | ||||
|   // Build the form based on current filters
 | ||||
|   private buildForm(): void { | ||||
|  | ||||
| @ -208,7 +208,9 @@ export class EditnewdashComponent implements OnInit { | ||||
|       }, | ||||
|       displayGrid: "always", | ||||
|       minCols: 10, | ||||
|       minRows: 10 | ||||
|       minRows: 10, | ||||
|       // Add resize callback to handle chart resizing
 | ||||
|       itemResizeCallback: this.itemResize.bind(this) | ||||
|     }; | ||||
| 
 | ||||
|     this.editId = this.route.snapshot.params.id; | ||||
| @ -1273,4 +1275,17 @@ export class EditnewdashComponent implements OnInit { | ||||
|       // When disabling, the user can edit the filters normally
 | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // Add method to handle item resize events
 | ||||
|   itemResize(item: any, itemComponent: any) { | ||||
|     console.log('Item resized:', item); | ||||
|     // Trigger a window resize event to notify charts to resize
 | ||||
|     window.dispatchEvent(new Event('resize')); | ||||
|      | ||||
|     // Also try to directly notify the chart component if possible
 | ||||
|     if (itemComponent && itemComponent.item && itemComponent.item.component) { | ||||
|       // If the resized item contains a chart, we could try to call its resize method directly
 | ||||
|       // This would require the chart component to have a public resize method
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <div style="display: block"> | ||||
| <div style="display: block; height: 100%; width: 100%;"> | ||||
|   <!-- No filter controls needed with the new simplified approach --> | ||||
|   <!-- Filters are now configured at the drilldown level --> | ||||
|    | ||||
| @ -19,13 +19,14 @@ | ||||
|   </div> | ||||
|    | ||||
|   <!-- Chart display --> | ||||
|   <div *ngIf="!noDataAvailable"> | ||||
|   <div *ngIf="!noDataAvailable" style="position: relative; height: calc(100% - 50px);"> | ||||
|     <canvas baseChart | ||||
|     [datasets]="barChartData" | ||||
|     [labels]="barChartLabels" | ||||
|     [type]="barChartType" | ||||
|     (chartHover)="chartHovered($event)" | ||||
|     (chartClick)="chartClicked($event)"> | ||||
|   </canvas> | ||||
|       [datasets]="barChartData" | ||||
|       [labels]="barChartLabels" | ||||
|       [type]="barChartType" | ||||
|       [options]="barChartOptions" | ||||
|       (chartHover)="chartHovered($event)" | ||||
|       (chartClick)="chartClicked($event)"> | ||||
|     </canvas> | ||||
|   </div> | ||||
| </div> | ||||
| @ -0,0 +1,31 @@ | ||||
| // Bar Chart Component Styles | ||||
| :host { | ||||
|   display: block; | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| .bar-chart-container { | ||||
|   position: relative; | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
| } | ||||
| 
 | ||||
| canvas { | ||||
|   display: block; | ||||
|   max-width: 100%; | ||||
|   max-height: 100%; | ||||
| } | ||||
| 
 | ||||
| // Responsive design for chart container | ||||
| @media (max-width: 768px) { | ||||
|   .bar-chart-container { | ||||
|     height: 300px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| @media (max-width: 480px) { | ||||
|   .bar-chart-container { | ||||
|     height: 250px; | ||||
|   } | ||||
| } | ||||
| @ -1,7 +1,9 @@ | ||||
| import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; | ||||
| import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges, ViewChild } from '@angular/core'; | ||||
| import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service'; | ||||
| import { Subscription } from 'rxjs'; | ||||
| import { FilterService } from '../../common-filter/filter.service'; | ||||
| // Add BaseChartDirective import for chart resizing
 | ||||
| import { BaseChartDirective } from 'ng2-charts'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-bar-chart', | ||||
| @ -35,6 +37,9 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | ||||
|   // Multi-layer drilldown configuration inputs
 | ||||
|   @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
 | ||||
| 
 | ||||
|   // Add ViewChild to access the chart directive
 | ||||
|   @ViewChild(BaseChartDirective) chart?: BaseChartDirective; | ||||
| 
 | ||||
|   barChartLabels: string[] = ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes']; | ||||
|   barChartType: string = 'bar'; | ||||
|   barChartPlugins = []; | ||||
| @ -43,6 +48,33 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | ||||
|   ]; | ||||
|   barChartLegend: boolean = true; | ||||
|    | ||||
|   // Add responsive chart options
 | ||||
|   barChartOptions: any = { | ||||
|     responsive: true, | ||||
|     maintainAspectRatio: false, | ||||
|     scales: { | ||||
|       x: { | ||||
|         ticks: { | ||||
|           autoSkip: false, | ||||
|           maxRotation: 45, | ||||
|           minRotation: 45 | ||||
|         } | ||||
|       }, | ||||
|       y: { | ||||
|         beginAtZero: true | ||||
|       } | ||||
|     }, | ||||
|     plugins: { | ||||
|       legend: { | ||||
|         display: true, | ||||
|         position: 'top', | ||||
|       }, | ||||
|       tooltip: { | ||||
|         enabled: true | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
|    | ||||
|   // Multi-layer drilldown state tracking
 | ||||
|   drilldownStack: any[] = []; // Stack to track drilldown navigation history
 | ||||
|   currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
 | ||||
| @ -104,6 +136,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | ||||
|     // Update legend visibility if it changed
 | ||||
|     if (changes.chartlegend !== undefined) { | ||||
|       this.barChartLegend = changes.chartlegend.currentValue; | ||||
|       this.barChartOptions.plugins.legend.display = this.barChartLegend; | ||||
|       console.log('Chart legend changed to:', this.barChartLegend); | ||||
|     } | ||||
|   } | ||||
| @ -536,6 +569,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy { | ||||
|     this.fetchChartData(); | ||||
|   } | ||||
|    | ||||
|   // Method to handle window resize events
 | ||||
|   onResize(): void { | ||||
|     if (this.chart) { | ||||
|       this.chart.chart?.resize(); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // 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
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user