This commit is contained in:
string 2025-10-25 15:02:26 +05:30
parent 6c01e71d04
commit aade12d6ff
8 changed files with 265 additions and 13 deletions

View File

@ -1,7 +1,9 @@
.chart-wrapper { .chart-wrapper {
height: 100%; height: 100%;
width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box;
.chart-header { .chart-header {
padding: 10px 15px; padding: 10px 15px;
@ -12,6 +14,9 @@
margin: 0; margin: 0;
color: #333; color: #333;
font-size: 16px; font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
@ -19,5 +24,45 @@
flex: 1; flex: 1;
padding: 15px; padding: 15px;
overflow: auto; 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;
}
} }
} }

View File

@ -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 { Subscription } from 'rxjs';
import { FilterService } from './filter.service'; import { FilterService } from './filter.service';
@ -41,6 +41,27 @@ export class ChartWrapperComponent implements OnInit, OnDestroy {
this.componentRef.destroy(); 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 { private loadChartComponent(): void {
if (this.chartContainer && this.chartComponent) { if (this.chartContainer && this.chartComponent) {

View File

@ -4,16 +4,26 @@
border: 1px solid #ddd; border: 1px solid #ddd;
border-radius: 4px; border-radius: 4px;
margin-bottom: 20px; margin-bottom: 20px;
height: 100%;
width: 100%;
box-sizing: border-box;
.filter-header { .filter-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 15px; margin-bottom: 15px;
flex-wrap: wrap;
gap: 10px;
h4 { h4 {
margin: 0; margin: 0;
color: #333; color: #333;
flex: 1;
}
.btn {
white-space: nowrap;
} }
} }
@ -24,21 +34,44 @@
display: flex; display: flex;
gap: 10px; gap: 10px;
align-items: center; align-items: center;
flex-wrap: wrap;
select { select {
flex: 1; flex: 1;
min-width: 150px;
}
.btn {
white-space: nowrap;
} }
} }
} }
.save-preset-section { .save-preset-section {
margin-bottom: 15px; 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-form {
.filters-grid { .filters-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px; gap: 15px;
.filter-item { .filter-item {
@ -46,6 +79,8 @@
border: 1px solid #e0e0e0; border: 1px solid #e0e0e0;
border-radius: 4px; border-radius: 4px;
padding: 15px; padding: 15px;
display: flex;
flex-direction: column;
.filter-header { .filter-header {
display: flex; display: flex;
@ -56,6 +91,10 @@
.filter-label { .filter-label {
font-weight: bold; font-weight: bold;
color: #333; color: #333;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
@ -69,22 +108,29 @@
input, select, textarea { input, select, textarea {
width: 100%; width: 100%;
min-width: 0; // Allow flexbox to shrink items
} }
} }
.date-range-controls { .date-range-controls {
display: flex; display: flex;
gap: 10px; gap: 10px;
flex-direction: column;
.clr-form-control { .clr-form-control {
flex: 1; flex: 1;
} }
@media (min-width: 480px) {
flex-direction: row;
}
} }
.toggle-control { .toggle-control {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
flex-wrap: wrap;
} }
.multiselect { .multiselect {
@ -100,4 +146,47 @@
color: #666; color: #666;
font-style: italic; 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;
}
}
} }

View File

@ -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 { FormBuilder, FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { Filter, FilterService, FilterType } from './filter.service'; import { Filter, FilterService, FilterType } from './filter.service';
@ -60,6 +60,16 @@ export class CommonFilterComponent implements OnInit, OnDestroy {
ngOnDestroy(): void { ngOnDestroy(): void {
this.subscriptions.forEach(sub => sub.unsubscribe()); 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 // Build the form based on current filters
private buildForm(): void { private buildForm(): void {

View File

@ -208,7 +208,9 @@ export class EditnewdashComponent implements OnInit {
}, },
displayGrid: "always", displayGrid: "always",
minCols: 10, 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; 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 // 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
}
}
} }

View File

@ -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 --> <!-- No filter controls needed with the new simplified approach -->
<!-- Filters are now configured at the drilldown level --> <!-- Filters are now configured at the drilldown level -->
@ -19,13 +19,14 @@
</div> </div>
<!-- Chart display --> <!-- Chart display -->
<div *ngIf="!noDataAvailable"> <div *ngIf="!noDataAvailable" style="position: relative; height: calc(100% - 50px);">
<canvas baseChart <canvas baseChart
[datasets]="barChartData" [datasets]="barChartData"
[labels]="barChartLabels" [labels]="barChartLabels"
[type]="barChartType" [type]="barChartType"
(chartHover)="chartHovered($event)" [options]="barChartOptions"
(chartClick)="chartClicked($event)"> (chartHover)="chartHovered($event)"
</canvas> (chartClick)="chartClicked($event)">
</canvas>
</div> </div>
</div> </div>

View File

@ -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;
}
}

View File

@ -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 { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { FilterService } from '../../common-filter/filter.service'; import { FilterService } from '../../common-filter/filter.service';
// Add BaseChartDirective import for chart resizing
import { BaseChartDirective } from 'ng2-charts';
@Component({ @Component({
selector: 'app-bar-chart', selector: 'app-bar-chart',
@ -35,6 +37,9 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
// 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
// Add ViewChild to access the chart directive
@ViewChild(BaseChartDirective) chart?: BaseChartDirective;
barChartLabels: string[] = ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes']; barChartLabels: string[] = ['Apple', 'Banana', 'Kiwifruit', 'Blueberry', 'Orange', 'Grapes'];
barChartType: string = 'bar'; barChartType: string = 'bar';
barChartPlugins = []; barChartPlugins = [];
@ -43,6 +48,33 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
]; ];
barChartLegend: boolean = true; 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 // Multi-layer drilldown state tracking
drilldownStack: any[] = []; // Stack to track drilldown navigation history drilldownStack: any[] = []; // Stack to track drilldown navigation history
currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level) 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 // Update legend visibility if it changed
if (changes.chartlegend !== undefined) { if (changes.chartlegend !== undefined) {
this.barChartLegend = changes.chartlegend.currentValue; this.barChartLegend = changes.chartlegend.currentValue;
this.barChartOptions.plugins.legend.display = this.barChartLegend;
console.log('Chart legend changed to:', this.barChartLegend); console.log('Chart legend changed to:', this.barChartLegend);
} }
} }
@ -536,6 +569,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.fetchChartData(); 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 // Ensure labels and data arrays have the same length
private syncLabelAndDataArrays(): void { private syncLabelAndDataArrays(): void {
// For bar charts, we need to ensure all datasets have the same number of data points // For bar charts, we need to ensure all datasets have the same number of data points