chart
This commit is contained in:
@@ -13,6 +13,19 @@
|
|||||||
<h4>{{ charttitle }}</h4>
|
<h4>{{ charttitle }}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter toggle icon -->
|
||||||
|
<div class="filter-toggle-icon" *ngIf="baseFilters && baseFilters.length > 0"
|
||||||
|
(click)="toggleFilters()"
|
||||||
|
style="cursor: pointer; text-align: right; padding: 5px;">
|
||||||
|
<clr-icon shape="filter" size="24"
|
||||||
|
[style.color]="showFilters ? '#007cba' : '#666'"
|
||||||
|
title="Toggle Filters">
|
||||||
|
</clr-icon>
|
||||||
|
<span style="margin-left: 5px; font-size: 12px; color: #666;">
|
||||||
|
{{ showFilters ? 'Hide Filters' : 'Show Filters' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Render different chart types based on chartType input -->
|
<!-- Render different chart types based on chartType input -->
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper">
|
||||||
<!-- Bar Chart -->
|
<!-- Bar Chart -->
|
||||||
@@ -131,23 +144,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Base Filters -->
|
<!-- Collapsible Base Filters -->
|
||||||
<div class="filters-section" *ngIf="baseFilters && baseFilters.length > 0">
|
<div class="filters-section" *ngIf="baseFilters && baseFilters.length > 0 && showFilters">
|
||||||
<h5>Filters</h5>
|
<h5>Filters</h5>
|
||||||
<div class="filters-container">
|
<div class="filters-container">
|
||||||
<div class="filter-item" *ngFor="let filter of baseFilters; let i = index">
|
<div class="filter-item" *ngFor="let filter of baseFilters; let i = index">
|
||||||
<!-- Text Filter -->
|
<!-- Text Filter -->
|
||||||
<div *ngIf="filter.type === 'text'" class="filter-text">
|
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)"
|
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)"
|
||||||
class="form-control" placeholder="Enter {{ filter.field }}">
|
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dropdown Filter -->
|
<!-- Dropdown Filter -->
|
||||||
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<select [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)" class="form-control">
|
<select [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)" class="form-control">
|
||||||
<option value="">Select {{ filter.field }}</option>
|
<option value="">Select {{ filter.field || 'value' }}</option>
|
||||||
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
@@ -156,12 +169,15 @@
|
|||||||
|
|
||||||
<!-- Multiselect Filter -->
|
<!-- Multiselect Filter -->
|
||||||
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="multiselect-container">
|
<div class="multiselect-container">
|
||||||
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'base')">
|
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'base')">
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) === 0">Select {{ filter.field }}</span>
|
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) > 0">
|
<span *ngIf="filter.value && !Array.isArray(filter.value)">
|
||||||
{{ getSelectedOptionsCount(filter) }} selected
|
{{ filter.value }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
|
||||||
|
{{ filter.value.length }} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'base')">
|
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'base')">
|
||||||
@@ -178,18 +194,18 @@
|
|||||||
|
|
||||||
<!-- Date Range Filter -->
|
<!-- Date Range Filter -->
|
||||||
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="date-range-inputs">
|
<div class="date-range-inputs">
|
||||||
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
|
||||||
class="form-control" placeholder="Start Date">
|
class="form-control" placeholder="Start Date">
|
||||||
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
|
||||||
class="form-control" placeholder="End Date">
|
class="form-control" placeholder="End Date">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Toggle Filter -->
|
<!-- Toggle Filter -->
|
||||||
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="toggle-switch">
|
<div class="toggle-switch">
|
||||||
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
||||||
id="toggle-{{ filter.field }}">
|
id="toggle-{{ filter.field }}">
|
||||||
@@ -203,22 +219,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Drilldown Filters -->
|
<!-- Drilldown Filters -->
|
||||||
<div class="filters-section" *ngIf="drilldownFilters && drilldownFilters.length > 0 && currentDrilldownLevel > 0">
|
<div class="filters-section" *ngIf="drilldownFilters && drilldownFilters.length > 0 && currentDrilldownLevel > 0 && showFilters">
|
||||||
<h5>Drilldown Filters</h5>
|
<h5>Drilldown Filters</h5>
|
||||||
<div class="filters-container">
|
<div class="filters-container">
|
||||||
<div class="filter-item" *ngFor="let filter of drilldownFilters; let i = index">
|
<div class="filter-item" *ngFor="let filter of drilldownFilters; let i = index">
|
||||||
<!-- Text Filter -->
|
<!-- Text Filter -->
|
||||||
<div *ngIf="filter.type === 'text'" class="filter-text">
|
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)"
|
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)"
|
||||||
class="form-control" placeholder="Enter {{ filter.field }}">
|
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dropdown Filter -->
|
<!-- Dropdown Filter -->
|
||||||
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<select [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)" class="form-control">
|
<select [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)" class="form-control">
|
||||||
<option value="">Select {{ filter.field }}</option>
|
<option value="">Select {{ filter.field || 'value' }}</option>
|
||||||
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
@@ -227,12 +243,15 @@
|
|||||||
|
|
||||||
<!-- Multiselect Filter -->
|
<!-- Multiselect Filter -->
|
||||||
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="multiselect-container">
|
<div class="multiselect-container">
|
||||||
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'drilldown')">
|
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'drilldown')">
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) === 0">Select {{ filter.field }}</span>
|
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) > 0">
|
<span *ngIf="filter.value && !Array.isArray(filter.value)">
|
||||||
{{ getSelectedOptionsCount(filter) }} selected
|
{{ filter.value }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
|
||||||
|
{{ filter.value.length }} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'drilldown')">
|
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'drilldown')">
|
||||||
@@ -249,18 +268,18 @@
|
|||||||
|
|
||||||
<!-- Date Range Filter -->
|
<!-- Date Range Filter -->
|
||||||
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="date-range-inputs">
|
<div class="date-range-inputs">
|
||||||
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
|
||||||
class="form-control" placeholder="Start Date">
|
class="form-control" placeholder="Start Date">
|
||||||
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
|
||||||
class="form-control" placeholder="End Date">
|
class="form-control" placeholder="End Date">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Toggle Filter -->
|
<!-- Toggle Filter -->
|
||||||
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="toggle-switch">
|
<div class="toggle-switch">
|
||||||
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
||||||
id="drilldown-toggle-{{ filter.field }}">
|
id="drilldown-toggle-{{ filter.field }}">
|
||||||
@@ -274,22 +293,22 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Layer Filters -->
|
<!-- Layer Filters -->
|
||||||
<div class="filters-section" *ngIf="hasActiveLayerFilters()">
|
<div class="filters-section" *ngIf="hasActiveLayerFilters() && showFilters">
|
||||||
<h5>Layer Filters</h5>
|
<h5>Layer Filters</h5>
|
||||||
<div class="filters-container">
|
<div class="filters-container">
|
||||||
<div class="filter-item" *ngFor="let filter of getActiveLayerFilters(); let i = index">
|
<div class="filter-item" *ngFor="let filter of getActiveLayerFilters(); let i = index">
|
||||||
<!-- Text Filter -->
|
<!-- Text Filter -->
|
||||||
<div *ngIf="filter.type === 'text'" class="filter-text">
|
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)"
|
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)"
|
||||||
class="form-control" placeholder="Enter {{ filter.field }}">
|
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dropdown Filter -->
|
<!-- Dropdown Filter -->
|
||||||
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<select [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)" class="form-control">
|
<select [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)" class="form-control">
|
||||||
<option value="">Select {{ filter.field }}</option>
|
<option value="">Select {{ filter.field || 'value' }}</option>
|
||||||
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
|
||||||
{{ option }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
@@ -298,12 +317,15 @@
|
|||||||
|
|
||||||
<!-- Multiselect Filter -->
|
<!-- Multiselect Filter -->
|
||||||
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="multiselect-container">
|
<div class="multiselect-container">
|
||||||
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'layer')">
|
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'layer')">
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) === 0">Select {{ filter.field }}</span>
|
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
|
||||||
<span *ngIf="getSelectedOptionsCount(filter) > 0">
|
<span *ngIf="filter.value && !Array.isArray(filter.value)">
|
||||||
{{ getSelectedOptionsCount(filter) }} selected
|
{{ filter.value }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
|
||||||
|
{{ filter.value.length }} selected
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'layer')">
|
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'layer')">
|
||||||
@@ -320,18 +342,18 @@
|
|||||||
|
|
||||||
<!-- Date Range Filter -->
|
<!-- Date Range Filter -->
|
||||||
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="date-range-inputs">
|
<div class="date-range-inputs">
|
||||||
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
|
||||||
class="form-control" placeholder="Start Date">
|
class="form-control" placeholder="Start Date">
|
||||||
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeChange(filter, filter.value)"
|
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
|
||||||
class="form-control" placeholder="End Date">
|
class="form-control" placeholder="End Date">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Toggle Filter -->
|
<!-- Toggle Filter -->
|
||||||
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
|
||||||
<label>{{ filter.field }}</label>
|
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
|
||||||
<div class="toggle-switch">
|
<div class="toggle-switch">
|
||||||
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
|
||||||
id="layer-toggle-{{ filter.field }}">
|
id="layer-toggle-{{ filter.field }}">
|
||||||
@@ -345,7 +367,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Clear Filters Button -->
|
<!-- Clear Filters Button -->
|
||||||
<div class="clear-filters" *ngIf="hasActiveFilters()">
|
<div class="clear-filters" *ngIf="hasActiveFilters() && showFilters">
|
||||||
<button class="btn btn-sm btn-outline" (click)="clearAllFilters()">
|
<button class="btn btn-sm btn-outline" (click)="clearAllFilters()">
|
||||||
Clear All Filters
|
Clear All Filters
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -30,16 +30,15 @@
|
|||||||
.chart-wrapper {
|
.chart-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: calc(100% - 100px);
|
height: calc(100% - 100px);
|
||||||
min-height: 400px; // Increased minimum height for better visibility
|
min-height: 400px;
|
||||||
padding: 10px; // Add padding to create space around the chart
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specific container for chart canvas elements
|
|
||||||
.chart-canvas-container {
|
.chart-canvas-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 15px; // Add padding around the canvas for better spacing
|
padding: 15px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
@@ -49,6 +48,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-toggle-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
clr-icon {
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #007cba !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover span {
|
||||||
|
color: #007cba;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.filters-section {
|
.filters-section {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
@@ -262,7 +288,6 @@
|
|||||||
100% { transform: rotate(360deg); }
|
100% { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Responsive adjustments
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.filters-container {
|
.filters-container {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
currentDrilldownLevel: number = 0;
|
currentDrilldownLevel: number = 0;
|
||||||
originalChartData: any = {};
|
originalChartData: any = {};
|
||||||
|
|
||||||
|
// Filter visibility toggle
|
||||||
|
showFilters: boolean = false;
|
||||||
|
|
||||||
// Flag to prevent infinite loops
|
// Flag to prevent infinite loops
|
||||||
private isFetchingData: boolean = false;
|
private isFetchingData: boolean = false;
|
||||||
|
|
||||||
@@ -85,6 +88,13 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Initialize filter values if they haven't been initialized yet
|
||||||
|
if (!this.filtersInitialized) {
|
||||||
|
this.initializeFilterValues();
|
||||||
|
this.filtersInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize chart options with default structure
|
||||||
this.initializeChartOptions();
|
this.initializeChartOptions();
|
||||||
this.fetchChartData();
|
this.fetchChartData();
|
||||||
}
|
}
|
||||||
@@ -92,6 +102,17 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
console.log('UnifiedChartComponent input changes:', changes);
|
console.log('UnifiedChartComponent input changes:', changes);
|
||||||
|
|
||||||
|
// Log all input values for debugging
|
||||||
|
console.log('Current input values:', {
|
||||||
|
chartType: this.chartType,
|
||||||
|
xAxis: this.xAxis,
|
||||||
|
yAxis: this.yAxis,
|
||||||
|
table: this.table,
|
||||||
|
baseFilters: this.baseFilters,
|
||||||
|
drilldownFilters: this.drilldownFilters,
|
||||||
|
drilldownLayers: this.drilldownLayers
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize filter values if they haven't been initialized yet
|
// Initialize filter values if they haven't been initialized yet
|
||||||
if (!this.filtersInitialized && (changes.baseFilters || changes.drilldownFilters || changes.drilldownLayers)) {
|
if (!this.filtersInitialized && (changes.baseFilters || changes.drilldownFilters || changes.drilldownLayers)) {
|
||||||
this.initializeFilterValues();
|
this.initializeFilterValues();
|
||||||
@@ -114,6 +135,36 @@ export class UnifiedChartComponent 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;
|
||||||
|
|
||||||
|
// Log base filters changes for debugging
|
||||||
|
if (baseFiltersChanged) {
|
||||||
|
console.log('Base filters changed:', changes.baseFilters);
|
||||||
|
console.log('Current base filters:', this.baseFilters);
|
||||||
|
// Log detailed information about each filter
|
||||||
|
if (this.baseFilters && Array.isArray(this.baseFilters)) {
|
||||||
|
this.baseFilters.forEach((filter, index) => {
|
||||||
|
console.log(`Base filter ${index} details:`, {
|
||||||
|
field: filter.field,
|
||||||
|
value: filter.value,
|
||||||
|
type: filter.type,
|
||||||
|
options: filter.options
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also log when baseFilters is not changed but we still have filters
|
||||||
|
if (!baseFiltersChanged && this.baseFilters && this.baseFilters.length > 0) {
|
||||||
|
console.log('Base filters present but not changed, logging current state:');
|
||||||
|
this.baseFilters.forEach((filter, index) => {
|
||||||
|
console.log(`Base filter ${index} details:`, {
|
||||||
|
field: filter.field,
|
||||||
|
value: filter.value,
|
||||||
|
type: filter.type,
|
||||||
|
options: filter.options
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Only fetch data if the actual chart configuration changed and we're not already fetching
|
// Only fetch data if the actual chart configuration changed and we're not already fetching
|
||||||
if (!this.isFetchingData && (chartTypeChanged || xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || drilldownFiltersChanged ||
|
if (!this.isFetchingData && (chartTypeChanged || xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || drilldownFiltersChanged ||
|
||||||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
|
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
|
||||||
@@ -126,7 +177,18 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
// Update legend visibility if it changed
|
// Update legend visibility if it changed
|
||||||
if (changes.chartlegend !== undefined) {
|
if (changes.chartlegend !== undefined) {
|
||||||
this.chartLegend = changes.chartlegend.currentValue;
|
this.chartLegend = changes.chartlegend.currentValue;
|
||||||
|
// Ensure chartOptions and required structures exist before accessing legend
|
||||||
|
if (!this.chartOptions) {
|
||||||
|
this.chartOptions = {};
|
||||||
|
}
|
||||||
|
if (!this.chartOptions.plugins) {
|
||||||
|
this.chartOptions.plugins = {};
|
||||||
|
}
|
||||||
|
if (!this.chartOptions.plugins.legend) {
|
||||||
|
this.chartOptions.plugins.legend = { display: this.chartLegend };
|
||||||
|
} else {
|
||||||
this.chartOptions.plugins.legend.display = this.chartLegend;
|
this.chartOptions.plugins.legend.display = this.chartLegend;
|
||||||
|
}
|
||||||
console.log('Chart legend changed to:', this.chartLegend);
|
console.log('Chart legend changed to:', this.chartLegend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,13 +203,30 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if filters are available
|
||||||
|
hasFilters(): boolean {
|
||||||
|
const hasBaseFilters = this.baseFilters && this.baseFilters.length > 0;
|
||||||
|
console.log('Checking for filters - baseFilters:', this.baseFilters, 'hasBaseFilters:', hasBaseFilters);
|
||||||
|
return hasBaseFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle filter visibility
|
||||||
|
toggleFilters(): void {
|
||||||
|
console.log('Toggling filters. Current state:', this.showFilters);
|
||||||
|
console.log('Base filters available:', this.hasFilters());
|
||||||
|
this.showFilters = !this.showFilters;
|
||||||
|
console.log('New state:', this.showFilters);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize filter values with proper default values based on type
|
// Initialize filter values with proper default values based on type
|
||||||
private initializeFilterValues(): void {
|
private initializeFilterValues(): void {
|
||||||
console.log('Initializing filter values');
|
console.log('Initializing filter values');
|
||||||
|
console.log('Base filters before initialization:', this.baseFilters);
|
||||||
|
|
||||||
// Initialize base filters
|
// Initialize base filters
|
||||||
if (this.baseFilters) {
|
if (this.baseFilters && Array.isArray(this.baseFilters)) {
|
||||||
this.baseFilters.forEach(filter => {
|
this.baseFilters.forEach((filter, index) => {
|
||||||
|
console.log(`Processing base filter ${index}:`, filter);
|
||||||
if (filter.value === undefined || filter.value === null) {
|
if (filter.value === undefined || filter.value === null) {
|
||||||
switch (filter.type) {
|
switch (filter.type) {
|
||||||
case 'multiselect':
|
case 'multiselect':
|
||||||
@@ -162,13 +241,22 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
default:
|
default:
|
||||||
filter.value = '';
|
filter.value = '';
|
||||||
}
|
}
|
||||||
|
console.log(`Initialized base filter ${index} value to:`, filter.value);
|
||||||
|
} else {
|
||||||
|
console.log(`Base filter ${index} already has value:`, filter.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Initialize as empty array if not provided
|
||||||
|
this.baseFilters = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Base filters after initialization:', this.baseFilters);
|
||||||
|
|
||||||
// Initialize drilldown filters
|
// Initialize drilldown filters
|
||||||
if (this.drilldownFilters) {
|
if (this.drilldownFilters && Array.isArray(this.drilldownFilters)) {
|
||||||
this.drilldownFilters.forEach(filter => {
|
this.drilldownFilters.forEach((filter, index) => {
|
||||||
|
console.log(`Processing drilldown filter ${index}:`, filter);
|
||||||
if (filter.value === undefined || filter.value === null) {
|
if (filter.value === undefined || filter.value === null) {
|
||||||
switch (filter.type) {
|
switch (filter.type) {
|
||||||
case 'multiselect':
|
case 'multiselect':
|
||||||
@@ -183,15 +271,23 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
default:
|
default:
|
||||||
filter.value = '';
|
filter.value = '';
|
||||||
}
|
}
|
||||||
|
console.log(`Initialized drilldown filter ${index} value to:`, filter.value);
|
||||||
|
} else {
|
||||||
|
console.log(`Drilldown filter ${index} already has value:`, filter.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Initialize as empty array if not provided
|
||||||
|
this.drilldownFilters = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize layer filters
|
// Initialize layer filters
|
||||||
if (this.drilldownLayers) {
|
if (this.drilldownLayers && Array.isArray(this.drilldownLayers)) {
|
||||||
this.drilldownLayers.forEach(layer => {
|
this.drilldownLayers.forEach((layer, layerIndex) => {
|
||||||
if (layer.filters) {
|
console.log(`Processing drilldown layer ${layerIndex}:`, layer);
|
||||||
layer.filters.forEach((filter: any) => {
|
if (layer.filters && Array.isArray(layer.filters)) {
|
||||||
|
layer.filters.forEach((filter, filterIndex) => {
|
||||||
|
console.log(`Processing layer ${layerIndex} filter ${filterIndex}:`, filter);
|
||||||
if (filter.value === undefined || filter.value === null) {
|
if (filter.value === undefined || filter.value === null) {
|
||||||
switch (filter.type) {
|
switch (filter.type) {
|
||||||
case 'multiselect':
|
case 'multiselect':
|
||||||
@@ -206,10 +302,16 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
default:
|
default:
|
||||||
filter.value = '';
|
filter.value = '';
|
||||||
}
|
}
|
||||||
|
console.log(`Initialized layer ${layerIndex} filter ${filterIndex} value to:`, filter.value);
|
||||||
|
} else {
|
||||||
|
console.log(`Layer ${layerIndex} filter ${filterIndex} already has value:`, filter.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Initialize as empty array if not provided
|
||||||
|
this.drilldownLayers = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Filter values initialized:', {
|
console.log('Filter values initialized:', {
|
||||||
@@ -221,6 +323,18 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
// Initialize chart options based on chart type
|
// Initialize chart options based on chart type
|
||||||
private initializeChartOptions(): void {
|
private initializeChartOptions(): void {
|
||||||
|
// Initialize with default structure to ensure plugins.legend exists
|
||||||
|
this.chartOptions = {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
switch (this.chartType) {
|
switch (this.chartType) {
|
||||||
case 'bar':
|
case 'bar':
|
||||||
this.initializeBarChartOptions();
|
this.initializeBarChartOptions();
|
||||||
@@ -573,6 +687,11 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.noDataAvailable = false;
|
this.noDataAvailable = false;
|
||||||
|
|
||||||
|
// Ensure chart options are initialized
|
||||||
|
if (!this.chartOptions) {
|
||||||
|
this.initializeChartOptions();
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Starting fetchChartData for chart type:', this.chartType);
|
console.log('Starting fetchChartData for chart type:', this.chartType);
|
||||||
|
|
||||||
// If we're in drilldown mode, fetch the appropriate drilldown data
|
// If we're in drilldown mode, fetch the appropriate drilldown data
|
||||||
@@ -1320,7 +1439,7 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public chartHovered(e: any): void {
|
public chartHovered(e: any): void {
|
||||||
console.log('Chart hovered:', e);
|
// console.log('Chart hovered:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to check if chart data is valid
|
// Method to check if chart data is valid
|
||||||
@@ -1476,8 +1595,27 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle date range changes
|
// Handle date range changes
|
||||||
onDateRangeChange(filter: any, dateRange: { start: string | null, end: string | null }): void {
|
onDateRangeChange(filter: any, event: any): void {
|
||||||
filter.value = dateRange;
|
// For date range filters, we need to handle the change differently
|
||||||
|
// since we're binding to individual start/end properties
|
||||||
|
if (!filter.value) {
|
||||||
|
filter.value = { start: null, end: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh data when filter changes
|
||||||
|
this.fetchChartData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle date range input changes for start/end dates
|
||||||
|
onDateRangeInputChange(filter: any, dateType: string, event: any): void {
|
||||||
|
// Initialize filter.value if it doesn't exist
|
||||||
|
if (!filter.value) {
|
||||||
|
filter.value = { start: null, end: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the specific date type (start or end)
|
||||||
|
filter.value[dateType] = event.target.value;
|
||||||
|
|
||||||
// Refresh data when filter changes
|
// Refresh data when filter changes
|
||||||
this.fetchChartData();
|
this.fetchChartData();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user