This commit is contained in:
string 2025-10-23 16:17:39 +05:30
parent b1dc16a67b
commit fcbee92929
10 changed files with 735 additions and 270 deletions

View File

@ -1,5 +1,6 @@
import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-bar-chart',
@ -28,7 +29,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
// @Input() baseFilters: any[] = []; // Removed base filters input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -49,7 +50,11 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
// No data state
noDataAvailable: boolean = false;
// Filter update timeout property removed
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
// Subscriptions to unsubscribe on destroy
private subscriptions: Subscription[] = [];
constructor(private dashboardService: Dashboard3Service) { }
@ -66,6 +71,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -73,10 +79,10 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Only fetch data if the actual chart configuration changed
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
@ -88,12 +94,15 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
// Filter parameters method removed
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -111,9 +120,23 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
let url = `chart/getdashjson/bar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Bar chart data URL:', url);
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
const subscription = this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received bar chart data:', data);
if (data === null) {
@ -121,6 +144,8 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.noDataAvailable = true;
this.barChartLabels = [];
this.barChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -131,7 +156,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.barChartLabels = data.chartLabels;
this.barChartData = data.chartData;
// Trigger change detection
this.barChartData = [...this.barChartData];
// this.barChartData = [...this.barChartData];
console.log('Updated bar chart with data:', { labels: this.barChartLabels, data: this.barChartData });
} else if (data && data.labels && data.datasets) {
// Backend has already filtered the data, just display it
@ -139,7 +164,7 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.barChartLabels = data.labels;
this.barChartData = data.datasets;
// Trigger change detection
this.barChartData = [...this.barChartData];
// this.barChartData = [...this.barChartData];
console.log('Updated bar chart with legacy data format:', { labels: this.barChartLabels, data: this.barChartData });
} else {
console.warn('Bar chart received data does not have expected structure', data);
@ -147,20 +172,29 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.barChartLabels = [];
this.barChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching bar chart data:', error);
this.noDataAvailable = true;
this.barChartLabels = [];
this.barChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
// Add subscription to array for cleanup
this.subscriptions.push(subscription);
} else {
console.log('Missing required data for bar chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true;
this.barChartLabels = [];
this.barChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -249,9 +283,23 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
}
console.log('Drilldown data URL:', url);
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'bar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
const subscription = this.dashboardService.getChartData(actualApiUrl, 'bar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -269,15 +317,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.barChartLabels = data.chartLabels;
this.barChartData = data.chartData;
// Trigger change detection
this.barChartData = [...this.barChartData];
// this.barChartData = [...this.barChartData];
console.log('Updated bar chart with drilldown data:', { labels: this.barChartLabels, data: this.barChartData });
} else if (data && data.labels && data.datasets) {
// Backend has already filtered the data, just display it
this.noDataAvailable = data.labels.length === 0;
this.barChartLabels = data.labels;
this.barChartData = data.datasets;
// Trigger change detection
this.barChartData = [...this.barChartData];
console.log('Updated bar chart with drilldown legacy data format:', { labels: this.barChartLabels, data: this.barChartData });
} else {
console.warn('Drilldown received data does not have expected structure', data);
@ -294,6 +340,9 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
// Keep current data in case of error
}
);
// Add subscription to array for cleanup
this.subscriptions.push(subscription);
}
// Reset to original data (go back to base level)
@ -306,11 +355,13 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
this.drilldownStack = [];
if (this.originalBarChartLabels.length > 0) {
this.barChartLabels = [...this.originalBarChartLabels];
// Create a deep copy to avoid reference issues
this.barChartLabels = JSON.parse(JSON.stringify(this.originalBarChartLabels));
console.log('Restored original labels');
}
if (this.originalBarChartData.length > 0) {
this.barChartData = [...this.originalBarChartData];
// Create a deep copy to avoid reference issues
this.barChartData = JSON.parse(JSON.stringify(this.originalBarChartData));
console.log('Restored original data');
}
@ -352,6 +403,29 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
// 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
if (this.barChartData && this.barChartData.length > 0 && this.barChartLabels) {
const labelCount = this.barChartLabels.length;
this.barChartData.forEach(dataset => {
if (dataset.data) {
// If dataset has more data points than labels, truncate the data
if (dataset.data.length > labelCount) {
dataset.data = dataset.data.slice(0, labelCount);
}
// If dataset has fewer data points than labels, pad with zeros
else if (dataset.data.length < labelCount) {
while (dataset.data.length < labelCount) {
dataset.data.push(0);
}
}
}
});
}
}
// events
public chartClicked(e: any): void {
console.log('Bar chart clicked:', e);
@ -369,8 +443,10 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {
// Store original data before entering drilldown mode
this.originalBarChartLabels = [...this.barChartLabels];
this.originalBarChartData = [...this.barChartData];
// Create a deep copy to avoid reference issues
this.originalBarChartLabels = JSON.parse(JSON.stringify(this.barChartLabels));
// Create a deep copy to avoid reference issues
this.originalBarChartData = JSON.parse(JSON.stringify(this.barChartData));
console.log('Stored original data for drilldown');
}
@ -442,6 +518,22 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
}
ngOnDestroy() {
// Cleanup method - no timeouts to clean up
// Unsubscribe from all subscriptions to prevent memory leaks
console.log('BarChartComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
this.subscriptions.forEach(subscription => {
if (subscription && !subscription.closed) {
subscription.unsubscribe();
}
});
this.subscriptions = [];
// Clear data to help with garbage collection
this.barChartLabels = [];
this.barChartData = [];
this.drilldownStack = [];
this.originalBarChartLabels = [];
this.originalBarChartData = [];
console.log('BarChartComponent destroyed and cleaned up');
}
}

View File

@ -29,6 +29,7 @@ export class BubbleChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -91,6 +92,9 @@ export class BubbleChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
constructor(private dashboardService: Dashboard3Service) { }
ngOnInit(): void {
@ -105,6 +109,7 @@ export class BubbleChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -112,19 +117,24 @@ export class BubbleChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -135,19 +145,36 @@ export class BubbleChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/bubble?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Bubble chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received bubble chart data:', data);
if (data === null) {
console.warn('Bubble chart API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true;
this.bubbleChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -168,17 +195,23 @@ export class BubbleChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.bubbleChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching bubble chart data:', error);
this.noDataAvailable = true;
this.bubbleChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
);
} else {
console.log('Missing required data for bubble chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true;
this.bubbleChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -258,13 +291,27 @@ export class BubbleChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/bubble?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -300,6 +347,35 @@ export class BubbleChartComponent implements OnInit, OnChanges {
);
}
// Transform chart data to bubble chart format
private transformToBubbleData(labels: string[], datasets: any[]): ChartDataset[] {
// For bubble charts, we need to transform the data into bubble format
// Bubble charts expect data in the format: {x: number, y: number, r: number}
// This is a simple transformation - in a real implementation, you might want to
// create a more sophisticated mapping based on your data structure
return datasets.map((dataset, index) => {
// Create bubble data points
const bubbleData = labels.map((label, i) => {
// Use x-axis data as x coordinate, y-axis data as y coordinate, and a fixed radius
const xValue = dataset.data[i] || 0;
const yValue = i < datasets.length ? (datasets[i].data[index] || 0) : 0;
const radius = 10; // Fixed radius for now
return { x: xValue, y: yValue, r: radius };
});
return {
data: bubbleData,
label: dataset.label || `Dataset ${index + 1}`,
backgroundColor: dataset.backgroundColor || `rgba(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, 0.6)`,
borderColor: dataset.borderColor || 'rgba(0, 0, 0, 1)',
hoverBackgroundColor: dataset.hoverBackgroundColor || 'rgba(255, 255, 255, 0.8)',
hoverBorderColor: dataset.hoverBorderColor || 'rgba(0, 0, 0, 1)'
};
});
}
// Reset to original data (go back to base level)
resetToOriginalData(): void {
console.log('Resetting to original data');
@ -351,70 +427,6 @@ export class BubbleChartComponent implements OnInit, OnChanges {
}
}
private transformToBubbleData(labels: any[], chartData: any[]): ChartDataset[] {
// Transform the API data into bubble chart format
const datasets: ChartDataset[] = [];
// Create a dataset for each data series
chartData.forEach((series, index) => {
// For bubble charts, we need x, y, and r values
// We'll use the labels as x values and the data as y values
// For radius (r), we'll use a default value or derive it from the data
const bubbleData = labels.map((label, i) => {
const xValue = isNaN(Number(label)) ? i : Number(label);
const yValue = series.data && series.data[i] !== undefined ?
(isNaN(Number(series.data[i])) ? 0 : Number(series.data[i])) : 0;
// Use a default radius or derive from data
const radius = Math.abs(yValue) > 0 ? Math.abs(yValue) / 10 : 5;
return {
x: xValue,
y: yValue,
r: radius
};
});
datasets.push({
data: bubbleData,
label: series.label || `Series ${index + 1}`,
backgroundColor: this.getBackgroundColor(index),
borderColor: this.getBorderColor(index),
hoverBackgroundColor: this.getHoverBackgroundColor(index),
hoverBorderColor: this.getHoverBorderColor(index),
});
});
return datasets;
}
private getBackgroundColor(index: number): string {
const colors = [
'rgba(255, 0, 0, 0.6)', // Red
'rgba(0, 255, 0, 0.6)', // Green
'rgba(0, 0, 255, 0.6)', // Blue
'rgba(255, 255, 0, 0.6)', // Yellow
'rgba(255, 0, 255, 0.6)', // Magenta
'rgba(0, 255, 255, 0.6)', // Cyan
];
return colors[index % colors.length];
}
private getBorderColor(index: number): string {
const colors = ['blue', 'green', 'red', 'orange', 'purple', 'cyan'];
return colors[index % colors.length];
}
private getHoverBackgroundColor(index: number): string {
const colors = ['purple', 'yellow', 'orange', 'red', 'blue', 'green'];
return colors[index % colors.length];
}
private getHoverBorderColor(index: number): string {
const colors = ['red', 'blue', 'green', 'purple', 'yellow', 'orange'];
return colors[index % colors.length];
}
// events
public chartClicked(e: any): void {
console.log('Bubble chart clicked:', e);
@ -424,18 +436,16 @@ export class BubbleChartComponent implements OnInit, OnChanges {
// Get the index of the clicked element
const clickedIndex = e.active[0].index;
// Get the dataset index
const datasetIndex = e.active[0].datasetIndex;
// Get the label of the clicked element
// For bubble charts, we might not have labels in the same way as other charts
const clickedLabel = `Bubble ${clickedIndex}`;
// Get the data point
const dataPoint = this.bubbleChartData[datasetIndex].data[clickedIndex];
console.log('Clicked on bubble:', { datasetIndex: datasetIndex, index: clickedIndex, dataPoint: dataPoint });
console.log('Clicked on bubble:', { index: clickedIndex, label: clickedLabel });
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {
// Store original data before entering drilldown mode
this.originalBubbleChartData = JSON.parse(JSON.stringify(this.bubbleChartData));
this.originalBubbleChartData = [...this.bubbleChartData];
console.log('Stored original data for drilldown');
}
@ -474,16 +484,12 @@ export class BubbleChartComponent implements OnInit, OnChanges {
// If there's a drilldown configuration for the next level, proceed
if (hasDrilldownConfig) {
// For bubble charts, we'll use the x value as the clicked value
const clickedValue = dataPoint && (dataPoint as any).x !== undefined ?
(dataPoint as any).x.toString() : '';
// Add this click to the drilldown stack
const stackEntry = {
level: nextDrilldownLevel,
datasetIndex: datasetIndex,
clickedIndex: clickedIndex,
clickedValue: clickedValue
clickedLabel: clickedLabel,
clickedValue: clickedLabel // Using label as value for now
};
this.drilldownStack.push(stackEntry);

View File

@ -28,6 +28,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -92,6 +93,9 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
constructor(private dashboardService: Dashboard3Service) { }
ngOnInit(): void {
@ -148,6 +152,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -155,11 +160,11 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
@ -174,9 +179,14 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
}
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -187,13 +197,28 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/doughnut?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Doughnut chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'doughnut', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'doughnut', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received doughnut chart data:', data);
if (data === null) {
@ -201,6 +226,10 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
this.noDataAvailable = true;
this.doughnutChartLabels = [];
this.doughnutChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -248,31 +277,34 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
this.noDataAvailable = true;
this.doughnutChartLabels = [];
this.doughnutChartData = [];
// Validate and sanitize data
// Validate and sanitize data to show default data
this.validateChartData();
}
// Log final state for debugging
console.log('Final doughnut chart state:', {
labels: this.doughnutChartLabels,
data: this.doughnutChartData,
labelsLength: this.doughnutChartLabels.length,
dataLength: this.doughnutChartData.length
});
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching doughnut chart data:', error);
this.noDataAvailable = true;
this.doughnutChartLabels = [];
this.doughnutChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
}
);
} else {
console.log('Missing required data for doughnut chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
console.log('Missing required data for doughnut chart, showing default data:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
// Don't set noDataAvailable to true when there's no required data
// This allows static data to be displayed
// Only validate the chart data to ensure we have some data to display
this.noDataAvailable = false;
// Validate the chart data to ensure we have some data to display
this.validateChartData();
// Force a redraw to ensure the chart displays
this.doughnutChartData = [...this.doughnutChartData];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -354,13 +386,27 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/doughnut?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'doughnut', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'doughnut', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -417,20 +463,13 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// Validate and sanitize data
this.validateChartData();
}
// Log final state for debugging
console.log('Final doughnut chart state:', {
labels: this.doughnutChartLabels,
data: this.doughnutChartData,
labelsLength: this.doughnutChartLabels.length,
dataLength: this.doughnutChartData.length
});
},
(error) => {
console.error('Error fetching drilldown data:', error);
this.noDataAvailable = true;
this.doughnutChartLabels = [];
this.doughnutChartData = [];
// Keep current data in case of error
}
);
}

View File

@ -30,6 +30,7 @@ export class DynamicChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -50,6 +51,7 @@ export class DynamicChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -57,12 +59,11 @@ export class DynamicChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
@ -101,10 +102,18 @@ export class DynamicChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -115,13 +124,28 @@ export class DynamicChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/dynamic?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Dynamic chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'dynamic', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'dynamic', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received dynamic chart data:', data);
if (data === null) {
@ -129,6 +153,8 @@ export class DynamicChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.dynamicChartLabels = [];
this.dynamicChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -155,12 +181,16 @@ export class DynamicChartComponent implements OnInit, OnChanges {
this.dynamicChartLabels = [];
this.dynamicChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching dynamic chart data:', error);
this.noDataAvailable = true;
this.dynamicChartLabels = [];
this.dynamicChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
@ -169,6 +199,8 @@ export class DynamicChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.dynamicChartLabels = [];
this.dynamicChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -250,13 +282,27 @@ export class DynamicChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/dynamic?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'dynamic', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'dynamic', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -366,13 +412,10 @@ export class DynamicChartComponent implements OnInit, OnChanges {
// Get the index of the clicked element
const clickedIndex = e.active[0].index;
// Get the label of the clicked element (if available)
let clickedLabel = '';
if (this.dynamicChartLabels && this.dynamicChartLabels[clickedIndex]) {
clickedLabel = this.dynamicChartLabels[clickedIndex];
}
// Get the label of the clicked element
const clickedLabel = this.dynamicChartLabels[clickedIndex];
console.log('Clicked on dynamic chart element:', { index: clickedIndex, label: clickedLabel });
console.log('Clicked on dynamic chart point:', { index: clickedIndex, label: clickedLabel });
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {
@ -450,6 +493,13 @@ export class DynamicChartComponent implements OnInit, OnChanges {
}
public randomize(): void {
this.barChartType = this.barChartType === 'bar' ? 'line' : 'bar';
let _dynamicChartData: Array<any> = new Array(this.dynamicChartData.length);
for (let i = 0; i < this.dynamicChartData.length; i++) {
_dynamicChartData[i] = {data: new Array(this.dynamicChartData[i].data.length), label: this.dynamicChartData[i].label};
for (let j = 0; j < this.dynamicChartData[i].data.length; j++) {
_dynamicChartData[i].data[j] = Math.floor((Math.random() * 100) + 1);
}
}
this.dynamicChartData = _dynamicChartData;
}
}

View File

@ -28,6 +28,7 @@ export class FinancialChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -46,6 +47,7 @@ export class FinancialChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -53,12 +55,11 @@ export class FinancialChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
@ -80,10 +81,18 @@ export class FinancialChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -94,13 +103,28 @@ export class FinancialChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/financial?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Financial chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'financial', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'financial', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received financial chart data:', data);
if (data === null) {
@ -108,6 +132,8 @@ export class FinancialChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.financialChartLabels = [];
this.financialChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -146,12 +172,16 @@ export class FinancialChartComponent implements OnInit, OnChanges {
this.financialChartLabels = [];
this.financialChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching financial chart data:', error);
this.noDataAvailable = true;
this.financialChartLabels = [];
this.financialChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
@ -160,6 +190,8 @@ export class FinancialChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.financialChartLabels = [];
this.financialChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -241,13 +273,27 @@ export class FinancialChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/financial?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'financial', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'financial', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -369,13 +415,10 @@ export class FinancialChartComponent implements OnInit, OnChanges {
// Get the index of the clicked element
const clickedIndex = e.active[0].index;
// Get the label of the clicked element (if available)
let clickedLabel = '';
if (this.financialChartLabels && this.financialChartLabels[clickedIndex]) {
clickedLabel = this.financialChartLabels[clickedIndex];
}
// Get the label of the clicked element
const clickedLabel = this.financialChartLabels[clickedIndex];
console.log('Clicked on financial chart element:', { index: clickedIndex, label: clickedLabel });
console.log('Clicked on financial chart point:', { index: clickedIndex, label: clickedLabel });
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {

View File

@ -28,6 +28,7 @@ export class LineChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -78,6 +79,9 @@ export class LineChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
constructor(private dashboardService: Dashboard3Service) { }
ngOnInit(): void {
@ -93,6 +97,7 @@ export class LineChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -100,12 +105,11 @@ export class LineChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
@ -117,9 +121,14 @@ export class LineChartComponent implements OnInit, OnChanges {
}
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -130,13 +139,28 @@ export class LineChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/line?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'line', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'line', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received chart data:', data);
if (data === null) {
@ -144,6 +168,8 @@ export class LineChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.lineChartLabels = [];
this.lineChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -170,12 +196,16 @@ export class LineChartComponent implements OnInit, OnChanges {
this.lineChartLabels = [];
this.lineChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching chart data:', error);
this.noDataAvailable = true;
this.lineChartLabels = [];
this.lineChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
@ -184,6 +214,8 @@ export class LineChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.lineChartLabels = [];
this.lineChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -265,13 +297,27 @@ export class LineChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/line?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'line', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'line', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -372,6 +418,29 @@ export class LineChartComponent implements OnInit, OnChanges {
}
}
// Ensure labels and data arrays have the same length
private syncLabelAndDataArrays(): void {
// For line charts, we need to ensure all datasets have the same number of data points
if (this.lineChartData && this.lineChartData.length > 0 && this.lineChartLabels) {
const labelCount = this.lineChartLabels.length;
this.lineChartData.forEach(dataset => {
if (dataset.data) {
// If dataset has more data points than labels, truncate the data
if (dataset.data.length > labelCount) {
dataset.data = dataset.data.slice(0, labelCount);
}
// If dataset has fewer data points than labels, pad with zeros
else if (dataset.data.length < labelCount) {
while (dataset.data.length < labelCount) {
dataset.data.push(0);
}
}
}
});
}
}
public randomize(): void {
let _lineChartData: Array<any> = new Array(this.lineChartData.length);
for (let i = 0; i < this.lineChartData.length; i++) {

View File

@ -28,6 +28,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -91,6 +92,9 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
constructor(private dashboardService: Dashboard3Service) { }
/**
@ -117,6 +121,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -124,20 +129,24 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -148,13 +157,28 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/pie?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Pie chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'pie', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'pie', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received pie chart data:', data);
if (data === null) {
@ -164,6 +188,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
this.pieChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -214,6 +240,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
// Validate and sanitize data to show default data
this.validateChartData();
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching pie chart data:', error);
@ -222,6 +250,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
this.pieChartData = [];
// Validate and sanitize data to show default data
this.validateChartData();
// Reset flag after fetching
this.isFetchingData = false;
}
);
} else {
@ -233,6 +263,8 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
this.validateChartData();
// Force a redraw to ensure the chart displays
this.pieChartData = [...this.pieChartData];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -314,13 +346,27 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/pie?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'pie', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -28,6 +28,7 @@ export class PolarChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -46,6 +47,7 @@ export class PolarChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -53,12 +55,11 @@ export class PolarChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
@ -79,10 +80,18 @@ export class PolarChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -93,13 +102,28 @@ export class PolarChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/polar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Polar chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'polar', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'polar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received polar chart data:', data);
if (data === null) {
@ -107,6 +131,8 @@ export class PolarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -144,12 +170,16 @@ export class PolarChartComponent implements OnInit, OnChanges {
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching polar chart data:', error);
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
@ -158,6 +188,8 @@ export class PolarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.polarAreaChartLabels = [];
this.polarAreaChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -239,13 +271,27 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/polar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'polar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'polar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -369,7 +415,7 @@ export class PolarChartComponent implements OnInit, OnChanges {
// Get the label of the clicked element
const clickedLabel = this.polarAreaChartLabels[clickedIndex];
console.log('Clicked on polar slice:', { index: clickedIndex, label: clickedLabel });
console.log('Clicked on polar area:', { index: clickedIndex, label: clickedLabel });
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {
@ -445,5 +491,4 @@ export class PolarChartComponent implements OnInit, OnChanges {
public chartHovered(e: any): void {
console.log(e);
}
}

View File

@ -28,6 +28,7 @@ export class RadarChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -57,6 +58,9 @@ export class RadarChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
constructor(private dashboardService: Dashboard3Service) { }
ngOnInit(): void {
@ -71,6 +75,7 @@ export class RadarChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -78,19 +83,24 @@ export class RadarChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -101,13 +111,28 @@ export class RadarChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/radar?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Radar chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'radar', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'radar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received radar chart data:', data);
if (data === null) {
@ -115,6 +140,8 @@ export class RadarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.radarChartLabels = [];
this.radarChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -155,12 +182,16 @@ export class RadarChartComponent implements OnInit, OnChanges {
this.radarChartLabels = [];
this.radarChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching radar chart data:', error);
this.noDataAvailable = true;
this.radarChartLabels = [];
this.radarChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
);
} else {
@ -168,6 +199,8 @@ export class RadarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.radarChartLabels = [];
this.radarChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -249,13 +282,27 @@ export class RadarChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/radar?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'radar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'radar', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {

View File

@ -29,6 +29,7 @@ export class ScatterChartComponent implements OnInit, OnChanges {
@Input() drilldownXAxis: string;
@Input() drilldownYAxis: string;
@Input() drilldownParameter: string; // Add drilldown parameter input
@Input() baseFilters: any[] = []; // Add base filters input
// Multi-layer drilldown configuration inputs
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
@ -47,6 +48,7 @@ export class ScatterChartComponent implements OnInit, OnChanges {
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
const tableChanged = changes.table && !changes.table.firstChange;
const connectionChanged = changes.connection && !changes.connection.firstChange;
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
// Drilldown configuration changes
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
@ -54,12 +56,11 @@ export class ScatterChartComponent implements OnInit, OnChanges {
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
// Respond to input changes
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged ||
// Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
drilldownLayersChanged) {
console.log('X or Y axis or table or connection or drilldown config changed, fetching new data');
// Only fetch data if xAxis, yAxis, table, connection, or drilldown config has changed (and it's not the first change)
drilldownLayersChanged)) {
console.log('Chart configuration changed, fetching new data');
this.fetchChartData();
}
}
@ -101,10 +102,18 @@ export class ScatterChartComponent implements OnInit, OnChanges {
// No data state
noDataAvailable: boolean = false;
// Flag to prevent infinite loops
private isFetchingData: boolean = false;
fetchChartData(): void {
// Set flag to prevent recursive calls
this.isFetchingData = true;
// If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
this.fetchDrilldownData();
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -115,19 +124,36 @@ export class ScatterChartComponent implements OnInit, OnChanges {
// Convert yAxis to string if it's an array
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
// Convert baseFilters to filter parameters
let filterParams = '';
if (this.baseFilters && this.baseFilters.length > 0) {
const filterObj = {};
this.baseFilters.forEach(filter => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
console.log('Base filter parameters:', filterParams);
// Log the URL that will be called
const url = `chart/getdashjson/scatter?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Scatter chart data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// For base level, we pass empty parameter and value
this.dashboardService.getChartData(this.table, 'scatter', this.xAxis, yAxisString, this.connection, '', '').subscribe(
// For base level, we pass empty parameter and value, but now also pass filters
this.dashboardService.getChartData(this.table, 'scatter', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => {
console.log('Received scatter chart data:', data);
if (data === null) {
console.warn('Scatter chart API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true;
this.scatterChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
@ -148,11 +174,15 @@ export class ScatterChartComponent implements OnInit, OnChanges {
this.noDataAvailable = true;
this.scatterChartData = [];
}
// Reset flag after fetching
this.isFetchingData = false;
},
(error) => {
console.error('Error fetching scatter chart data:', error);
this.noDataAvailable = true;
this.scatterChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
// Keep default data in case of error
}
);
@ -160,6 +190,8 @@ export class ScatterChartComponent implements OnInit, OnChanges {
console.log('Missing required data for scatter chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true;
this.scatterChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
}
}
@ -239,13 +271,27 @@ export class ScatterChartComponent implements OnInit, OnChanges {
console.log('URL after angle bracket replacement:', actualApiUrl);
}
// Convert drilldown layer filters to filter parameters (if applicable)
let filterParams = '';
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
const filterObj = {};
drilldownConfig.filters.forEach((filter: any) => {
if (filter.field && filter.value) {
filterObj[filter.field] = filter.value;
}
});
if (Object.keys(filterObj).length > 0) {
filterParams = JSON.stringify(filterObj);
}
}
// Log the URL that will be called
const url = `chart/getdashjson/scatter?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
console.log('Drilldown data URL:', url);
// Fetch data from the dashboard service with parameter field and value
// Backend handles filtering, we just pass the parameter field and value
this.dashboardService.getChartData(actualApiUrl, 'scatter', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue).subscribe(
this.dashboardService.getChartData(actualApiUrl, 'scatter', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => {
console.log('Received drilldown data:', data);
if (data === null) {
@ -282,6 +328,33 @@ export class ScatterChartComponent implements OnInit, OnChanges {
);
}
// Transform chart data to scatter chart format
private transformToScatterData(labels: string[], datasets: any[]): ChartDataset[] {
// For scatter charts, we need to transform the data into scatter format
// Scatter charts expect data in the format: {x: number, y: number}
// This is a simple transformation - in a real implementation, you might want to
// create a more sophisticated mapping based on your data structure
return datasets.map((dataset, index) => {
// Create scatter data points
const scatterData = labels.map((label, i) => {
// Use x-axis data as x coordinate, y-axis data as y coordinate
const xValue = dataset.data[i] || 0;
const yValue = i < datasets.length ? (datasets[i].data[index] || 0) : 0;
return { x: xValue, y: yValue };
});
return {
data: scatterData,
label: dataset.label || `Dataset ${index + 1}`,
backgroundColor: dataset.backgroundColor || `rgba(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, 0.6)`,
borderColor: dataset.borderColor || 'rgba(0, 0, 0, 1)',
pointRadius: dataset.pointRadius || 5
};
});
}
// Reset to original data (go back to base level)
resetToOriginalData(): void {
console.log('Resetting to original data');
@ -333,45 +406,6 @@ export class ScatterChartComponent implements OnInit, OnChanges {
}
}
private transformToScatterData(labels: any[], chartData: any[]): ChartDataset[] {
// Transform the API data into scatter chart format
const datasets: ChartDataset[] = [];
// Create a dataset for each data series
chartData.forEach((series, index) => {
// For scatter charts, we need x and y values
// We'll use the labels as x values and the data as y values
const scatterData = labels.map((label, i) => {
const xValue = isNaN(Number(label)) ? i : Number(label);
const yValue = series.data && series.data[i] !== undefined ?
(isNaN(Number(series.data[i])) ? 0 : Number(series.data[i])) : 0;
return {
x: xValue,
y: yValue
};
});
datasets.push({
data: scatterData,
label: series.label || `Series ${index + 1}`,
pointRadius: 10,
backgroundColor: this.getBackgroundColor(index),
});
});
return datasets;
}
private getBackgroundColor(index: number): string {
const colors = [
'red', 'green', 'blue', 'purple', 'yellow',
'brown', 'magenta', 'cyan', 'orange', 'pink'
];
return colors[index % colors.length];
}
// events
public chartClicked(e: any): void {
console.log('Scatter chart clicked:', e);
@ -381,18 +415,16 @@ export class ScatterChartComponent implements OnInit, OnChanges {
// Get the index of the clicked element
const clickedIndex = e.active[0].index;
// Get the dataset index
const datasetIndex = e.active[0].datasetIndex;
// Get the label of the clicked element
// For scatter charts, we might not have labels in the same way as other charts
const clickedLabel = `Point ${clickedIndex}`;
// Get the data point
const dataPoint = this.scatterChartData[datasetIndex].data[clickedIndex];
console.log('Clicked on scatter point:', { datasetIndex: datasetIndex, index: clickedIndex, dataPoint: dataPoint });
console.log('Clicked on scatter point:', { index: clickedIndex, label: clickedLabel });
// If we're not at the base level, store original data
if (this.currentDrilldownLevel === 0) {
// Store original data before entering drilldown mode
this.originalScatterChartData = JSON.parse(JSON.stringify(this.scatterChartData));
this.originalScatterChartData = [...this.scatterChartData];
console.log('Stored original data for drilldown');
}
@ -431,16 +463,12 @@ export class ScatterChartComponent implements OnInit, OnChanges {
// If there's a drilldown configuration for the next level, proceed
if (hasDrilldownConfig) {
// For scatter charts, we'll use the x value as the clicked value
const clickedValue = dataPoint && (dataPoint as any).x !== undefined ?
(dataPoint as any).x.toString() : '';
// Add this click to the drilldown stack
const stackEntry = {
level: nextDrilldownLevel,
datasetIndex: datasetIndex,
clickedIndex: clickedIndex,
clickedValue: clickedValue
clickedLabel: clickedLabel,
clickedValue: clickedLabel // Using label as value for now
};
this.drilldownStack.push(stackEntry);