Design Features

To fit in 10K I had to be fairly ruthless as to which features were
absolutely necessary and which merely nice-to-have. The main ones are:

Given a search term, find an image URL;

Given an image URL, display puzzle pieces;

Large pictures are scaled down and small ones scaled up to fit in the arena;

Pieces are moved with drag and drop;

Pieces snap together when brought together to make hunks;

Hunks of puzzle get dragged around as a unit.

I didn’t want the pieces to snap in to their position on the board. The
effect I wanted was like when my mum worked on jigsaws on a big board,
assembling hunks and then combining them.

Some nice-to-have features would be:

Vary the size of the bumps to make the pieces’ shapes more variable;

Pieces that rotate;

Drop shadow for hunks which is deeper for the one being dragged (to give faux 3D);

Sound when snapping pieces together;

Message when puzzle complete;

Permalinks for sharing a particular jigsaw with your chums.

I ran out of space or time for these, but I might add them later on anyway.

Jigsaw Pieces in SVG

Since I wanted curvy shapes, SVG seemed the logical way to implement
the puzzle itself.

I wanted to do this without manipulating the image directly—each puzzle
piece displays a piece-shaped portion of the original image. I was using
SVG for this, so there are three ways that occurred to me:

Each puzzle piece has a reference to the image with a different
clipPath element.

Each puzzle piece is a path element whose fill refers to a
pattern that references the image.

Each puzzle piece is a path element with a filter that uses the
image as a raster source and then offsets it.

The problem with using image and clipPath (at least in the way I
tried it) was that Safari treats drag-and-drop specially for images,
allowing you to drag images out of a page on to your desktop. The effect
of this was that when you dragged a puzzle piece, a ghost of the
complete image would appear and it would go awry. It is possible that
there was a way to fix this, but in the end I decided to try a different
approach instead.

Option 2 is what I got working in the end. Each piece is a
path whose fill references a pattern whose sole content is a use
element referencing a symbol which contains the image. This means
the image should be loaded only once (not once per piece), though I do
not know whether the buffering of the pattern image will consume
graphics memory based on the entire image size or just the fraction
visible in the puzzle piece.

The paths for the pieces are generated by JavaScript, using a hash
function of the row and column of the piece to decide whether its bump
pokes out or in. As is common in graphics work, the hBump and vBump
functions are very similar since they just swap
x coordinates for
y
coordinates, but it isn’t quite possible to write one cleverer function
that works either way. When every character counts towards the 10K
total, the almost-duplicated code is annoying.

Drag & Drop

The trickiest part of the JavaScript programming was getting the
drag-and-drop interaction to work. It is particularly exasperating to
debug since you can’t interact with the debugger without interrupting
the mouse movements you are trying to observe. I had to add a logging
system to spurt out progress messages.

Eventually I settled on a system
where, on mousedown, I record the clientX and clientY attributes of
the event, and the start X and Y of the puzzle pieces in the affected
hunk. Then as mousemove events arrive, the change in event coordinates
is added to the the piece coordinates. This avoids having to translate
from the coordinate system used for events and the coordinate system
used for the pieces.

The other thing I had to do was ensure that the mousemove events are
captured by the container (g element) containing all the pieces, so
that they are still caught even if the user’s mouse movement takes it
out of the boundary of the piece. For this to work, the background (the
big grey rectangle) has to be included in the enclosing g element,
since otherwise the container is transparent where there are no pieces
and does not receive events.

It is possible that sufficiently clever use of the properties
controlling movement events would have allowed for this to work with
transparent background, but once I had got something together
I was not in the mood to fiddle with it.

Host Page

While the jigsaw itself is purely SVG + JavaScript, it is supplied with
its image URL, image dimensions, and number of pieces by
the HTML page it is embedded in. (I did not
attempt to merge the SVG in to the HTML page, but used an embed tag. I am assuming
without checking that embed is permissible HTML5, given it is the only
way to embed SVG that works reliably.) This page takes care of displaying the form,
loading the image to get its dimensions, if necessary, and embedding the jigsaw.

The Flickr support works through the Flickr API. Using the JSONP
approach—where my app performs a simple HTTP request and Flickr returns
the data as an object in JSON format—is a snap with jQuery. I created a
flickrCall function to do this not so much because it was complicated
as to save a few dozen bytes’ repeated code.

By the way, Flickr enforces ‘safe’ search, so feel free to create jigsaws of big cocks and great tits.

The first version of the app had two forms, not one. The Flickr tag form
had a button labelled ‘Next >’ which did the Flickr API call and copied
the URL in to the second form, which had the ‘Jigsaw!’ button. After
complaints from my play testers, I did the typical thing, which is
ponder adding messages or arrows to tell people the correct order to
operate the controls. Then I realized the correct solution was to mash
the forms together in to one. The new form has both URL and tag fields,
but only one is shown at a time. I had this brainstorm just before going
to bed, but it only took half an hour or so to refactor the jQuery code
to implement the new user experience.

Future

The app has been entered in to the contest and awaits the judges’ verdict. Meanwhile I have
its own little web site, http://jigsawr.org/

I should add a link on the jigsaw to itself, so you can share your favourite jigsaws with your friends.

It should be easy to create a bookmarklet that examines the current page, finds the largest image on it, and
displays a jigsaw of that image.

I am considering how I might implement rotating of pieces—though most players will agree it is more likely to be annoying than fun.

One thing I have not worked out how to do: an iPad-compatible version. Drag & drop does not work
because dragging is used for moving the page as whole!