I encountered the same issue with that particular problem, which proved to be quite challenging due to the unconventional way the plugin constructs the calendar using tables and dynamically positioning events with absolute values for the top CSS property.
Fortunately, I was able to devise a versatile solution that functions admirably well. Firstly, I will present you with the code, followed by an explanation of its operation.
To address this issue, I utilized the eventAfterAllRender option in FullCalendar. Here is a live example.https://i.sstatic.net/ZoC5e.png
I made use of moment for time management and assumed that the ID of the FullCalendar HTML element is 'Calendar'.
eventAfterAllRender: function() {
// define static values, use these values to adjust event item height
var defaultItemHeight = 25;
var defaultEventItemHeight = 18;
// ...
// retrieve all rows and create a function to select a row based on a specific time
var rows = [];
$('div.fc-slats > table > tbody > tr[data-time]').each(function() {
rows.push($(this));
});
var rowIndex = 0;
var getRowElement = function(time) {
while (rowIndex < rows.length && moment(rows[rowIndex].attr('data-time'), ['HH:mm:ss']) <= time) {
rowIndex++;
}
var selectedIndex = rowIndex - 1;
return selectedIndex >= 0 ? rows[selectedIndex] : null;
};
// reposition events items and increase row height when necessary
$('div.fc-content-col > div.fc-event-container').each(function() { // iterate through week columns
var accumulator = 0;
var previousRowElement = null;
$(this).find('> a.fc-time-grid-event.fc-v-event.fc-event.fc-start.fc-end').each(function() { // iterate through events in column
// determine the current event time and its respective row
var currentEventTime = moment($(this).find('> div.fc-content > div.fc-time').attr('data-full'), ['h:mm A']);
var currentEventRowElement = getRowElement(currentEventTime);
// move down events if multiple in same row (using margin-top to avoid conflicts)
if (currentEventRowElement === previousRowElement) {
accumulator++;
$(this).css('margin-top', '+=' + (accumulator * defaultItemHeight).toString() + 'px');
var maxItemsOnRow = currentEventRowElement.attr('data-max-items') || 1;
if (accumulator >= maxItemsOnRow) {
currentEventRowElement.attr('data-max-items', accumulator + 1);
currentEventRowElement.css('height', '+=' + defaultItemHeight.toString() + 'px');
}
} else {
rowIndex = 0;
accumulator = 0;
}
// set default styles for event item and update previosRow
$(this).css('left', '0');
$(this).css('right', '7px');
$(this).css('height', defaultEventItemHeight.toString() + 'px');
$(this).css('margin-right', '0');
previousRowElement = currentEventRowElement;
});
});
$('#calendar').fullCalendar('option', 'aspectRatio', $('#calendar').fullCalendar('option', 'aspectRatio'));
}
How Does the Code Operate:
Initially, I located all tr elements representing the rows in my calendar, each containing its own timestamp attribute.
Subsequently, I iterated over each column, retrieving the event items within each one represented by anchor elements with date attributes such as data-full.
For each event, I determined its appropriate row position and adjusted it vertically using the margin-top property rather than the standard top property to prevent plugin conflicts.
In addition, I tracked the maximum number of events in a row to ensure proper height adjustments.
This outlines the primary functionality of the code. Feel free to inquire further if needed.