| Issue 2210: | Faster render when navigating thousands of events | |
| 1 person starred this issue and may be notified of changes. | Back to list |
I am using fullCalendar to display daily historical events for up to 10 years of history. When I try to navigate to another month, there is a noticeable delay of 3-4 seconds.
I tried implementing an eventSource function with a binary search, and I was able to get that delay down to less than a second. I'm hoping this can be added to fullCalendar itself so that others may not have to do what I did (luckily, the binary search was already written for some other feature of the app).
Here's the code for the binary search I'm using and the eventSource function that uses it.
// All the datetimes I want to display an event for
var all_datetimes = [ '2014-01-01T00:00:00Z', '2014-01-02T00:00:00Z' ];
// The binary search. Returns the index of the closest datetime to
// the given query
var find_nearest_date = function ( all_datetimes, query ) {
var query_dt = moment( query );
var first = 0;
var last = all_datetimes.length;
var pivot;
SEARCH:
while ( first <= last ) {
pivot = Math.floor( ( last - first ) / 2 ) + first;
var pivot_dt = moment( all_datetimes[ pivot ] );
// Special-case the same day
// We would prefer to be on the same day if possible, no matter if it
// is further away from yesterday's or tomorrow's value
if ( pivot - first <= 2 && !query_dt.isSame( pivot_dt, 'day' ) ) {
// If we're not on the same day yet, try to get there
DAY:
while ( first <= last ) {
pivot = first;
pivot_dt = moment( all_datetimes[ first ] );
if ( query_dt.isSame( pivot_dt, 'day' ) ) {
break SEARCH;
}
else if ( query_dt.isBefore( pivot_dt ) ) {
// But do not go past the date!
break SEARCH;
}
first++;
}
}
else if ( query_dt.isAfter( pivot_dt ) ) {
first = pivot + 1;
}
else if ( query_dt.isBefore( pivot_dt ) ) {
last = pivot - 1;
}
else {
break;
}
}
return pivot;
};
// The eventSource function
var find_calendar_events = function ( start, end, tz, cb ) {
if ( all_events.length == 0 ) {
cb( [] );
return;
}
var start_idx = find_nearest_date( all_datetimes, start );
var end_idx = find_nearest_date( all_datetimes, end );
var dt;
var events = [];
while ( start_idx < end_idx ) {
dt = all_datetimes[ start_idx ];
events.push(
{
start: dt,
title: "Hello"
}
);
start_idx++;
}
cb( events );
};
Jul 17, 2014
I am loading thousands of datetimes into Javascript because I can, because it was easy. A small transformation, above, turns the datetime strings into the events that fullCalendar expects, but until then they are simply ISO8601 datetimes in UTC (a 20-character basic-ASCII string, with JS overhead making a still-insignificant amount of memory). Having all the datetimes allows me to rapidly search through them on the client, when, for example, the user doesn't know exactly when something happened, but they know nearly when it happened. The find_nearest_date function was written for that purpose: The user can type in a date and I'll find the nearest event, with emphasis on finding one on the exact date even if one on another date is technically closer. The data is time series data, market data, so the user doesn't care about searching the event data (all events have the same data, just different values which are not usefully searchable), so to get the event body requires another request. The user does care about rapidly searching through the dates/times available, so I preload that data on the client. All my callback above does is fake the behavior of an AJAX request without the unknown quantity of how long the database request will take. Given already-sorted data (a prereq for binary search), it finds the requested data faster than the existing method built-in to the calendar. It probably doesn't start being noticeably faster until about 100 events (no actual benchmarking or performance testing was performed here), but it scales much, much better than a linear search (an assumption, I never looked at how the calendar was picking events to display when using the local event array). In theory, my needs could also have been served by a datepicker control, without loading any of the data into a calendar-like view, but I like showing the user which dates have data, and the datepicker controls I was looking at did not have that feature. The new browser wars have made amazingly fast and intelligent clients, it'd be a shame not to use that power.
Jul 18, 2014
I was going to ask why this simply can't be done a custom event source function, but I see that you already acknowledged that fact and wanted to share this code for others who must store lots of event data on the client. Thanks for this code, but I'm fairly certain this is not too common of a usecase, so I won't bake it into the core. I'll close this ticket, because I don't see anyone taking action on this in the near future, but people will be able to find this ticket via googling and such, and if enough interest is generated, ill reopen it and maybe it can be made into a more official add-on of some sort. thanks
Status:
Done
|
|
| ► Sign in to add a comment |
Labels: Type-Feature