Splitting an image into pieces
Our next task is to divide the image into a specified number of squares to represent the individual pieces of the puzzle. To do this we'll create a series of smaller elements which each show a different part of the image and which can be manipulated individually.
Prepare for Lift Off
The single step required to complete this task is to create a specified number of puzzle pieces and give each a unique background-position and position in order to recreate the image.
Engage Thrusters
We now want to generate the different pieces that make up the puzzle. We can do this with the following code, which should be added directly after the variables we just defined in sliding-puzzle.js
:
for (var x = 0, y = aspectH; x < y; x++) { for (var a = 0, b = aspectW; a < b; a++) { var top = pieceH * x, left = pieceW * a; piece.clone() .attr("id", idCounter++) .css({ width: pieceW, height: pieceH, position: "absolute", top: top, left: left, backgroundImage: ["url(", path, ")"].join(""), backgroundPosition: [ "-", pieceW * a, "px ", "-", pieceH * x, "px" ].join("") }).appendTo(imgContainer); positions.push({ top: top, left: left }); } }
Objective Complete - Mini Debriefing
We used a nested set of for
loops to create the new puzzle pieces in a grid pattern. The first loop will run for as many rows as required; with a 3:4 aspect-ratio image such as that used in this example, we will need four rows of squares. The inner loop will for run for as many columns as required, which in this case is three.
Within the inner loop we first create two new variables top
and left
. We need to use these values in a couple of places so it makes sense to create them once and reuse them each time they're required.
The top
position is equal to the height
of the piece multiplied by the current value of the outer loop's counter variable (x
), while the left
position is equal to the width
of the piece multiplied by the current value of the inner loop's counter variable (a
). These variables are used to make the puzzle pieces line up in a grid.
We then copy our stored <div>
element using jQuery's clone()
method and use the attr()
method to set a unique id
attribute using the idCounter
variable that we initialized in the first part of the project. Notice that we increment the variable at the same time as setting it directly within the attr()
method.
We could increment the variable either inside the method as we have done here, or outside of the method; there's no real difference in performance or anything else. I just feel that it's more succinct to update it in situ.
Next we use the css()
method to set a style
attribute on the new element. We set the width
and height
of the puzzle piece and position it using our top
and left
variables, as well as set its backgroundImage
and backgroundPosition
style properties.
Note
Any style properties that are usually defined using hyphenated words, such as background-image
, should be camel-cased when used with jQuery's css()
method in conjunction with an object.
The backgroundImage
property can be set using our path
variable and the rest of the string components of the style, but the backgroundPosition
property will need to be calculated individually for each puzzle piece.
The horizontal component of the backgroundPosition
style property is equal to the width
of the piece multiplied by the value of the inner loop's counter variable (a
), while the vertical component is equal to the height
of the piece multiplied by the value of the outer loop's counter variable (x
).
Once the new element has been created we can add its position to our positions
array using JavaScript's push()
method, passing in an object containing the top
and left
positional properties of the element for later use.
Classified Intel
Instead of using standard string concatenation to construct the backgroundImage
and backgroundPosition
strings, we put the values into an array literal and then joined the array using JavaScript's join()
method. By specifying an empty string as the value to use to join the string, we ensure that no additional characters are added to the string.
Joining an array of substrings to form a single string is much faster than building a string using the +
operator on substrings, and as we're working repetitively inside a loop, we should optimize the code within the loop as much as possible.