Improves all-day event header animation performance
Optimizes all-day event header animation by caching DOM elements. This change avoids redundant DOM queries during animation, resulting in smoother transitions when adding or removing all-day events. It also introduces a destroy method for proper cleanup of cached elements.
This commit is contained in:
parent
7f387cfa30
commit
77592278d3
1 changed files with 81 additions and 12 deletions
|
|
@ -19,14 +19,76 @@ export interface HeaderRenderer {
|
||||||
* Base class with shared addToAllDay implementation
|
* Base class with shared addToAllDay implementation
|
||||||
*/
|
*/
|
||||||
export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
|
// Cached DOM elements to avoid redundant queries
|
||||||
|
private cachedCalendarHeader: HTMLElement | null = null;
|
||||||
|
private cachedAllDayContainer: HTMLElement | null = null;
|
||||||
|
private cachedHeaderSpacer: HTMLElement | null = null;
|
||||||
|
|
||||||
abstract render(calendarHeader: HTMLElement, context: HeaderRenderContext): void;
|
abstract render(calendarHeader: HTMLElement, context: HeaderRenderContext): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached calendar header element
|
||||||
|
*/
|
||||||
|
private getCalendarHeader(): HTMLElement | null {
|
||||||
|
if (!this.cachedCalendarHeader) {
|
||||||
|
this.cachedCalendarHeader = document.querySelector('swp-calendar-header');
|
||||||
|
}
|
||||||
|
return this.cachedCalendarHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached all-day container element
|
||||||
|
*/
|
||||||
|
private getAllDayContainer(): HTMLElement | null {
|
||||||
|
if (!this.cachedAllDayContainer) {
|
||||||
|
const calendarHeader = this.getCalendarHeader();
|
||||||
|
if (calendarHeader) {
|
||||||
|
this.cachedAllDayContainer = calendarHeader.querySelector('swp-allday-container');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.cachedAllDayContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get cached header spacer element
|
||||||
|
*/
|
||||||
|
private getHeaderSpacer(): HTMLElement | null {
|
||||||
|
if (!this.cachedHeaderSpacer) {
|
||||||
|
this.cachedHeaderSpacer = document.querySelector('swp-header-spacer');
|
||||||
|
}
|
||||||
|
return this.cachedHeaderSpacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate all-day height based on number of rows
|
||||||
|
*/
|
||||||
|
private calculateAllDayHeight(targetRows: number): {
|
||||||
|
targetHeight: number;
|
||||||
|
currentHeight: number;
|
||||||
|
heightDifference: number;
|
||||||
|
} {
|
||||||
|
const root = document.documentElement;
|
||||||
|
const targetHeight = targetRows * ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT;
|
||||||
|
const currentHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-row-height') || '0');
|
||||||
|
const heightDifference = targetHeight - currentHeight;
|
||||||
|
|
||||||
|
return { targetHeight, currentHeight, heightDifference };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear cached DOM elements (call when DOM structure changes)
|
||||||
|
*/
|
||||||
|
private clearCache(): void {
|
||||||
|
this.cachedCalendarHeader = null;
|
||||||
|
this.cachedAllDayContainer = null;
|
||||||
|
this.cachedHeaderSpacer = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand header to show all-day row
|
* Expand header to show all-day row
|
||||||
*/
|
*/
|
||||||
addToAllDay(dayHeader: HTMLElement): void {
|
addToAllDay(dayHeader: HTMLElement): void {
|
||||||
const root = document.documentElement;
|
const { currentHeight } = this.calculateAllDayHeight(0);
|
||||||
const currentHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-row-height') || '0');
|
|
||||||
|
|
||||||
if (currentHeight === 0) {
|
if (currentHeight === 0) {
|
||||||
// Find the calendar header element to animate
|
// Find the calendar header element to animate
|
||||||
|
|
@ -47,7 +109,7 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAndAnimateAllDayHeight(): void {
|
checkAndAnimateAllDayHeight(): void {
|
||||||
const container = document.querySelector('swp-allday-container');
|
const container = this.getAllDayContainer();
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const allDayEvents = container.querySelectorAll('swp-allday-event');
|
const allDayEvents = container.querySelectorAll('swp-allday-event');
|
||||||
|
|
@ -100,24 +162,21 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
* Animate all-day container to specific number of rows
|
* Animate all-day container to specific number of rows
|
||||||
*/
|
*/
|
||||||
animateToRows(targetRows: number): void {
|
animateToRows(targetRows: number): void {
|
||||||
const root = document.documentElement;
|
const { targetHeight, currentHeight, heightDifference } = this.calculateAllDayHeight(targetRows);
|
||||||
const targetHeight = targetRows * ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT;
|
|
||||||
const currentHeight = parseInt(getComputedStyle(root).getPropertyValue('--all-day-row-height') || '0');
|
|
||||||
|
|
||||||
if (targetHeight === currentHeight) return; // No animation needed
|
if (targetHeight === currentHeight) return; // No animation needed
|
||||||
|
|
||||||
console.log(`🎬 All-day height animation starting: ${currentHeight}px → ${targetHeight}px (${Math.ceil(currentHeight / ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT)} → ${targetRows} rows)`);
|
console.log(`🎬 All-day height animation starting: ${currentHeight}px → ${targetHeight}px (${Math.ceil(currentHeight / ALL_DAY_CONSTANTS.SINGLE_ROW_HEIGHT)} → ${targetRows} rows)`);
|
||||||
|
|
||||||
// Find elements to animate
|
// Get cached elements
|
||||||
const calendarHeader = document.querySelector('swp-calendar-header') as HTMLElement;
|
const calendarHeader = this.getCalendarHeader();
|
||||||
const headerSpacer = document.querySelector('swp-header-spacer') as HTMLElement;
|
const headerSpacer = this.getHeaderSpacer();
|
||||||
const allDayContainer = calendarHeader?.querySelector('swp-allday-container') as HTMLElement;
|
const allDayContainer = this.getAllDayContainer();
|
||||||
|
|
||||||
if (!calendarHeader || !allDayContainer) return;
|
if (!calendarHeader || !allDayContainer) return;
|
||||||
|
|
||||||
// Get current parent height for animation
|
// Get current parent height for animation
|
||||||
const currentParentHeight = parseFloat(getComputedStyle(calendarHeader).height);
|
const currentParentHeight = parseFloat(getComputedStyle(calendarHeader).height);
|
||||||
const heightDifference = targetHeight - currentHeight;
|
|
||||||
const targetParentHeight = currentParentHeight + heightDifference;
|
const targetParentHeight = currentParentHeight + heightDifference;
|
||||||
|
|
||||||
const animations = [
|
const animations = [
|
||||||
|
|
@ -133,6 +192,7 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
|
|
||||||
// Add spacer animation if spacer exists
|
// Add spacer animation if spacer exists
|
||||||
if (headerSpacer) {
|
if (headerSpacer) {
|
||||||
|
const root = document.documentElement;
|
||||||
const currentSpacerHeight = parseInt(getComputedStyle(root).getPropertyValue('--header-height')) + currentHeight;
|
const currentSpacerHeight = parseInt(getComputedStyle(root).getPropertyValue('--header-height')) + currentHeight;
|
||||||
const targetSpacerHeight = parseInt(getComputedStyle(root).getPropertyValue('--header-height')) + targetHeight;
|
const targetSpacerHeight = parseInt(getComputedStyle(root).getPropertyValue('--header-height')) + targetHeight;
|
||||||
|
|
||||||
|
|
@ -150,6 +210,7 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
|
|
||||||
// Update CSS variable after animation
|
// Update CSS variable after animation
|
||||||
Promise.all(animations.map(anim => anim.finished)).then(() => {
|
Promise.all(animations.map(anim => anim.finished)).then(() => {
|
||||||
|
const root = document.documentElement;
|
||||||
root.style.setProperty('--all-day-row-height', `${targetHeight}px`);
|
root.style.setProperty('--all-day-row-height', `${targetHeight}px`);
|
||||||
eventBus.emit('header:height-changed');
|
eventBus.emit('header:height-changed');
|
||||||
});
|
});
|
||||||
|
|
@ -163,9 +224,17 @@ export abstract class BaseHeaderRenderer implements HeaderRenderer {
|
||||||
// Create simple all-day container (initially hidden)
|
// Create simple all-day container (initially hidden)
|
||||||
container = document.createElement('swp-allday-container');
|
container = document.createElement('swp-allday-container');
|
||||||
calendarHeader.appendChild(container);
|
calendarHeader.appendChild(container);
|
||||||
} else {
|
// Clear cache since DOM structure changed
|
||||||
|
this.clearCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public cleanup method for cached elements
|
||||||
|
*/
|
||||||
|
public destroy(): void {
|
||||||
|
this.clearCache();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue