jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
<style>
.track_vertical
{
position:absolute;
top:0;
bottom:0;
margin:auto;
right:10px;
background:#231f1f;
width:3px;
z-index: 9999;
}
.thumb_vertical
{
position:absolute;
background:#7C2845;
width:5px;
top:0;
left:-1px;
cursor: url('../img/grab.cur'),move;
}
.track_horizontal
{
position: absolute;
left: 0;
right: 0;
bottom: 10px;
height: 3px;
margin: auto;
background: #231f1f;
z-index: 9999;
}
.thumb_horizontal
{
position:absolute;
background:#7C2845;
height:5px;
left:0;
top:-1px;
cursor: url('../img/grab.cur'),move;
}
</style>
<div class="viewport" style="background-color:blue;position:relative;overflow:hidden;width:500px;height:300px;">
<div id="unique_1" style="position: absolute;top: 0;left: 0;width:900px;height:900px;" class="scroller">
<img id="fake_target" style="position: relative;width:900px;height:900px;" src="http://akhmetelitheatre.ge/cms/scrollbar/img/1.jpg" />
</div>
</div>
var _scrollBarInstances = [],
filterArray = function(a,pop) {
return a.filter(function(i) {return pop.indexOf(i) < 0;});
},
returnDim = function(x,y)
{
var arr = [];
if(x){arr.push(x)}
if(y){arr.push(y)}
return arr;
},
_gd_activeAnimation = null,
animatedProperty = '-webkit-transform',
style = { horizontalLow : 'width', verticalLow : 'height',horizontalCap : 'Width',verticalCap : 'Height',horizontalXY : 'X',verticalXY : 'Y' },
frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { return window.setTimeout(callback, 1000 / 60);},
stopFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame || function (callback) { window.clearTimeout(callback);};
function mouseDragEvents()
{
var mousedown = false,
target,
firstTarget,
targetInstance,
targetDim,
dimLength = 0,
unique = {},
start = {},
move = {},
end = {},
change = {},
delta = {},
startTime,
endTime,
speed,
isThumb = -1,
ratio = 1,
inverseDim,
inverseDimEl,
ThumbX,
ThumbY;
/** Attach events **/
//window.addEventListener("mousedown", MouseDown, false);// IE9, Chrome, Safari, Opera
//window.addEventListener("mouseup", MouseUp, false);// IE9, Chrome, Safari, Opera
//window.addEventListener("mousemove", MouseMove, false);// IE9, Chrome, Safari, Opera
/** Function in work **/
//MouseUp(mouseEvent('mouseup', 0, 0, 0, 0));
// setTimeout(function(){
// MouseMove(mouseEvent('mousemove', -5, -5, -5, -5));
// MouseMove(mouseEvent('mousemove', -10, -10, -10, -10));
// MouseMove(mouseEvent('mousemove', -15, -15, -15, -15));
// MouseMove(mouseEvent('mousemove', -20, -20, -20, -20));
// MouseMove(mouseEvent('mousemove', -25, -25, -25, -25));
// MouseMove(mouseEvent('mousemove', -30, -30, -30, -30));
// MouseMove(mouseEvent('mousemove', -35, -35, -35, -35));
// MouseMove(mouseEvent('mousemove', -40, -40, -40, -40));
// MouseMove(mouseEvent('mousemove', -45, -45, -45, -45));
// },200);
//
// setTimeout(function(){
// MouseUp(mouseEvent('mouseup', -50, -50, -50, -50));
// },500);
this.MouseDown = function(e)
{
e.preventDefault();
e.stopPropagation();
target = document.getElementById('fake_target');
startTime = e.timeStamp;
firstTarget = target;
while(!target.hasAttribute('gd_scroll')){ target = target.parentNode; }
for(var i = 0,l = _scrollBarInstances.length;i<l;++i){ if(target === _scrollBarInstances[i].viewport.el){ targetInstance = _scrollBarInstances[i]; } }
if(targetInstance !== null)
{
if(targetInstance.thumb)
{
ThumbX = targetInstance.thumb['horizontal'] ? targetInstance.thumb['horizontal'].el : null;
ThumbY = targetInstance.thumb['vertical'] ? targetInstance.thumb['vertical'].el : null;
}
isThumb = (ThumbX === firstTarget || ThumbY === firstTarget) ? 1 : -1;
ratio = ThumbY == firstTarget ? targetInstance.ratio['vertical'] : ThumbX == firstTarget ? targetInstance.ratio['horizontal'] : 1;
targetDim = returnDim(targetInstance.dimension.horizontal,targetInstance.dimension.vertical);
dimLength = targetDim.length;
if(dimLength > 0){ targetInstance.viewport.el.setAttribute('dragging','true') }
for(var k = 0; k < dimLength; ++k)
{
start[''+targetDim[k]+''] = unique[''+targetDim[k]+''] = e['page'+style[''+targetDim[k]+'XY']+''];
}
mousedown = true;
}
}
this.MouseDownFree = function(e)
{
e.preventDefault();
e.stopPropagation();
target = document.getElementById('fake_target');
startTime = e.timeStamp;
firstTarget = target;
while(!target.hasAttribute('gd_scroll')){ target = target.parentNode; }
}
this.MouseMove = function(e)
{
if(mousedown)
{
for(var k = 0; k < dimLength; ++k)
{
inverseDim = filterArray(targetDim,targetDim[k])[0];
if(targetInstance.thumb)
{
inverseDimEl = targetInstance.thumb[''+inverseDim+''] ? targetInstance.thumb[''+inverseDim+''].el : null;
}
else
{
inverseDimEl = null;
}
move[''+targetDim[k]+''] = e['page'+style[''+targetDim[k]+'XY']+''];
delta[''+targetDim[k]+''] = isThumb*((start[''+targetDim[k]+'']-move[''+targetDim[k]+''])/Math.abs(start[''+targetDim[k]+'']-move[''+targetDim[k]+'']));
change[''+targetDim[k]+''] = inverseDimEl == firstTarget ? 0 : Math.abs(start[''+targetDim[k]+'']-move[''+targetDim[k]+''])/ratio;
start[''+targetDim[k]+''] = e['page'+style[''+targetDim[k]+'XY']+''];
if(!delta[''+targetDim[k]+'']){ delta[''+targetDim[k]+''] = 1 };
}
new animateScroll(targetInstance.position.scroller,targetInstance.position.thumb,targetInstance.options.easing,
targetInstance.Min,targetInstance.Max,targetInstance.ratio,targetInstance.scroller.el.style,
targetInstance.thumb.horizontal.el.style,
targetInstance.thumb.vertical.el.style,change,delta,true);
}
}
this.MouseUp = function(e)
{
endTime = e.timeStamp;
for(var k = 0; k < dimLength; ++k)
{
inverseDim = filterArray(targetDim,targetDim[k])[0];
if(targetInstance.thumb)
{
inverseDimEl = targetInstance.thumb[''+inverseDim+''] ? targetInstance.thumb[''+inverseDim+''].el : null;
}
else
{
inverseDimEl = null;
}
end[''+targetDim[k]+''] = e['page'+style[''+targetDim[k]+'XY']+''];
change[''+targetDim[k]+''] = Math.abs(end[''+targetDim[k]+'']-unique[''+targetDim[k]+'']);
speed = change[''+targetDim[k]+'']/(endTime-startTime);
if(speed < 0.3){ speed = 0 }
change[''+targetDim[k]+''] = inverseDimEl == firstTarget ? 0 : change[''+targetDim[k]+'']*speed;
}
new animateScroll(targetInstance.position.scroller,targetInstance.position.thumb,targetInstance.options.easing,
targetInstance.Min,targetInstance.Max,targetInstance.ratio,targetInstance.scroller.el.style,
targetInstance.thumb.horizontal.el.style,
targetInstance.thumb.vertical.el.style,change,delta);
mousedown = false;
if(dimLength > 0){ targetInstance.viewport.el.removeAttribute('dragging') }
}
}
function scrollBar(scroller,options) {
var self = this;
/** Define default options **/
self.options =
{
mouseWheel:true,
mouseWheelSpeed:200,
duration:0.35,
trackSize:{vertical:'96%',horizontal:'96%'},
thumbSize:{vertical:null,horizontal:null},
visibleScrollbars:true,
Min:{ vertical:null,horizontal:null},
Max:{ vertical:null,horizontal:null},
enable:{horizontal:true,vertical:true},
/** in easing c = changeInValue,t = time(percent of animation complete),s = start value**/
easing:
{
easeOutSine: function(c,t,s){ return c*Math.sin(t * (Math.PI / 2)) + s },
easeOutQuad: function(c,t,s){ return c*((t=t-1)*t*t + 1) + s },
easeOutQuart: function(c,t,s){ return c*((t=t-1)*t*t*t + 1) + s },
easeOutQuint: function(c,t,s){ return c*((t=t-1)*t*t*t*t + 1) + s },
easeOutCirc: function(c,t,s){ return c*Math.sqrt(1 - (t=t-1)*t) + s }
}
};
/** Extend options **/
for ( var j in options ) {
self.options[j] = options[j];
}
/** Initialize new Instance **/
this.init = function()
{
iniContainer();
_scrollBarInstances.push(self);
}
/** Define properties depending on the container **/
function iniContainer()
{
/** scroller/viewport el's **/
self.scroller = {};
self.scroller.el = typeof scroller === 'string' ? document.querySelector(scroller) : scroller;
self.viewport = {};
self.viewport.el = self.scroller.el.parentNode;
self.viewport.el.setAttribute('gd_scroll','true');
/** property controller **/
self.animatedProperty = {};
/** position controller **/
self.position = { scroller: {} };
/** Min/Max object **/
self.Min = {};
self.Max = {};
/** update contaienr options, create/update scrollbars**/
self.update();
//console.log(self);
}
/** initialize Scrollbar when needed **/
function iniScrollbar()
{
if(self.dimension.horizontal || self.dimension.vertical)
{
self.track = self.track ? self.track : {};
self.thumb = self.thumb ? self.thumb : {};
self.ratio = self.ratio ? self.ratio : {};
self.position.thumb = self.position.thumb ? self.position.thumb : {};
for ( var k in self.dimension )
{
if(self.dimension[''+k+''] !== false)
{
_gd_dim = self.dimension[''+k+''];
self.track[''+_gd_dim+''] = self.track[''+_gd_dim+''] ? self.track[''+_gd_dim+''] : {};
self.thumb[''+_gd_dim+''] = self.thumb[''+_gd_dim+''] ? self.thumb[''+_gd_dim+''] : {};
self.track[''+_gd_dim+''].el = self.track[''+_gd_dim+''].el ? self.track[''+_gd_dim+''].el : document.createElement('div');
self.thumb[''+_gd_dim+''].el = self.thumb[''+_gd_dim+''].el ? self.thumb[''+_gd_dim+''].el : document.createElement('div');
if(self.track[''+_gd_dim+''].el.parentNode !== self.viewport)
{
self.track[''+_gd_dim+''].el.appendChild(self.thumb[''+_gd_dim+''].el);
self.viewport.el.appendChild(self.track[''+_gd_dim+''].el);
self.track[''+_gd_dim+''].el.setAttribute('class','track_'+_gd_dim+'');
self.thumb[''+_gd_dim+''].el.setAttribute('class','thumb_'+_gd_dim+'');
}
self.track[''+_gd_dim+''].styleSize = self.options.trackSize[''+_gd_dim+''];
self.thumb[''+_gd_dim+''].styleSize =
self.options.thumbSize[''+_gd_dim+''] ? self.options.thumbSize[''+_gd_dim+''] : self.viewport[''+style[''+_gd_dim+'Low']+'']/self.scroller[''+style[''+_gd_dim+'Low']+'']*100+'%';
self.track[''+_gd_dim+''].el.style[''+style[''+_gd_dim+'Low']+''] = self.track[''+_gd_dim+''].styleSize;
self.thumb[''+_gd_dim+''].el.style[''+style[''+_gd_dim+'Low']+''] = self.thumb[''+_gd_dim+''].styleSize;
self.track[''+_gd_dim+''].numSize = self.track[''+_gd_dim+''].el['offset'+style[''+_gd_dim+'Cap']+''];
self.thumb[''+_gd_dim+''].numSize = self.thumb[''+_gd_dim+''].el['offset'+style[''+_gd_dim+'Cap']+''];
self.ratio[''+_gd_dim+''] = self.track[''+_gd_dim+''].numSize/self.scroller[''+style[''+_gd_dim+'Low']+''];
self.position.thumb[''+_gd_dim+''] = Math.abs(self.position.scroller[''+_gd_dim+'']*self.ratio[''+_gd_dim+'']);
self.thumb[''+_gd_dim+''].el.style[''+self.animatedProperty[''+_gd_dim+'']+''] = 'translate3d(0,'+self.position.thumb[''+_gd_dim+'']+'px,0)';
}
}
}
}
self.update = function()
{
/** get scroller specs **/
self.scroller.height = self.scroller.el.offsetHeight;
self.scroller.width = self.scroller.el.offsetWidth;
/** get viewport specs **/
self.viewport.height = self.viewport.el.offsetHeight;
self.viewport.width = self.viewport.el.offsetWidth;
/** determine scrollbar dimension **/
self.dimension = {};
self.dimension.horizontal = self.scroller['width'] > self.viewport['width'] ? 'horizontal' : false;
self.dimension.vertical = self.scroller['height'] > self.viewport['height'] ? 'vertical' : false;
/** Determine Min/Max values(can be custom for whatever reason),Animated Property,Start Position for specific dimension */
for ( var k in self.dimension )
{
if(self.dimension[''+k+''] !== false)
{
_gd_dim = self.dimension[''+k+''];
self.Min[''+_gd_dim+''] = self.options.Min[''+_gd_dim+''] ? self.options.Min[''+_gd_dim+''] : 0;
self.Max[''+_gd_dim+''] = self.options.Max[''+_gd_dim+''] ? self.options.Max[''+_gd_dim+''] : self.viewport[''+style[''+_gd_dim+'Low']+''] - self.scroller[''+style[''+_gd_dim+'Low']+''];
self.position.scroller[''+_gd_dim+''] = self.position.scroller[''+_gd_dim+''] ? self.position.scroller[''+_gd_dim+''] : 0;
}
}
if(self.options.visibleScrollbars)
{
iniScrollbar();
}
}
self.init();
}
function animateScroll(posScroller,posThumb,easing,Min,Max,ratio,scrollerStyle,thumbXStyle,thumbYStyle,change,delta,drag)
{
var posThumbX = posThumb.horizontal,
posThumbY = posThumb.vertical,
deltaX = delta.horizontal,
deltaY = delta.vertical,
changeX = change.horizontal,
changeY = change.vertical,
MinX = Min.horizontal,
MaxX = Max.horizontal,
MinY = Min.vertical,
MaxY = Max.vertical,
ratioX = ratio.horizontal,
ratioY = ratio.vertical,
currentPositionX = posScroller.horizontal,
currentPositionY = posScroller.vertical,
stepSizeX = 0,
stepSizeY = 0,
currentStep = 0,
maxStep = drag ? 1 : 60*0.35,
t = 0;
if(_gd_activeAnimation){ stopFrame(_gd_activeAnimation); }
function _step()
{
t = drag ? 1 : currentStep/maxStep;
stepSizeX = easing['easeOutSine'](deltaX*changeX,t,currentPositionX);
stepSizeX >= MinX ? stepSizeX = MinX : '';
stepSizeX <= MaxX ? stepSizeX = MaxX : '';
stepSizeY = easing['easeOutSine'](deltaY*changeY,t,currentPositionY);
stepSizeY >= MinY ? stepSizeY = MinY : '';
stepSizeY <= MaxY ? stepSizeY = MaxY : '';
posScroller.horizontal = stepSizeX;
posScroller.vertical = stepSizeY;
if(posThumb)
{
posThumbX = -1*stepSizeX*ratioX;
posThumbY = -1*stepSizeY*ratioY;
thumbXStyle[''+animatedProperty+''] = 'translateX('+posThumbX+'px)';
thumbYStyle[''+animatedProperty+''] = 'translateY('+posThumbY+'px)';
}
scrollerStyle[''+animatedProperty+''] = 'translate('+stepSizeX+'px,'+stepSizeY+'px)';
currentStep++;
if(currentStep <= maxStep){ _gd_activeAnimation = frame(_step) }
}
_step();
}
function mouseEvent(type, sx, sy, cx, cy) {
var evt;
var e = {
bubbles: true,
cancelable: (type != "mousemove"),
view: window,
detail: 0,
screenX: sx,
screenY: sy,
clientX: cx,
clientY: cy,
ctrlKey: false,
altKey: false,
shiftKey: false,
metaKey: false,
button: 0,
relatedTarget: undefined
};
if (typeof( document.createEvent ) == "function") {
evt = document.createEvent("MouseEvents");
evt.initMouseEvent(type,
e.bubbles, e.cancelable, e.view, e.detail,
e.screenX, e.screenY, e.clientX, e.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
e.button, document.body.parentNode);
} else if (document.createEventObject) {
evt = document.createEventObject();
for (prop in e) {
evt[prop] = e[prop];
}
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
}
return evt;
}
function dispatchEvent (el, evt) {
if (el.dispatchEvent) {
el.dispatchEvent(evt);
} else if (el.fireEvent) {
el.fireEvent('on' + type, evt);
}
return evt;
}
var scroll = new scrollBar('.scroller',{
mouseWheelSpeed:300,
mouseWheel:true,
visibleScrollbars:true
});
var drags = new mouseDragEvents();
Ready to run.
Test | Ops/sec | |
---|---|---|
in |
| ready |
inn |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.