DHTML Jigsaw Puzzle: Cross-Browser; Initialization | WebReference

DHTML Jigsaw Puzzle: Cross-Browser; Initialization


The DHTML Lab Jigsaw Puzzle, Part IV: Cross-Browser
initializing the puzzle

The Global Variables

The puzzle script global variables are exactly the same as always, with two new bug-fixing additions, imageSelected and isSolving:

    puzzLeft = puzzTop = null; puzzWidth = puzzHeight = null; bordWidth = 3; puzzAcross = puzzDown = 5; isPuzzDraggable = true; isGrid = false; isNewPuzz = null; isCreated = null; piecesCreated = 0 pieceCount = 1; topCount = 0; isBroken = false; solvedCount = 1; pieceToSolve = null; flashTotal = 6; flashCount = 0; loadTotal = 3; loadCount = 0; tempEl = null; sp = " "; imageSelected = false; isSolving = false;

In our original Navigator code, we excluded elControls from the mousedown event, thus enabling the form buttons, and allowing the user to drag the full puzzle only by grabbing the image. After a new image load, the form buttons could become "sticky", needing a second or third attempt before they reacted. This reaction, of course, does not make much sense. If it is OK the nth time, why isn't it OK the first time? To avoid this problem, we will capture and release a mousedown only if the user is over the image. To track the mousedown in relation to the image, we declare the imageSelected variable.

In the original Explorer and Navigator codes, if a user pressed Solve, while an automatic solve was already in progress, a second auto-solve began, leading to unpredictable, albeit humorous, results. Selecting Hint during auto-solve caused problems as well. We didn't foresee this possibility. To track the auto-solve, therefore, we introduce isSolving.


Our puzzle image, our grid image, and our HTML page, all call the whenLoaded() function when they have loaded. If all is fine, the function now calls one of two browser-specific initialization functions. When these functions return, whenLoaded() sets up puzzle draggability, as before, then assigns a new function, showIt(), as a method of all elements that allow visibility toggling (see below). Then it completes its statements as before, and calls initPuzz(), passing the fake "firstPic" argument to identify the call as a first time call.

    function whenLoaded() { loadCount++; if (loadCount initNS4() } else { initIE4() } if (isPuzzDraggable) { elPuzzle.draggable = true; if (IE4) { elImage.style.cursor = "move"} } else { elPuzzle.draggable = false; dragBut.value = "Drag OFF"; } elPuzzle.showIt = elGrid.showIt = elBlank.showIt = elImage.showIt = elControls.showIt = showIt; elPuzzle.clipLeft = elPuzzle.clipTop = 0; initPuzz("firstPic"); }

Navigator Initialization

The Navigator-specific initialization assigns objects to variables that correspond to their ID, in the case of the elements, to their NAME, in the form button case, or a new cross-browser moniker is created, as with the images:

    function initNS4(){ elPuzzle = document.elPuzzle; elBlank = elPuzzle.document.elBlank; elGrid = elPuzzle.document.elGrid; elImage = elPuzzle.document.elImage; elControls = elPuzzle.document.elControls; gridImage = elGrid.document.images["imGrid"]; puzzImage = elImage.document.images["imOrig"]; gridBut = elControls.document.fmControls["gridBut"]; dragBut = elControls.document.fmControls["dragBut"]; elImage.onmouseover = overImage; elImage.onmouseout = outImage; }

This shorthand reference scheme will assist us in cross-browser referencing, and will save us some typing.

To help us in identifying the full puzzle as the intended element-to-drag, the onmouseover and onmouseout event handlers are assigned to elImage. Whenever the user passes the mouse over elImage, the overImage() function is called. When the mouse leaves elImage, the outImage() function is called.

Capturing mousedown for the Full Puzzle

In Navigator, therefore, when the user passes the mouse over the puzzle image, overImage() is called, which checks to see if the puzzle is draggable to begin with. If it isn't, the function returns. If it is, the imageSelected variable is set to true, and then, and only then, do we capture the mousedown event, and direct it to grabEl().

    function overImage() { if (!isPuzzDraggable) {return}; imageSelected = true; document.captureEvents(Event.MOUSEDOWN); document.onmousedown = grabEl; } function outImage() { imageSelected = false; document.releaseEvents(Event.MOUSEDOWN); }

When the user leaves the image area, imageSelected becomes false, and mousedown capturing is terminated. In this way, elControls never receives a mousedown, to create "sticky" buttons. In fact, only elImage receives the mousedown, since leaving elImage cancels event capturing.

Explorer Initialization

Since Explorer can refer to all elements by their ID only, there is no need to create variables for them. We do, however, assign the form buttons to the same variables as Navigator does. Even though Explorer recognizes the document.images array, it does not update it as efficiently as it does its proprietary "all" collection. Therefore, puzzImage is initialized to the puzzle image ID, elImOrig.

    function initIE4(){ dragBut = document.fmControls["dragBut"]; gridBut = document.fmControls["gridBut"]; puzzImage = elImOrig; elControls.style.textAlign = "center"; }

Finally, we make the HTML contained in the control panel centered within the element. An added bonus, which Navigator does not allow us to do without reloading the element content every time its size changes.


The puzzle plays with element visibility quite a bit. The flashing upon correct positioning or solve, hiding the puzzle image to create a work area, turning the grid on and off, and so on. If you recall, our Navigator elements take visibility values of show and hide, and Explorer elements require visible and hidden. To avoid much typing of if...else statements, we can create a cross browser JavaScript method for elements that need visibility toggling. A function is assigned to this method, so whenever the method is used, the function is called.

Therefore, we create a function, showIt(), which takes one Boolean argument, on, denoting whether the element should be made visible or not:

    function showIt(on){ if (IE4) {this.style.visibility = (on) ? "visible" : "hidden"} else {this.visibility = (on) ? "show" : "hide"} }

Now, if we wanted to create a method for say, elPuzzle, we need the statement:

    elPuzzle.showIt = showIt;

To make elPuzzle visible, we need only to include a true argument in the method, and vice-versa to hide it:


All the elements requiring this method, have it assigned in the whenLoaded() function, before initPuzz() is called.

More Initialization

Except for the substitution of our new showIt() method, initPuzz() is as we left it in the Navigator discussion. It re-initializes variables, tidies up through allDone(), changes the puzzle image by calling changeImage(), and makes sure the puzzle is visible.

    function initPuzz(whichIm) { isNewPuzz = true; if (isBroken) {allDone(false)}; changeImage(whichIm); elPuzzle.showIt(true); isCreated = false; pieceToSolve = 1; }

Next, we look at loading puzzle images and shaping the puzzle container to accomodate them.

Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Dec. 17, 1997
Revised: Jan. 18, 1998

URL: http://www.webreference.com/dhtml/column11/puzzCBinit.html