Refactor event rendering with column-based event management

Improves event rendering by integrating event filtering directly into column data sources

Key changes:
- Moves event filtering responsibility to IColumnDataSource
- Simplifies event rendering pipeline by pre-filtering events per column
- Supports both date and resource-based calendar modes
- Enhances drag and drop event update mechanism

Optimizes calendar rendering performance and flexibility
This commit is contained in:
Janus C. H. Knudsen 2025-11-22 23:38:52 +01:00
parent eeaeddeef8
commit 17909696ed
9 changed files with 179 additions and 250 deletions

View file

@ -1,5 +1,5 @@
import { Configuration } from '../configurations/CalendarConfig';
import { CalendarView, ICalendarEvent } from '../types/CalendarTypes';
import { CalendarView } from '../types/CalendarTypes';
import { IColumnRenderer, IColumnRenderContext } from './ColumnRenderer';
import { eventBus } from '../core/EventBus';
import { DateService } from '../utils/DateService';
@ -105,15 +105,13 @@ export class GridRenderer {
* @param grid - Container element where grid will be rendered
* @param currentDate - Base date for the current view (e.g., any date in the week)
* @param view - Calendar view type (day/week/month)
* @param dates - Array of dates to render as columns
* @param events - All events for the period
* @param columns - Array of columns to render (each column contains its events)
*/
public renderGrid(
grid: HTMLElement,
currentDate: Date,
view: CalendarView = 'week',
columns: IColumnInfo[] = [],
events: ICalendarEvent[] = []
columns: IColumnInfo[] = []
): void {
if (!grid || !currentDate) {
@ -125,10 +123,10 @@ export class GridRenderer {
// Only clear and rebuild if grid is empty (first render)
if (grid.children.length === 0) {
this.createCompleteGridStructure(grid, currentDate, view, columns, events);
this.createCompleteGridStructure(grid, currentDate, view, columns);
} else {
// Optimized update - only refresh dynamic content
this.updateGridContent(grid, currentDate, view, columns, events);
this.updateGridContent(grid, currentDate, view, columns);
}
}
@ -146,14 +144,13 @@ export class GridRenderer {
* @param grid - Parent container
* @param currentDate - Current view date
* @param view - View type
* @param dates - Array of dates to render
* @param columns - Array of columns to render (each column contains its events)
*/
private createCompleteGridStructure(
grid: HTMLElement,
currentDate: Date,
view: CalendarView,
columns: IColumnInfo[],
events: ICalendarEvent[]
columns: IColumnInfo[]
): void {
// Create all elements in memory first for better performance
const fragment = document.createDocumentFragment();
@ -168,7 +165,7 @@ export class GridRenderer {
fragment.appendChild(timeAxis);
// Create grid container with caching
const gridContainer = this.createOptimizedGridContainer(columns, events);
const gridContainer = this.createOptimizedGridContainer(columns);
this.cachedGridContainer = gridContainer;
fragment.appendChild(gridContainer);
@ -213,14 +210,11 @@ export class GridRenderer {
* - Time grid (grid lines + day columns) - structure created here
* - Column container - created here, populated by ColumnRenderer
*
* @param currentDate - Current view date
* @param view - View type
* @param dates - Array of dates to render
* @param columns - Array of columns to render (each column contains its events)
* @returns Complete grid container element
*/
private createOptimizedGridContainer(
columns: IColumnInfo[],
events: ICalendarEvent[]
columns: IColumnInfo[]
): HTMLElement {
const gridContainer = document.createElement('swp-grid-container');
@ -238,7 +232,7 @@ export class GridRenderer {
// Create column container
const columnContainer = document.createElement('swp-day-columns');
this.renderColumnContainer(columnContainer, columns, events);
this.renderColumnContainer(columnContainer, columns);
timeGrid.appendChild(columnContainer);
scrollableContent.appendChild(timeGrid);
@ -255,13 +249,11 @@ export class GridRenderer {
* Event rendering is handled by EventRenderingService listening to GRID_RENDERED.
*
* @param columnContainer - Empty container to populate
* @param dates - Array of dates to render
* @param events - All events for the period (passed through, not used here)
* @param columns - Array of columns to render (each column contains its events)
*/
private renderColumnContainer(
columnContainer: HTMLElement,
columns: IColumnInfo[],
events: ICalendarEvent[]
columns: IColumnInfo[]
): void {
// Delegate to ColumnRenderer
this.columnRenderer.render(columnContainer, {
@ -279,21 +271,19 @@ export class GridRenderer {
* @param grid - Existing grid element
* @param currentDate - New view date
* @param view - View type
* @param dates - Array of dates to render
* @param events - All events for the period
* @param columns - Array of columns to render (each column contains its events)
*/
private updateGridContent(
grid: HTMLElement,
currentDate: Date,
view: CalendarView,
columns: IColumnInfo[],
events: ICalendarEvent[]
columns: IColumnInfo[]
): void {
// Update column container if needed
const columnContainer = grid.querySelector('swp-day-columns');
if (columnContainer) {
columnContainer.innerHTML = '';
this.renderColumnContainer(columnContainer as HTMLElement, columns, events);
this.renderColumnContainer(columnContainer as HTMLElement, columns);
}
}
/**
@ -310,8 +300,8 @@ export class GridRenderer {
* @returns New grid element ready for animation
*/
public createNavigationGrid(parentContainer: HTMLElement, columns: IColumnInfo[]): HTMLElement {
// Create grid structure without events (events rendered by EventRenderingService)
const newGrid = this.createOptimizedGridContainer(columns, []);
// Create grid structure (events are in columns, rendered by EventRenderingService)
const newGrid = this.createOptimizedGridContainer(columns);
// Position new grid for animation - NO transform here, let Animation API handle it
newGrid.style.position = 'absolute';