mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-16 08:16:15 +10:00
Update InfiniteCircularScroll component
This commit is contained in:
@@ -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);
|
||||
@@ -33,7 +33,7 @@
|
||||
'</div>'
|
||||
].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 );
|
||||
|
||||
Reference in New Issue
Block a user