Reputation: 541
I've created a little javascript web page for Movember to let users "shave" my beard into a moustache, or completely off.
I've done this by covering a shaved picture with a grid of divs holding the bearded picture with differing offsets. When a user moves their mouse over one of the divs, it disappears, showing the shaved skin in the picture underneath.
The problem is that in creating the 4000 little divs, the jquery.min.js script keeps popping up an "unresponsive script" error.
I'm hoping somebody can spot something really inefficient in my code, or suggest how to get Jquery to take a breath. I even tried having a "loading..." spinning wheel gif show while the code was running, but the javascript threw the hourglass so quickly that the gif never even showed up.
Here's the code:
<script type="text/javascript">
var isErase = false;
var isCover = false;
var size = 4;
var i = 0;
var j = 0;
$(document).ready(function(){
for (i = 0; i < 400; i += size) {
for (j = 0; j < 250; j += size) {
$('#picture').append('<div class="piece" style="background-position: -' + j + 'px -' + i + 'px;" />');
}
}
$('div.piece').click(function(event){
isCover = false;
isErase = ! isErase;
if (isErase) $('#mode').html(' *** SHAVING ***');
else $('#mode').html('OFF');
});
$('div.piece').dblclick(function(event){
isErase = false;
isCover = ! isCover;
if (isCover) $('#mode').html(' *** UNSHAVING ***');
else $('#mode').html('OFF');
});
$("div.piece").mouseenter(function(event){
if (isErase) { $(this).addClass('invisible'); }
else if (isCover) { $(this).removeClass('invisible'); }
});
});
</script>
Upvotes: 1
Views: 1984
Reputation: 75317
<script type="text/javascript">
var isErase = false;
var isCover = false;
var size = 4;
var i = 0;
var j = 0;
var str = '';
$(document).ready(function(){
for (i = 0; i < 400; i += size) {
for (j = 0; j < 250; j += size) {
str += '<div class="piece" style="background-position: -' + j + 'px -' + i + 'px;" />';
}
}
$('#picture').html(str).delegate('div.piece', 'click', function (event) {
isCover = false;
isErase = ! isErase;
if (isErase) $('#mode').html(' *** SHAVING ***');
else $('#mode').html('OFF');
}).delegate('div.piece', 'dblclick', function(event) {
isErase = false;
isCover = ! isCover;
if (isCover) $('#mode').html(' *** UNSHAVING ***');
else $('#mode').html('OFF');
}).delegate('div.piece', 'mouseenter', function(event) {
if (isErase) { $(this).addClass('invisible'); }
else if (isCover) { $(this).removeClass('invisible'); }
});
});
</script>
The biggest inefficiency's in your code were as follows:
piece
each time. Creating a string with the HTML and adding it once is so much quicker.$('div.piece')
, you looked up all 100,000 of those. Either chain your jQuery methods, or cache the objects.piece
's. Take advantage of Javascripts event bubbling, and add the event once to an ancestor of the elements (see delegate()).Upvotes: 4
Reputation: 590
This helps for me in safari, but either way I don't this is something that is really suitable for HTML and JavaScript.
<script type="text/javascript">
var isErase = false;
var isCover = false;
var size = 4;
var i = 0;
var j = 0;
$(document).ready(function(){
for (i = 0; i < 400; i += size) {
for (j = 0; j < 250; j += size) {
$('#picture').append('<div class="piece" style="background-position: -' + j + 'px -' + i + 'px;" />');
}
}
$("#picture").live('click',function(event){
isCover = false;
isErase = ! isErase;
if (isErase) $('#mode').html(' *** SHAVING ***');
else $('#mode').html('OFF');
});
$("#picture").live('dblclick',function(event){
isErase = false;
isCover = ! isCover;
if (isCover) $('#mode').html(' *** UNSHAVING ***');
else $('#mode').html('OFF');
});
$("div.piece").live('mouseenter',function(event){
if (isErase) { $(this).addClass('invisible'); }
else if (isCover) { $(this).removeClass('invisible'); }
});
});
</script>
Upvotes: 1