This simple JavaScript picture puzzle contains a unique feature. It uses DHTML techniques to show individual sections of a single picture, so it doesn't need multiple graphics files for the various slices. Here's a full explanation of how the code works.
January 17, 2001
First, an introduction to the puzzle. It's a straightforward shuffle-the-pieces puzzle. There's one blank space and the rest of the picture elements are in the wrong place. The player must make use of the blank space to shuffle the nearby pieces until everything's correctly positioned.
It's not a new kind of puzzle. Similar scripts exist. The difference lies in the way it's generated. Usually, when we want to make an image puzzle, we cut our image into small images, equal in size, so we end up with 16 little gif files created from one big file.
But this new technique uses JavaScript to create the smaller images on the fly. It's a demonstration of a new approach rather than a Copy & Paste script, though you are welcome to use the script yourself if you wish.
As you know, JavaScript is a very limited language that can't manipulate an image file. So how can we take the picture file and slice it for the picture puzzle? All we do is give the impression that we are slicing it. The trick is in the way we set up our div tags (or layers if we want to do it in Netscape). The example here works in Internet Explorer.
To show the first 50 pixels of our image we create a div tag, assign to it a style, and define the crop sizes in the style.
Anything we put inside this tag will be cropped to show only 50 pixels. This is one block of the picture puzzle. We need a few more div tags, each cropping our image, then we order the blocks incorrectly to distort the image. Finally we add functionality allowing the user to change the blocks' positions,
But there are a few extra problems to solve. If our image is 500x100% pixels, we can't make blocks 50 pixels square. The division won't work. This can be solved by a few lines of code that find the image size, divide it by the number of blocks, and so determine the crop dimensions.
var rows = 4;
var lines = 4;
var Ihight, Iwidth, cellH, cellW;
BaseImg = new Image;
BaseImg.src = "birth_of_venus.jpg";
Ihight = BaseImg.height;
Iwidth = BaseImg.width;
cellH = parseFloat(Ihight/rows);
cellW = parseFloat(Iwidth/lines);
Here, the variables cellH and cellW determine the right crop dimensions for our image.
The next problem we face is that so far our blocks show the same top corner of the image - the first 50 pixels (or some other figure). To solve this we create another div tag that goes inside the first and moves the image to different locations inside the first div. You can think of the first div as a window to look at the second div. In the second div we place the <img> tag.
As you can see, the div called "Inn" has a negative position. Because it's displaying the image 100 pixels from the top left corner, to "lift up" the image, it has to have a negative position inside the "Holder" div. Note that the inner div position is relative to the holder div, and the holder div position is relative to the page itself.
These functions create all the blocks of the picture puzzle. Note the onclick event handler inserted in the Makeholder function. This is used to move the blocks.
Out Of Order
Now we need to shuffle the blocks and write them into the browser window. We have an Array of 16 unordered numbers.
RandNum = new Array(7,12,14,3,9,6,0,8,5,10,4,11,1,13,2,15,16);
You can create your own Arrays, but make sure there are no repeated numbers. With this Array we write the puzzle to the same browser window. Our example uses document.write(), though there are problems with this solution. You may find that the script shows the puzzle only on the second try, due to image caching problems. An alternative would be to use an innerHTML method.
Here is the code that writes the blocks. The first line writes JavaScript code that changes their order. Notice that the image tag is inserted in only 15 blocks (cells-1) to keep one block free for the player to use.
document.write(Scrip);
for (q=0; q<cells; q++) {
document.write(HoldDiv[q]);
var Rnumber = RandNum[q];
document.write(InnerDiv[Rnumber]);
if (q != cells-1){
document.write('<img src="'+IMAGE+'" name="mag'+q+'" border="0">');
eval ("document.mag"+q+".src = BaseImg.src");
}
document.write("</div></div>");