Add infinite scrolling to the timeline

refs #4190
This commit is contained in:
Johannes Meyer 2014-04-01 11:41:05 +02:00
parent 7440d61189
commit 80b4e3bf33
5 changed files with 129 additions and 125 deletions

View File

@ -66,9 +66,12 @@ class Monitoring_TimelineController extends ActionController
$timeline->setMinimumCircleWidth('0.3em'); $timeline->setMinimumCircleWidth('0.3em');
$timeline->setDisplayRange($displayRange); $timeline->setDisplayRange($displayRange);
$timeline->setForecastRange($forecastRange); $timeline->setForecastRange($forecastRange);
$timeline->setSession($this->getWindowSession('timeline', $this->getRequest()->getParam('extend') != 1)); $beingExtended = $this->getRequest()->getParam('extend') == 1;
$timeline->setSession($this->getWindowSession('timeline', !$beingExtended));
$this->view->timeline = $timeline; $this->view->timeline = $timeline;
$this->view->nextRange = $forecastRange;
$this->view->beingExtended = $beingExtended;
$this->view->intervalFormat = $this->getIntervalFormat(); $this->view->intervalFormat = $this->getIntervalFormat();
$oldBase = $timeline->getCalculationBase(false); $oldBase = $timeline->getCalculationBase(false);
$this->view->switchedContext = $oldBase !== null && $oldBase !== $timeline->getCalculationBase(true); $this->view->switchedContext = $oldBase !== null && $oldBase !== $timeline->getCalculationBase(true);

View File

