Timeline supports lazy loading of events during moving / zooming in the timeline. This makes sense when event's loading is time-consuming. Events are loaded lazy when p:ajax with event="lazyload" is attached to the p:timeline tag. The event class TimelineLazyLoadEvent contains one or two time ranges the events should be loaded for (two times ranges occur when you zoom out the timeline).
Note: The "lazyload" listener is not invoked again when the visible time range (incl. some hidden ranges defined by preloadFactor) already has lazy loaded events.
Documentation<h:form id="form"> <p:growl id="growl" showSummary="true" showDetail="false"> <p:autoUpdate /> </p:growl> <div id="loadingText" style="font-weight:bold; margin:-5px 0 5px 0; visibility:hidden;">Loading ...</div> <p:timeline id="timeline" value="#{lazyTimelineView.model}" preloadFactor="#{lazyTimelineView.preloadFactor}" zoomMax="#{lazyTimelineView.zoomMax}" minHeight="170"> <p:ajax event="lazyload" update="@none" listener="#{lazyTimelineView.onLazyLoad}" onstart="$('#loadingText').css('visibility', 'visible')" oncomplete="$('#loadingText').css('visibility', 'hidden')"/> </p:timeline> <h:panelGrid columns="2" style="margin-top:15px"> <p:spinner id="spinner" value="#{lazyTimelineView.preloadFactor}" min="0" max="1" stepFactor="0.05"/> <p:commandButton value="Update Preload Factor" process="@this spinner" update="timeline" action="#{lazyTimelineView.clearTimeline}" style="margin-left:5px"/> </h:panelGrid> </h:form>
@Named @ViewScoped public class LazyTimelineView implements Serializable { private TimelineModel<String, ?> model; private float preloadFactor = 0; private long zoomMax; @PostConstruct protected void initialize() { // create empty model model = new TimelineModel<>(); // about five months in milliseconds for zoomMax // this can help to avoid a long loading of events when zooming out to wide time ranges zoomMax = 1000L * 60 * 60 * 24 * 31 * 5; } public TimelineModel<String, ?> getModel() { return model; } public void onLazyLoad(TimelineLazyLoadEvent e) { try { // simulate time-consuming loading before adding new events Thread.sleep((long) (1000 * Math.random() + 100)); } catch (InterruptedException ex) { // ignore } TimelineUpdater timelineUpdater = TimelineUpdater.getCurrentInstance(":form:timeline"); LocalDateTime startDate = e.getStartDateFirst(); // alias getStartDate() can be used too LocalDateTime endDate = e.getEndDateFirst(); // alias getEndDate() can be used too // fetch events for the first time range generateRandomEvents(startDate, endDate, timelineUpdater); if (e.hasTwoRanges()) { // zooming out ==> fetch events for the second time range generateRandomEvents(e.getStartDateSecond(), e.getEndDateSecond(), timelineUpdater); } } private void generateRandomEvents(LocalDateTime startDate, LocalDateTime endDate, TimelineUpdater timelineUpdater) { LocalDateTime curDate = startDate; Random rnd = new Random(); PrimitiveIterator.OfInt randomInts = rnd.ints(1, 99999).iterator(); while (curDate.isBefore(endDate)) { // create events in the given time range if (rnd.nextBoolean()) { // event with only one date model.add(TimelineEvent.<String>builder() .data("Event " + randomInts.nextInt()) .startDate(curDate) .build(), timelineUpdater); } else { // event with start and end dates model.add(TimelineEvent.<String>builder() .data("Event " + randomInts.nextInt()) .startDate(curDate) .endDate(curDate.plusHours(18)) .build(), timelineUpdater); } curDate = curDate.plusHours(24); } } public void clearTimeline() { // clear Timeline, so that it can be loaded again with a new preload factor model.clear(); } public void setPreloadFactor(float preloadFactor) { this.preloadFactor = preloadFactor; } public float getPreloadFactor() { return preloadFactor; } public long getZoomMax() { return zoomMax; } }