This commit is contained in:
Gaurav Kumar
2025-11-04 19:11:00 +05:30
parent 71be18b21f
commit 40438fcc1b
2 changed files with 154 additions and 106 deletions

View File

@@ -1,11 +1,4 @@
<div class="chart-container" *ngIf="!noDataAvailable && !isLoading">
<!-- Dynamic template container -->
<div class="dynamic-template-container" *ngIf="dynamicTemplate" [innerHTML]="dynamicTemplate"></div>
<!-- Debug: Show when dynamic template is loaded -->
<div *ngIf="dynamicTemplate" style="color: red; font-weight: bold; margin: 10px;">
DEBUG: Dynamic template loaded - check browser DevTools Elements tab to see if canvas is in DOM
</div>
<!-- Back button for drilldown navigation -->
<div class="drilldown-back" *ngIf="currentDrilldownLevel > 0">
<button class="btn btn-sm btn-secondary" (click)="navigateBack()">
@@ -33,110 +26,21 @@
<!-- Render different chart types based on chartType input -->
<div class="chart-wrapper">
<!-- Bar Chart -->
<!-- <div *ngIf="chartType === 'bar'" class="chart-canvas-container">
<!-- Dynamic Chart Container - uses extracted dynamic options and styles but static template -->
<div *ngIf="dynamicTemplate || chartType" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'bar'"
[chartType]="chartType || 'bar'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
</div>
<!-- Line Chart -->
<!-- <div *ngIf="chartType === 'line'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'line'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Pie Chart -->
<!-- <div *ngIf="chartType === 'pie'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'pie'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Doughnut Chart -->
<!-- <div *ngIf="chartType === 'doughnut'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'doughnut'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Bubble Chart -->
<!-- <div *ngIf="chartType === 'bubble'" class="chart-canvas-container">
<canvas baseChart
[datasets]="bubbleChartData"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'bubble'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Radar Chart -->
<!-- <div *ngIf="chartType === 'radar'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'radar'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Polar Area Chart -->
<!-- <div *ngIf="chartType === 'polar'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'polarArea'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Scatter Chart -->
<!-- <div *ngIf="chartType === 'scatter'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[options]="chartOptions"
[legend]="chartLegend"
[chartType]="'scatter'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div> -->
<!-- Default/Unknown Chart Type -->
<div *ngIf="!dynamicTemplate && !['bar', 'line', 'pie', 'doughnut', 'bubble', 'radar', 'polar', 'scatter'].includes(chartType)" class="chart-canvas-container">
<!-- Fallback for when no chart type is specified -->
<div *ngIf="!dynamicTemplate && !chartType" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"

View File

