How my jQuery Drag’n’Drop Jigsaw works

AU-bg I had a kind of implied request to talk about the code in this jquery jigsaw puzzle. I sort of figured you can Firebug it from hereif you like, but maybe a little expository prose will enable you to focus on the salient parts of the script. (Sorry the old link got broken when I restructured this blog.)

This script makes use of several of the jquery-ui official widgets or whatever you call them. It also uses tabs, but I’m going to focus on the drag and drop stuff, which is the heart of the matter.
You add draggable class to any DOM element you wish to be able to drag around. You add droppable class to any DOM element you wish to be able to drop things on.

Here are a few of the things I did on the back end to build this puzzle.

  • I have multiple versions of each puzzle piece in a variety of flat colors. I pregenerated them rather than created them on the fly on the back end, because it would extract a huge performance hit to create them on the fly, not to mention that random colors tended to be ugly. When the back end script is run, it decides on a random color and location for each puzzle piece.
  • The random color and location data is attached to the draggable divs which are children of the white container div that precedes the puzzle canvas div. The width and height are constant, and are retrieved from the database.
  • The puzzle background is a div called canvas with a background image of the area in light colours. It contains droppable child div’s corresponding to each piece. The position and size of these divs is grabbed from the database on the back end.

OK, now we get to the jQuery! I suggest running Firebug and examining the code. The script you want to select is puzzle.js The crux of the drag’n’drop is in this code:

	 $(".droppableP > .sensible").each(function() {
			$(this).droppable( {
			   accept :    "#i" + $(this).closest('.droppableP').attr('id').substring(1), 
			   tolerance : 'intersect',
			   activeClass : 'droppable-active',
			   hoverClass : 'droppable-hover',
			   drop : function() {
				   //dependency:  requires utf-8.js loaded
		           currentAudio = Utf8.encode($(this).closest('.droppableP').attr('id').substring(2) );
				   playTrack( parentURL + '/' + currentPuzzle  + '/audio/' + currentAudio + '.mp3');
				   $(this).closest('.droppableP')
				      //.addClass($(this).closest('.droppableP').attr('id'))  //won't work anymore!!!!!
				      .addClass('encastrado')
				      .css({
				    	  'cursor' : 'auto',
				    	  'backgroundImage' :   $('#i' + $(this).closest('.droppableP').attr('id').substring(1)).css('backgroundImage')
				      }) 
				      .animate( {
				            opacity: 0.25 
				         },
				         200, 
				        'linear'
				      ) ;
				   $("#i" + $(this).closest('.droppableP').attr('id').substring(1)).addClass('used').hide();  //previously remove
				   $('div .bp').not('.used').random(1).show();  //shows a new piece to replace the old one
				   //.css('cursor','auto')
				   checkWin();
			   }
		    }); 
	 });

Line by line:
(Note that the numbers for the actual script might change. I’m referring to the excerpt above.) The accept attribute (line 3) defines what the droppable will respond to, and the function attached to the drop attribute defines the behaviour that will occur when the droppable accept is triggered. The actual droppable elements have a class of “sensible” (which means sensitive in Spanish). So I select all the sensibles, and just to make sure, I require that they be descendants of an element of the droppableP class. (parent of a droppable.) Through some string manipulation I construct the name of the corresponding draggable that I want it to respond to.

In the drop function, I want to do several things:

  • Play the sound corresponding to the piece just dropped
  • Copy the background graphic of the piece dropped to its target
  • Then animate fade the target to about 25% opacity
  • hide the dragged object
  • show a new unused piece

I run the utf8 encode filter on the name (line 9) just in case it had non English characters in it. Then I construct the url of the mp3 file from some global variables and feed it to the jquery player plugin and play the sound. (line 10) I add the bogus class “encastrado” (found) to each found piece so that I can check for completion later. (line 13) I alter the css si that it’s background image is a copy of image from the draggable. (lines 14-17) Once the image is in place I animate it down. (lines 18-23) I then add the class “used” to the chosen piece and hide it. (line 24) Then I choose one from the not used yet pieces and show it. (line 25) I then poll to see if the puzzle is finished (line 27), and if it is, I allow the checkWin routine to handle that.

5 comments to How my jQuery Drag’n’Drop Jigsaw works

A sample text widget

Etiam pulvinar consectetur dolor sed malesuada. Ut convallis euismod dolor nec pretium. Nunc ut tristique massa.

Nam sodales mi vitae dolor ullamcorper et vulputate enim accumsan. Morbi orci magna, tincidunt vitae molestie nec, molestie at mi. Nulla nulla lorem, suscipit in posuere in, interdum non magna.