I've a code which applies marquee to certain elements by using the requestAnimFrame
method. However, when I test my application on a lower spec PC (Intel Celeron 2.13GHz dou core) the CPU usage is skyrocketing and gets to a minimum of around 80%! (I have to mentioned that I have 2 elements that the custom maruqee is applied to).
Also, there are cases where even 3 or 4 elements are being targeted by the marquee. There is also a case in my application, not so common, that there is another animation that scrolls text from the right to the left.
My development environment is a lot different, I'm using a 3.8GHz 8-cores CPU with a strong GPU so my CPU usage is no more than 11%.
I'm not sure if it matters but locally I'm using xampp and on the tested PC I've been using wamp.
The code for my marquee is splitted into few functions:
/**
* Applies the marquee function to the elements who are overflowing
*/
function tryMarquee(/**/) {
var args = arguments;
for(var i=0; i<args.length; i++) {
var elem = $(args[i]);
var containerHeight = elem.outerHeight(true);
var contentHeight = calculateContentHeight(elem);
// extract args
var settings = $('.marqueeSettings');
var speed = settings.find('input[data-target="'+args[i]+'"]input[name=marqueeSpeed]').val() || 1;
var spacer = settings.find('input[data-target="'+args[i]+'"]input[name=marqueeSpacer]').val() == "1";
var spacerHeight = settings.find('input[data-target="'+args[i]+'"]input[name=marqueeSpacerHeight]').val() || 60;
if(contentHeight > containerHeight && containerHeight > 10) {
marquee(args[i], speed, spacer, spacerHeight);
}
}
}
/**
* Calculates the content height of an element by it's children's height
* @param elem
* @returns {number}
*/
function calculateContentHeight(elem) {
var total = 0;
elem.children().not('.clone').each(function() {
if(parseInt($(this).css('margin-top')) >= 0)
total += $(this).height() + parseInt($(this).css('margin-top'));
else
total += $(this).height();
});
total -= 10;
return total;
}
/**
* Generates a spacer.
* @param marginTop
* @param height
* @returns {*|jQuery|HTMLElement}
*/
function generateSpacer(marginTop, height) {
var spacer = $('<div class="marquee-spacer clone" style="margin-top: '+marginTop+'px;"></div>');
height = height || 60;
spacer.css({
height: height
});
return spacer;
}
/**
* returns a clone of an element's children
* @param elem
* @returns {*|jQuery|HTMLElement}
*/
function duplicateContent(elem) {
return elem.children().clone().addClass('clone');
}
/**
* Checks the prayers element still needs the marquee.
* @returns {boolean}
*/
function keepPrayersMaruqee() {
var containerHeight = elem.outerHeight(true);
var contentHeight = calculateContentHeight(prayers);
return contentHeight > containerHeight;
}
These functions are only triggered once so I'm not sure if it has something to do when the application is fully loaded and already running.
function marquee(className, scrollAmount, spacer, spacerHeight) {
// parse spacer
spacer = spacer || false;
// select the elements
var elemSet = $(className);
// loop through the element set
elemSet.each(function() {
var $this = $(this);
$this.addClass('marquee');
/**
* TODO: if the container is taller than the content we should clone the content so there's no gap in the loop
*/
var initialMargin = parseInt($this.find("div").first().css('margin-top'));
if(spacer)
$this.append(generateSpacer($this, initialMargin, spacerHeight));
$this.append(duplicateContent($this));
(function loop(){
/**
* This block of code is only executed on a certain element so check if it still needs to be scrolled
* because there is a possibility that the element's children will be removed dynamically.
*/
if($this.hasClass('prayers'))
if( ! keepPrayersMaruqee()) {
// remove clone elements
$this.children('.clone').remove();
// cancel the maruqee
return;
}
var first = $this.find("div").first();
var top = parseInt(first.css('margin-top'));
var height = first.outerHeight();
if ((height+top) > 0){
first.css('margin-top','-='+scrollAmount);
} else {
first.appendTo($this);
first.css('margin-top',initialMargin);
}
/**
* repeat the animation
* @see window.requestAnimFrame
*/
requestAnimFrame(loop);
})();
});
}
This is where the magic happens. I was trying to make this code as efficient as possible. Any suggestion on how I can actually improve this code and make it consume much less CPU power?