@@ -81,13 +81,42 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
dynamicStyles: string = '';
dynamicOptions: any = null;
// Properties to hold extracted values from dynamic template
extractedChartType: string = '';
extractedDatasetsBinding: string = '';
extractedLabelsBinding: string = '';
extractedOptionsBinding: string = '';
extractedLegendBinding: string = '';
extractedChartClickBinding: string = '';
extractedChartHoverBinding: string = '';
// Add setter to log when dynamicTemplate changes
setDynamicTemplate(value: string) {
console.log('Setting dynamic template:', value);
this.dynamicTemplate = value;
// Extract values from the dynamic template
this.extractTemplateValues(value);
// Apply dynamic options if they were extracted
if (this.dynamicOptions) {
this.mergeDynamicOptions();
}
// Apply dynamic styles if they were extracted
if (this.dynamicStyles) {
this.applyDynamicStyles();
}
// Trigger change detection to ensure the template is rendered
setTimeout(() => {
console.log('Dynamic template updated in DOM');
// Check if the dynamic template container exists
const dynamicContainer = this.el.nativeElement.querySelector('.dynamic-template-container');
console.log('Dynamic template container:', dynamicContainer);
if (dynamicContainer) {
console.log('Dynamic container innerHTML:', dynamicContainer.innerHTML);
}
// Check if the canvas element exists in the DOM
const canvasElements = this.el.nativeElement.querySelectorAll('canvas');
console.log('Canvas elements found in DOM:', canvasElements.length);
@@ -96,10 +125,96 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
// Check if it has the baseChart directive processed
const firstCanvas = canvasElements[0];
console.log('Canvas has baseChart directive processed:', firstCanvas.classList.contains('chartjs-render-monitor'));
} else {
console.log('No canvas elements found - checking if template was inserted but not processed');
// Check if there's HTML content in the dynamic container
if (dynamicContainer) {
const htmlContent = dynamicContainer.innerHTML;
console.log('HTML content in dynamic container:', htmlContent);
if (htmlContent && htmlContent.includes('canvas')) {
console.log('Canvas tag found in HTML but not processed by Angular');
}
}
}
}, 100);
}
// Extract values from dynamic template HTML
private extractTemplateValues(template: string): void {
console.log('Extracting values from template:', template);
// Reset extracted values
this.extractedChartType = this.chartType || '';
this.extractedDatasetsBinding = 'chartData';
this.extractedLabelsBinding = 'chartLabels';
this.extractedOptionsBinding = 'chartOptions';
this.extractedLegendBinding = 'chartLegend';
this.extractedChartClickBinding = 'chartClicked($event)';
this.extractedChartHoverBinding = 'chartHovered($event)';
if (!template) {
console.log('No template to extract values from');
return;
}
// Parse the template to extract bindings
// Look for [chartType] binding
const chartTypeMatch = template.match(/\[chartType\]="([^"]+)"/);
if (chartTypeMatch && chartTypeMatch[1]) {
this.extractedChartType = chartTypeMatch[1];
console.log('Extracted chartType binding:', this.extractedChartType);
}
// Look for [datasets] binding
const datasetsMatch = template.match(/\[datasets\]="([^"]+)"/);
if (datasetsMatch && datasetsMatch[1]) {
this.extractedDatasetsBinding = datasetsMatch[1];
console.log('Extracted datasets binding:', this.extractedDatasetsBinding);
}
// Look for [labels] binding
const labelsMatch = template.match(/\[labels\]="([^"]+)"/);
if (labelsMatch && labelsMatch[1]) {
this.extractedLabelsBinding = labelsMatch[1];
console.log('Extracted labels binding:', this.extractedLabelsBinding);
}
// Look for [options] binding
const optionsMatch = template.match(/\[options\]="([^"]+)"/);
if (optionsMatch && optionsMatch[1]) {
this.extractedOptionsBinding = optionsMatch[1];
console.log('Extracted options binding:', this.extractedOptionsBinding);
}
// Look for [legend] binding
const legendMatch = template.match(/\[legend\]="([^"]+)"/);
if (legendMatch && legendMatch[1]) {
this.extractedLegendBinding = legendMatch[1];
console.log('Extracted legend binding:', this.extractedLegendBinding);
}
// Look for (chartClick) binding
const chartClickMatch = template.match(/\(chartClick\)="([^"]+)"/);
if (chartClickMatch && chartClickMatch[1]) {
this.extractedChartClickBinding = chartClickMatch[1];
console.log('Extracted chartClick binding:', this.extractedChartClickBinding);
}
// Look for (chartHover) binding
const chartHoverMatch = template.match(/\(chartHover\)="([^"]+)"/);
if (chartHoverMatch && chartHoverMatch[1]) {
this.extractedChartHoverBinding = chartHoverMatch[1];
console.log('Extracted chartHover binding:', this.extractedChartHoverBinding);
}
// Extract CSS styles if present in the template
const styleMatch = template.match(/<style[^>]*>([\s\S]*?)<\/style>/i);
if (styleMatch && styleMatch[1]) {
this.dynamicStyles = styleMatch[1];
console.log('Extracted CSS styles:', this.dynamicStyles);
}
}
constructor(
private dashboardService: Dashboard3Service,
private filterService: FilterService,
@@ -284,11 +399,13 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
console.log('Received chart configuration:', config);
console.log('Loaded chart configuration:', config);
// Apply the first template if available
// Apply the first template if available (for CSS styles)
if (config.templates && config.templates.length > 0) {
const defaultTemplate = config.templates.find(t => t.isDefault) || config.templates[0];
if (defaultTemplate) {
this.setDynamicTemplate(defaultTemplate.templateHtml || '');
const templateHtml = defaultTemplate.templateHtml || '';
console.log('Template HTML to be set:', templateHtml);
this.setDynamicTemplate(templateHtml);
this.dynamicStyles = defaultTemplate.templateCss || '';
// Apply styles to the component
@@ -356,8 +473,15 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
// Merge dynamic options with current chart options
private mergeDynamicOptions(): void {
if (this.dynamicOptions) {
// Merge dynamic options with existing chart options
this.chartOptions = { ...this.chartOptions, ...this.dynamicOptions };
console.log('Merging dynamic options with existing chart options:', {
existing: this.chartOptions,
dynamic: this.dynamicOptions
});
// Deep merge dynamic options with existing chart options
this.chartOptions = this.deepMerge(this.chartOptions, this.dynamicOptions);
console.log('Merged chart options:', this.chartOptions);
// If we have a chart instance, update it
if (this.chart) {
@@ -367,6 +491,25 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
}
}
// Helper method for deep merging objects
private deepMerge(target: any, source: any): any {
const result = { ...target };
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
// Recursively merge objects
result[key] = this.deepMerge(result[key] || {}, source[key]);
} else {
// Override with source value
result[key] = source[key];
}
}
}
return result;
}
// Apply dynamic styles to the component
private applyDynamicStyles(): void {
// Remove any previously applied dynamic styles
@@ -381,6 +524,7 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
this.renderer.setAttribute(styleElement, 'class', 'dynamic-chart-styles');
this.renderer.setProperty(styleElement, 'textContent', this.dynamicStyles);
this.renderer.appendChild(this.el.nativeElement, styleElement);
console.log('Applied dynamic styles to component');
}
}