diff --git a/readme.hints.md b/readme.hints.md index ec2dbb9..b77b61c 100644 --- a/readme.hints.md +++ b/readme.hints.md @@ -8,8 +8,10 @@ ### dees-chart-area - Fully functional area chart component using ApexCharts - Displays time-series data with gradient fills -- Responsive with ResizeObserver +- Responsive with ResizeObserver (debounced to prevent flicker) - Demo shows CPU and memory usage metrics +- Fixed: Chart now properly respects container boundaries on initial render +- Overflow prevention with proper CSS containment ### dees-chart-log - Server log viewer component (not a chart despite the name) diff --git a/ts_web/elements/dees-chart-area.ts b/ts_web/elements/dees-chart-area.ts index 40b4f57..6ff6bcd 100644 --- a/ts_web/elements/dees-chart-area.ts +++ b/ts_web/elements/dees-chart-area.ts @@ -33,27 +33,40 @@ export class DeesChartArea extends DeesElement { public label: string = 'Untitled Chart'; private resizeObserver: ResizeObserver; + private resizeTimeout: number; constructor() { super(); domtools.elementBasic.setup(); this.resizeObserver = new ResizeObserver((entries) => { - for (let entry of entries) { - if (entry.target.classList.contains('mainbox')) { - this.resizeChart(); // Call resizeChart when the .mainbox size changes - } + // Debounce resize calls to prevent excessive updates + if (this.resizeTimeout) { + clearTimeout(this.resizeTimeout); } + + this.resizeTimeout = window.setTimeout(() => { + for (let entry of entries) { + if (entry.target.classList.contains('mainbox') && this.chart) { + this.resizeChart(); + } + } + }, 100); // 100ms debounce }); + this.registerStartupFunction(async () => { this.updateComplete.then(() => { const mainbox = this.shadowRoot.querySelector('.mainbox'); if (mainbox) { - this.resizeObserver.observe(mainbox); // Start observing the .mainbox element + this.resizeObserver.observe(mainbox); } }); }); + this.registerGarbageFunction(async () => { + if (this.resizeTimeout) { + clearTimeout(this.resizeTimeout); + } this.resizeObserver.disconnect(); }); } @@ -73,6 +86,7 @@ export class DeesChartArea extends DeesElement { height: 400px; background: #111; border-radius: 8px; + overflow: hidden; } .chartTitle { @@ -82,6 +96,7 @@ export class DeesChartArea extends DeesElement { width: 100%; text-align: center; padding-top: 16px; + z-index: 10; } .chartContainer { position: absolute; @@ -90,6 +105,7 @@ export class DeesChartArea extends DeesElement { bottom: 0px; right: 0px; padding: 32px 16px 16px 0px; + overflow: hidden; } `, ]; @@ -104,7 +120,30 @@ export class DeesChartArea extends DeesElement { } public async firstUpdated() { - const domtoolsInstance = await this.domtoolsPromise; + await this.domtoolsPromise; + + // Wait for next animation frame to ensure layout is complete + await new Promise(resolve => requestAnimationFrame(resolve)); + + // Get actual dimensions of the container + const mainbox: HTMLDivElement = this.shadowRoot.querySelector('.mainbox'); + const chartContainer: HTMLDivElement = this.shadowRoot.querySelector('.chartContainer'); + + if (!mainbox || !chartContainer) { + console.error('Chart containers not found'); + return; + } + + // Calculate initial dimensions + const styleChartContainer = window.getComputedStyle(chartContainer); + const paddingTop = parseInt(styleChartContainer.paddingTop, 10); + const paddingBottom = parseInt(styleChartContainer.paddingBottom, 10); + const paddingLeft = parseInt(styleChartContainer.paddingLeft, 10); + const paddingRight = parseInt(styleChartContainer.paddingRight, 10); + + const initialWidth = mainbox.clientWidth - paddingLeft - paddingRight; + const initialHeight = mainbox.offsetHeight - paddingTop - paddingBottom; + var options: ApexCharts.ApexOptions = { series: [ { @@ -129,12 +168,20 @@ export class DeesChartArea extends DeesElement { }, ], chart: { - width: 0, // Adjusted for responsive width - height: 0, // Adjusted for responsive height + width: initialWidth || 100, // Use actual width or fallback + height: initialHeight || 100, // Use actual height or fallback type: 'area', toolbar: { show: false, // This line disables the toolbar }, + animations: { + enabled: true, + speed: 400, + animateGradually: { + enabled: true, + delay: 150 + }, + }, }, dataLabels: { enabled: false, @@ -184,14 +231,11 @@ export class DeesChartArea extends DeesElement { x: { format: 'dd/MM/yy HH:mm', }, - custom: function ({ series, seriesIndex, dataPointIndex, w }) { - // Get the x value - const xValue = w.globals.labels[dataPointIndex]; + custom: function ({ series, dataPointIndex, w }: any) { // Iterate through each series and get its value let tooltipContent = `