@ -1,10 +1,12 @@
<?php <?php
use Icinga\Web\Url;
use Icinga\Util\Color; use Icinga\Util\Color;
$groupInfo = $timeline->getGroupInfo(); $groupInfo = $timeline->getGroupInfo();
$firstRow = true; $firstRow = !$beingExtended;
?> ?>
<?php if (!$beingExtended): ?>
<div class="controls"> <div class="controls">
<div style="margin: 1em;" class="dontprint"> <div style="margin: 1em;" class="dontprint">
<?= $intervalBox; ?> <?= $intervalBox; ?>
@ -20,6 +22,7 @@ $firstRow = true;
</div> </div>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<div class="timeline"> <div class="timeline">
<?php endif ?>
<?php foreach ($timeline as $timeInfo): ?> <?php foreach ($timeline as $timeInfo): ?>
<div class="timeframe"> <div class="timeframe">
<span> <span>
@ -76,5 +79,19 @@ $extrapolatedCircleWidth = $timeline->getExtrapolatedCircleWidth($timeInfo[1][$g
</div> </div>
<?php $firstRow = false; ?> <?php $firstRow = false; ?>
<?php endforeach ?> <?php endforeach ?>
<a id="end" href="<?= Url::fromRequest()->getUrlWithout(
array(
'raw_timestamp<',
'raw_timestamp>'
)
)->overwriteParams(
array(
'start' => $nextRange->getStart()->getTimestamp(),
'end' => $nextRange->getEnd()->getTimestamp(),
'extend' => 1
)
); ?>"></a>
<?php if (!$beingExtended): ?>
</div> </div>
</div> </div>
<?php endif ?>

View File

@ -0,0 +1,83 @@
(function(Icinga) {
var Monitoring = function(module) {
/**
* The Icinga.Module instance
*/
this.module = module;
/**
* The observer used to handle the timeline's infinite loading
*/
this.scrollCheckTimer = null;
/**
* Whether to skip the timeline's scroll-check
*/
this.skipScrollCheck = false;
this.initialize();
};
Monitoring.prototype = {
initialize: function()
{
this.module.on('rendered', this.enableScrollCheck);
this.module.icinga.logger.debug('Monitoring module loaded');
},
/**
* Enable the timeline's scroll-check
*/
enableScrollCheck: function()
{
/**
* Re-enable the scroll-check in case the timeline has just been extended
*/
if (this.skipScrollCheck) {
this.skipScrollCheck = false;
}
/**
* Prepare the timer to handle the timeline's infinite loading
*/
if ($('div.timeline').length) {
if (this.scrollCheckTimer === null) {
this.scrollCheckTimer = this.module.icinga.timer.register(
this.checkTimelinePosition,
this,
800
);
this.module.icinga.logger.debug('Enabled timeline scroll-check');
}
}
},
/**
* Check whether the user scrolled to the end of the timeline
*/
checkTimelinePosition: function()
{
if (!$('div.timeline').length) {
this.module.icinga.timer.unregister(this.scrollCheckTimer);
this.scrollCheckTimer = null;
this.module.icinga.logger.debug('Disabled timeline scroll-check');
} else if (!this.skipScrollCheck && this.module.icinga.utils.isVisible('#end')) {
this.skipScrollCheck = true;
this.module.icinga.loader.loadUrl(
$('#end').remove().attr('href'),
$('div.timeline'),
undefined,
undefined,
'append'
);
}
}
},
Icinga.availableModules.monitoring = Monitoring;
}(Icinga));

View File

@ -1,123 +0,0 @@
/*global Icinga:false, document: false, define:false require:false base_url:false console:false */
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
/**
* Provides infinite scrolling functionality for the monitoring timeline
*/
define(['jquery', 'logging'], function($, log) {
'use strict';
return function() {
this.scrolled = false;
this.ignoreScroll = false;
/**
* Scroll-event to register that the user has scrolled
*/
this.registerScroll = function() {
if (!this.ignoreScroll) {
this.scrolled = true;
}
};
/**
* Check whether the user has scrolled to the timeline's end
* and initiate the infinite scrolling if this is the case
*/
this.checkScroll = function() {
if (this.scrolled) {
if (this.isScrolledIntoView('#TimelineEnd')) {
this.ignoreScroll = true;
this.loadTimeline.bind(this)();
}
this.scrolled = false;
}
if ($('[name="Timeline"]').length > 0) {
setTimeout(this.checkScroll.bind(this), 1000);
}
};
/**
* Return whether the given element is visible in the users view
*
* Borrowed from: http://stackoverflow.com/q/487073
*
* @param {selector} element The element to check
* @returns {Boolean}
*/
this.isScrolledIntoView = function(element) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(element).offset().top;
var elemBottom = elemTop + $(element).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
&& (elemBottom <= docViewBottom) && (elemTop >= docViewTop));
};
/**
* Return the current base url
*
* @returns {String}
*/
this.getBaseUrl = function() {
var protocol = window.location.protocol;
var host = window.location.host;
var base = window.base_url;
return protocol + "//" + host + base;
}
/**
* Initiate the AJAX timeline request
*/
this.loadTimeline = function() {
var query = {};
var base_url = this.getBaseUrl();
$.get(base_url + '/monitoring/timeline/extend', query, this.extendTimeline.bind(this));
};
/**
* Process the AJAX timeline response
*
* @param {string} html
*/
this.extendTimeline = function(html) {
this.ignoreScroll = false;
// TODO: Implement the processing logic
}
// The scroll-logic is split into two functions to avoid wasting too much
// performance by checking whether the user reached the end of the timeline
$(window).scroll(this.registerScroll.bind(this));
setTimeout(this.checkScroll.bind(this), 1000);
};
});

View File

@ -53,6 +53,30 @@
return hours + ':' + minutes + ':' + seconds; return hours + ':' + minutes + ':' + seconds;
}, },
/**
* Return whether the given element is visible in the users view
*
* Borrowed from: http://stackoverflow.com/q/487073
*
* @param {selector} element The element to check
* @returns {Boolean}
*/
isVisible: function(element)
{
var $element = $(element);
if (!$element.length) {
return false;
}
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $element.offset().top;
var elemBottom = elemTop + $element.height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
&& (elemBottom <= docViewBottom) && (elemTop >= docViewTop));
},
getUrlHelper: function () { getUrlHelper: function () {
if (this.urlHelper === null) { if (this.urlHelper === null) {
this.urlHelper = document.createElement('a'); this.urlHelper = document.createElement('a');