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

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 { 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) {

View File

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

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 { 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 {

View File

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

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 -->
<!-- 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>

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 { 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