filter
This commit is contained in:
parent
6c01e71d04
commit
aade12d6ff
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
@ -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 { 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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user