From ef982cbb27249407735ef71d3300550e39f8bb14 Mon Sep 17 00:00:00 2001 From: denz Date: Wed, 15 Jul 2015 16:34:20 +0900 Subject: [PATCH] Update InfiniteCircularScroll component --- .../InfiniteCircularScroll.js | 351 ++++++++++-------- .../features/timeline/timeline.directive.js | 12 +- 2 files changed, 198 insertions(+), 165 deletions(-) diff --git a/web/src/main/webapp/components/infiniteCircularScroll/InfiniteCircularScroll.js b/web/src/main/webapp/components/infiniteCircularScroll/InfiniteCircularScroll.js index 2e1cead7d..2a1037d0c 100644 --- a/web/src/main/webapp/components/infiniteCircularScroll/InfiniteCircularScroll.js +++ b/web/src/main/webapp/components/infiniteCircularScroll/InfiniteCircularScroll.js @@ -1,170 +1,203 @@ (function(window, $) { 'use strict'; var ROW_SPARE_COUNT = 8; - window.InfiniteCircularScroll = $.Class({ - $init: function(options) { - this.option(options); - this._init(); - this._initVar(); - this._initEvent(); - }, - _init: function() { - this.$wrapper = this.option("wrapper"); - this._threshold = this.option("elementHeight") * (ROW_SPARE_COUNT / 4); // 2 * elementHeight - this._previousTop = 0; - this._previousTime = -1; - this._selectedRow = -1; - }, - _initVar: function() { - this._elementArray = []; - this._elementArrayStartIndex = 0; - this._elementArrayEndIndex = 0; - this._elementArraySize = 0; - this._previousTop = 0; - }, - _initEvent: function() { - var self = this; - this.option("scroller").on("scroll", function(event) { - self._scrollEventHandler(event, $(this)); - }); - }, - _calculateElementStartCount: function() { - var temp = parseInt( this._viewAreaHeight / this.option("elementHeight") ) + ROW_SPARE_COUNT; - this._elementArraySize = temp > this._source.length ? this._source.length : temp; - this._elementArrayEndIndex = this._elementArraySize - 1; - }, - _initElementArray: function() { - this.$wrapper.empty(); - for( var i = 0 ; i < this._elementArraySize ; i++ ) { - var $element = $(this.option("template")); - this._renderElement($element, i); - this._elementArray.push($element); - this.$wrapper.append($element); - } - }, - _renderElement: function($element, index) { - this._renderFunc.call( this, $element, index, this._source[index] ); - $element.attr("data-index", index).css("top", (index * this.option("elementHeight")) + "px" ); - }, - _getDataIndex: function(index) { - return parseInt(this._elementArray[index].attr("data-index")); - }, - _getTopByIndex: function(index) { - return parseInt(this._elementArray[index].css("top")); - }, - _getNextArrayIndex: function(index) { - return index + 1 >= this._elementArraySize ? 0 : index + 1; - }, - _getPreviousArrayIndex: function(index) { - return ( index - 1 < 0 ? this._elementArraySize : index ) - 1; - }, - _scrollEventHandler: function(event, $targetElement) { - var top = $targetElement.scrollTop(); - var mTime = new Date().valueOf(); - if ( top == this._previousTop ) return; - - var bIsDown = top - this._previousTop > 0; - if ( bIsDown ) { // scroll down - this._scrollDown(top, this._getTopByIndex(this._elementArrayStartIndex)); - } else { // scroll up - this._scrollUp(top, this._getTopByIndex(this._elementArrayEndIndex)); - } - this._previousTop = top; - this._previousTime = mTime; - }, - _scrollDown: function( top, firstElementTop ) { - var exceededDistance = top - firstElementTop - this._threshold; - if ( exceededDistance >= 0 ) { - var sourceLastIndex = this._getDataIndex(this._elementArrayEndIndex); - var nextIndex = this._elementArrayStartIndex; - var nextIndexStep = parseInt(exceededDistance / this.option("elementHeight")); - - for( var i = 0 ; i < nextIndexStep ; i++ ) { - var sourceIndex = sourceLastIndex + i + 1; - if ( sourceIndex >= this._source.length ) { - break; - } - if ( nextIndexStep - i <= this._elementArraySize * 2 ) { - this._renderElement(this._elementArray[nextIndex], sourceIndex); - } - nextIndex = this._getNextArrayIndex(nextIndex); - } - this._elementArrayStartIndex = nextIndex; - this._elementArrayEndIndex = this._getPreviousArrayIndex(nextIndex); - } - }, - _scrollUp: function( top, lastElementTop ) { - var exceededDistance = lastElementTop + this.option("elementHeight") - top - this._viewAreaHeight - this._threshold; - if ( exceededDistance >= 0 ) { - var sourceFirstIndex = this._getDataIndex(this._elementArrayStartIndex); - var previousIndex = this._elementArrayEndIndex; - var previousIndexStep = parseInt(exceededDistance / this.option("elementHeight")); - - for( var i = 0 ; i < previousIndexStep ; i++ ) { - var sourceIndex = sourceFirstIndex - (i + 1); - if ( sourceIndex < 0 ) { - break; - } - if ( previousIndexStep - i <= this._elementArraySize * 2 ) { - this._renderElement(this._elementArray[previousIndex], sourceIndex); - } - previousIndex = this._getPreviousArrayIndex(previousIndex); - } - this._elementArrayEndIndex = previousIndex; - this._elementArrayStartIndex = this._getNextArrayIndex(previousIndex); - } - }, - setSource: function( source ) { - this._source= source; - return this; - }, - setViewAreaHeight: function( viewAreaHeight ) { - this._viewAreaHeight = viewAreaHeight; - return this; - }, - setRenderFunc: function( fnRender ) { - this._renderFunc = fnRender; - return this; - }, - reset: function() { - this._initVar(); - this._calculateElementStartCount(); - this._initElementArray(); - return this; - }, - getContentsAreaHeight: function() { - return this.option("elementHeight") * this._source.length; - }, - destroy: function() { - this.$wrapper.parent().off("scroll"); - }, - resize: function( resizedViewAreaHeight ) { - var currentRow = parseInt(this.option("scroller").scrollTop() / this.option("elementHeight")); - this.setViewAreaHeight(resizedViewAreaHeight); + + var ICS = function( options ){ + this.options = options; + this._init(); + this._initOption(); + this._initVar(); + this._initEvent(); + this._renderScrollArea(); + }; + ICS.prototype._init = function() { + this.$wrapper = this.options.wrapper; + this._threshold = this.options.elementHeight * (ROW_SPARE_COUNT / 4); // 2 * elementHeight + }; + ICS.prototype._initOption = function() { + this._viewAreaHeight = this.options.viewAreaHeight; + this._renderFunc = this.options.renderFunc || function() {}; + this._source = this.options.source; + this._previousTop = 0; + this._previousTime = -1; + this._selectedRow = -1; + } + ICS.prototype._initVar = function() { + this._elementArray = []; + this._elementArrayStartIndex = 0; + this._elementArrayEndIndex = 0; + this._elementArraySize = 0; + this._previousTop = 0; + }; + ICS.prototype._initEvent = function() { + var self = this; + this.options.scroller.on("scroll", function(event) { + self._scrollEventHandler(event, $(this)); + }); + }, + ICS.prototype._isDefined = function( v ) { + return typeof v != "undefined"; + }; + ICS.prototype._renderScrollArea = function() { + if ( this._isDefined( this._source ) && this._isDefined( this.options.viewAreaHeight ) ) { this.reset(); - this.moveByRow( currentRow ); - }, - moveByRow: function( row ) { // from 0 - var self = this; - setTimeout(function() { - self.option("scroller").scrollTop(row * self.option("elementHeight")); - },0); - }, - searchRow: function( from, to, func) { - var resultRow = -1; - to = (to == -1 ? this._source.length : to); - for( var i = from ; i < to ; i++ ) { - if ( func(this._source[i]) ) { - resultRow = i; + } + }, + ICS.prototype._calculateElementStartCount = function() { + var temp = parseInt( this._viewAreaHeight / this.options.elementHeight ) + ROW_SPARE_COUNT; + this._elementArraySize = temp > this._source.length ? this._source.length : temp; + this._elementArrayEndIndex = this._elementArraySize - 1; + this.$wrapper.height( this._source.length * this.options.elementHeight ); + }; + ICS.prototype._initElementArray = function() { + this.$wrapper.empty(); + for( var i = 0 ; i < this._elementArraySize ; i++ ) { + var $element = $(this.options.template); + this._renderElement($element, i); + this._elementArray.push($element); + this.$wrapper.append($element); + } + }; + ICS.prototype._renderElement = function($element, index) { + this._renderFunc.call( this, $element, index, this._source[index] ); + $element.attr("data-index", index).css("top", (index * this.options.elementHeight) + "px" ); + }; + ICS.prototype._getDataIndex = function(index) { + return parseInt(this._elementArray[index].attr("data-index")); + }; + ICS.prototype._getTopByIndex = function(index) { + return parseInt(this._elementArray[index].css("top")); + }; + ICS.prototype._getNextArrayIndex = function(index) { + return index + 1 >= this._elementArraySize ? 0 : index + 1; + }; + ICS.prototype._getPreviousArrayIndex = function(index) { + return ( index - 1 < 0 ? this._elementArraySize : index ) - 1; + }; + ICS.prototype._scrollEventHandler = function(event, $targetElement) { + var top = $targetElement.scrollTop(); + var mTime = new Date().valueOf(); + if ( top == this._previousTop ) return; + + var bIsDown = top - this._previousTop > 0; + if ( bIsDown ) { // scroll down + this._scrollDown(top, this._getTopByIndex(this._elementArrayStartIndex)); + } else { // scroll up + this._scrollUp(top, this._getTopByIndex(this._elementArrayEndIndex)); + } + this._previousTop = top; + this._previousTime = mTime; + }; + ICS.prototype._scrollDown = function( top, firstElementTop ) { + var exceededDistance = top - firstElementTop - this._threshold; + if ( exceededDistance >= 0 ) { + var sourceLastIndex = this._getDataIndex(this._elementArrayEndIndex); + var nextIndex = this._elementArrayStartIndex; + var nextIndexStep = parseInt(exceededDistance / this.options.elementHeight); + + for( var i = 0 ; i < nextIndexStep ; i++ ) { + var sourceIndex = sourceLastIndex + i + 1; + if ( sourceIndex >= this._source.length ) { break; } + if ( nextIndexStep - i <= this._elementArraySize * 2 ) { + this._renderElement(this._elementArray[nextIndex], sourceIndex); + } + nextIndex = this._getNextArrayIndex(nextIndex); } - return resultRow; - }, - setSelectedRow: function(row, func) { + this._elementArrayStartIndex = nextIndex; + this._elementArrayEndIndex = this._getPreviousArrayIndex(nextIndex); + } + }, + ICS.prototype._scrollUp = function( top, lastElementTop ) { + var exceededDistance = lastElementTop + this.options.elementHeight - top - this._viewAreaHeight - this._threshold; + if ( exceededDistance >= 0 ) { + var sourceFirstIndex = this._getDataIndex(this._elementArrayStartIndex); + var previousIndex = this._elementArrayEndIndex; + var previousIndexStep = parseInt(exceededDistance / this.options.elementHeight); + + for( var i = 0 ; i < previousIndexStep ; i++ ) { + var sourceIndex = sourceFirstIndex - (i + 1); + if ( sourceIndex < 0 ) { + break; + } + if ( previousIndexStep - i <= this._elementArraySize * 2 ) { + this._renderElement(this._elementArray[previousIndex], sourceIndex); + } + previousIndex = this._getPreviousArrayIndex(previousIndex); + } + this._elementArrayEndIndex = previousIndex; + this._elementArrayStartIndex = this._getNextArrayIndex(previousIndex); + } + }; + ICS.prototype.source = function() { + if ( arguments.length == 1 ) { + this.options.source = arguments[0]; + return this; + } else { + return this._source; + } + }; + ICS.prototype.viewAreaHeight = function() { + if ( arguments.length == 1 ) { + this.options.viewAreaHeight = arguments[0]; + return this; + } else { + return this._viewAreaHeight; + } + }; + ICS.prototype.renderFunc = function() { + if ( arguments.length == 1 ) { + this.options.renderFunc = arguments[0]; + return this; + } else { + return this._renderFunc; + } + }; + ICS.prototype.reset = function() { + this._initOption(); + this._initVar(); + this._calculateElementStartCount(); + this._initElementArray(); + return this; + }; + ICS.prototype.contentsAreaHeight = function() { + return this.options.elementHeight * this._source.length; + }; + ICS.prototype.destroy = function() { + this.options.scroller.off("scroll"); + }; + ICS.prototype.resize = function( resizedViewAreaHeight ) { + var currentRow = parseInt(this.options.scroller.scrollTop() / this.options.elementHeight); + this.setViewAreaHeight(resizedViewAreaHeight); + this.reset(); + this.moveByRow( currentRow ); + }; + ICS.prototype.moveByRow = function( row ) { // from 0 + var self = this; + setTimeout(function() { + self.options.scroller.scrollTop(row * self.options.elementHeight); + },0); + }; + ICS.prototype.searchRow = function( from, to, func) { + var resultRow = -1; + to = (to == -1 ? this._source.length : to); + for( var i = from ; i < to ; i++ ) { + if ( func(this._source[i]) ) { + resultRow = i; + break; + } + } + return resultRow; + }; + ICS.prototype.selectedRow = function(row, func) { + if ( arguments.length == 0 ) { + return this._selectedRow; + } else { func.call(this, row); this._selectedRow = row; return this; } - }); -})(window, jQuery); + }; + window.InfiniteCircularScroll = ICS; +})(window, jQuery); \ No newline at end of file diff --git a/web/src/main/webapp/features/timeline/timeline.directive.js b/web/src/main/webapp/features/timeline/timeline.directive.js index 76eae42ec..513d1823e 100644 --- a/web/src/main/webapp/features/timeline/timeline.directive.js +++ b/web/src/main/webapp/features/timeline/timeline.directive.js @@ -33,7 +33,7 @@ '' ].join("") }); - icscroller.setRenderFunc(function( $element, index, elementData ) { + icscroller.renderFunc(function( $element, index, elementData ) { var marginLeft = getMarginLeft(elementData); $element[ index == this._selectedRow ? "addClass" : "removeClass" ]("timeline-bar-selected") .find("div.clickable-bar").css({ @@ -66,11 +66,11 @@ scope.key = transactionDetail.callStackIndex; scope.barRatio = 1000 / (transactionDetail.callStack[0][scope.key.end] - transactionDetail.callStack[0][scope.key.begin]); scope.newCallStacks = filterCallStacks(); - icscroller.setSource( scope.newCallStacks ) - .setViewAreaHeight( $(element).parentsUntil("div.wrapper").height() - 70 ) // 70 is header area height - .setSelectedRow(-1, angular.noop) + icscroller.source( scope.newCallStacks ) + .viewAreaHeight( $(element).parentsUntil("div.wrapper").height() - 70 ) // 70 is header area height + .selectedRow(-1, angular.noop) .reset(); - scope.maxHeight = icscroller.getContentsAreaHeight(); + scope.maxHeight = icscroller.contentsAreaHeight(); searchStartIndex = 0; scope.$digest(); @@ -148,7 +148,7 @@ }); }; searchSuccess = function(resultIndex, message) { - icscroller.setSelectedRow( resultIndex, function(newIndex) { + icscroller.selectedRow( resultIndex, function(newIndex) { this.$wrapper.find("div[data-index=" + this._selectedRow + "]").removeClass("timeline-bar-selected"); this.$wrapper.find("div[data-index=" + newIndex + "]").addClass("timeline-bar-selected"); }).moveByRow( resultIndex );