Damian Cugley → Alleged Tarot 2002 →
SVG files can have Javascript programs embedded in them, just
like HTML.
So my
deal.svg
graphic is linked to a JavaScript file
dealer.js
which defines a bunch of
variables and functions
for decoding the script parameters,
and "dealing" cards. The outermost svg
element in
the picture has an onload
attribute that invokes
a function ol
that ties them all together.
The first thing it does is call
scanOpts
which extracts the parameters to the script from the
URL. The params recognized at present are
lo
, which must name one of the
layouts it the "database" of layouts (described later),
and q
, the question text.
An example URL defining
those parameters would be deal.svg?lo=horseshoe&q=Will+Frodo+reach+Mordor%2F
(where the
plus signs represent spaces, and %2F
is an encoded question mark).
Then ol
creates an array of 78 numbers representing the cards
and calls shuffle
to rearrange them randomly.
Finally it calls dealLayout
to
generate images of cards "drawn" from the deck
at positions on the screen defined by the layout.
Each card is represented by a bunch of SVG elements—the
rectangle that is the backdrop, the image of the card, the text, etc.
Rather than try to write JavaScript code that creates all these
elements, I created a template in the defs
section which
is cloned once for each dealt card. This uses the DOM functions
getElementById
to locate the items that need to be modified
(such as the link, whose xlink:href
attribute must be modified),
and finally cloneNode
to make a copy that can
be appended to the document.
The advantage of using getElementById
each time
is that it avoids having the code that makes the per-card changes
having to know the details of how the cards are drawn.
I should be able to make changes to the SVG template
without breaking the dealing part.
A layout is an arrangement of dealt cards, eahc of which needs to have an indication of its role in the spread (this card represents the seeker, that one the future, and so on). At first I stored this in the JavaScript as a dictionary (=object) mapping layout names to a sequence of card coordinates:
var layoutDefs = { three: [0,0,'past', 1,0,'present', 2,0,'future'], ...etc... };
This worked well enough, but when it came to the Celtic Cross
spread—which has one card laid crosswise—I realized
this was too limited for the long term. So I rewrote the
dealLayout
function to instead use XML data stored in the
SVG document itself:
<lo:layouts xmlns:lo="http://www.alleged.org.uk/pdc/tarot/"> <lo:layout id="three"> <lo:card col="0" row="0" title="past"></lo:card> <lo:card col="1" row="0" title="present"></lo:card> <lo:card col="2" row="0" title="future"></lo:card> </lo:layout> .... </lo:layouts>
This goes in the defs
section, along with the
template for the cards. (I cannot find a reference
in the SVG specification that makes it explicit that
embedding random XML data in SVG is kosher, but it seems
to be implied by wording on the SVG section of the W3C site.)
The JavaScript code uses the DOM conventions to read the information needed to lay out the cards. Using XML means that it was easy to add another attribute indicating a rotated card—and makes it easy to extend the format when adding new exotic layouts in future. For example, longer descriptions of the significance of each of the positions in the spread?
The querent’s question affects the deal through the
"shuffling" process. The shuffling is controlled by a sequence of
78 pseudo-random numbers, and the pseudo-random number sequence in
turn depends on a seed number. The function
questionToSeed
converts the character string in to a single
number. The algorithm used is a simple one I found after a little
time with Google. (Try
g_str_hash X31_HASH).
The textbook I had at my side while doing the JavaScript programming is the rhino book: David Flanagan, JavaScript: The Definitive Guide 4/e (O’Reilly, Jan 2002).