paperJS (paper.js) JavaScript Library walk through by Brett Paufler -
9-18-13
JavaScript Tutorial & paper.js primer
MultiDimensional & Two Dimensional Arrays
The hardest part about filling the screen with a pattern of
repeating hexagons (or any shape for that matter), for me at least, was
figuring out how to do a two dimensional array. The form for
creating a two dimensional array is simple enough:
var firstArray = [];
firstArray[1] = [];
firstArray[2] = [];
firstArray[3] = [];
firstArray[etc.] = [];
This is more commonly written along the lines of:
var firstArray = [];
for (i = 1; i <= 3; i++){
firstArray[i] = [];
}
I must admit that I like the way the syntax below looks, but it won't run for me:
var firstArray[[]]; // this is an ERROR for me
In short, to declare a two dimensional array, one must simple declare the base array:
var firstArray = [];
And then, declare a second array as the value for each item in the first array:
for (i = 1; i <= 3; i++){
firstArray[i] = [];
}
HexaGon &/or HexaGram GameBoard Creation
This is the complete segment of code that tiles the screen with hexagons, including the color shift effect.
// createHexaGonBoard
var gameHex = []; // the array to hold each of the Hexagon Path objects
var hexSize = 25; // size of the object, this can be changed, also it's not a 'Magic Number this way
var hexCenter = new Point(0,0); // at the origin, I tried to center the pattern at CP, but this was easier, go with easier
var gTNH = 0; // horizontal - gameTileNumberHorizontal // a tracking variable that will be incremented
var gTNV = 0; // vertical // another tracking variable, two dimensional pattern = 2 tracking variables
// all of the variables (per above) are declared outside of the function and so are global in scope
function createHexaGonBoard(){ // function declaration
gTNV = 0; // resetting the variable to zero for the second time the function is called
for (hexCenter.y = 0; hexCenter.y <= (screenHeight + pushHeight); hexCenter.y + hexSize){ // it's complicated, but it's just a for loop
gameHex[gTNV] = []; // for each vertical row (each gTNV) another array is added to our array
hexCenter.x = 0; // hexes are drawn from left to right across screen, this sets X position at zero
gTNH = 0; // resets the Horizontal control variable to Zero for each pass throug the loop
for (hexCenter.x = 0; hexCenter.x <= (screenWidth + pushWidth); hexCenter.x + hexSize){ // calling to 2D array requires 2 for loops
if (gTNH === 0){ // is true only once per line
hexCenter.x += (gTNV % 2) * hexSize; // equals zero every other line
} // this if statement shifts the octagons by half a size, at every other line
gameHex[gTNV][gTNH] = {}; // probably not technically required, I tend to set variables as objects prior to loading Path()'s into them
gameHex[gTNV][gTNH] = new Path.RegularPolygon(hexCenter, 6, hexSize); // octagon path creation, should be review
//gameHex[gTNV][gTNH].strokeColor = 'black'; // at the end, Iremarked out the outline color
// this is
what it was throughout most of the debugging process
gameHex[gTNV][gTNH].fillColor = 'red'; // for the hue effect to work, one cannot start with black
gameHex[gTNV][gTNH].fillColor.hue += gTNV*gTNH; // hue incremented by a more or less random operation
hexCenter.x += (2 * hexSize); // the X coordinate of the hexCenter is shifted
gTNH += 1; // the horizontal control variable is incremented (stands for gameTileNumberHorizontal)
} // inner for loop terminates, this is the one that controls the horizontal placement
gTNV += 1; // gameTileNumberVertical is incremented outside of inner for loop
hexCenter.y += 2 * hexSize; // vertical displacement of center in incremented
} // outer for loop controlling vertical displacement terminates
} // create createHexaGonBoard() // the function terminates
createHexaGonBoard(); // the function is immediately called
The same code without the explanatory comments:
// createHexaGonBoard
var gameHex = [];
var hexSize = 25;
var hexCenter = new Point(0,0);
var gTNH = 0; // horizontal - gameTileNumberHorizontal
var gTNV = 0; // vertical
function createHexaGonBoard(){
gTNV = 0;
for (hexCenter.y = 0; hexCenter.y <= (screenHeight + pushHeight); hexCenter.y + hexSize){
gameHex[gTNV] = [];
hexCenter.x = 0;
gTNH = 0;
for (hexCenter.x = 0; hexCenter.x <= (screenWidth + pushWidth); hexCenter.x + hexSize){
if (gTNH === 0){
hexCenter.x += (gTNV % 2) * hexSize;
} // this shifts the octagons by half a size, every other
gameHex[gTNV][gTNH] = {};
gameHex[gTNV][gTNH] = new Path.RegularPolygon(hexCenter, 6, hexSize);
//gameHex[gTNV][gTNH].strokeColor = 'black';
gameHex[gTNV][gTNH].fillColor = 'red';
gameHex[gTNV][gTNH].fillColor.hue += gTNV*gTNH;
hexCenter.x += (2 * hexSize);
gTNH += 1;
}
gTNV += 1;
hexCenter.y += 2 * hexSize;
}
} // create createHexaGonBoard()
createHexaGonBoard();
Both for loops are variable and can be dynamically changed at runtime:
screenHeight + pushHeight
screenWidth + pushWidth
For whatever reason, if one draws to a canvas, that canvas is increased
to fit the drawing. Or so, I infer from the behavior of this
code. This is where that extra size is inserted into the drawing
program.
User Input - The Six Control Boxes
Up top on the left are six boxes, three white (or empty), three
black. onMouseDown() within those boxes (onMouseClick) produces
these results:
First White: increments the pushWidth variable, if screen is subsequently redrawn, hexagons will extend off side of screen
First Black: same as above, but for the height
Both of these effects may only be noticeable in a browser that has been
opened to less than full screen. (This has nothing to do with
screen size.) Rather, if a browser is opened to less than full
screen, after incrementing these variables and then redrawing the
hexes, if the browser is then enlarged, the additional hexes can be
seen. (Different browsers work differently, but in Mozzilla,
nothing is different until one enlarges the browsers screen area.)
Probably not an important effect, still it is there, so it should be noted.
Second White: decrements the hexSize variable by 5
Second Black: increments the hexSize variable by 5
Nothing really happens until one of the next buttons is pushed. Code for these, discussed below.
Third White: screen is redrawn without the hexagrams (making the PointText feedback boxes easier to read)
Third Black: screen is redrawn with hexagrams, implementing the changes from any other button
Here's the code for implementing the boxes:
The onMouseDown function calls the checkClickBox and nothing more:
function onMouseDown(event){
checkClickBox(event);
}
function checkClickBox(event){
for (i = 1; i <= 6; i++){ // a for loop that cycles through all of the possible click boxes
// if there are enough items and this structure is used onFrame, the program will
crawl to a halt
if (clickBox[i].contains(event.point)){ // Asks whether this is the clickBox we want? sets 'i' to the appropriate number
switch (i){ // 'i' having been set above, it is used to call the appropriate case
case 1:
pushWidth += 100; // onClick the variable is incremented
clickBoxContent(); // this updates the text at the click box area
updateFeedbackPointText(); // this updates the PointText's used for Feedback
break;
case 2:
pushHeight += 100; // onClick the variable is incremented
clickBoxContent();
updateFeedbackPointText();
break; // every case ends with a break or the one will run into the next
case 3:
if (hexSize > 5){hexSize -= 5;} // a simple if/then statement that limits the size of the change, no smaller than 5
clickBoxContent();
updateFeedbackPointText();
break;
case 4:
if (hexSize < 100){hexSize += 5;}// a simple if/then statement that limits the size of the change, no larger than 100
clickBoxContent();
updateFeedbackPointText();
break;
case 5:
paper.project.activeLayer.removeChildren(); // erases the canvas, all items are removed from the project active layer
createDefaultPage(); // the above removes everything, this puts certain pieces back, the text, it's user defined, not a default function
updateFeedbackPointText();
break;
case 6:
paper.project.activeLayer.removeChildren();
createHexaGonBoard(); // order is important // a user defined function that redraws the board (is as discussed above)
createDefaultPage();
updateFeedbackPointText();
break;
} // end switch
} // end contains if
} // end for
} // end checkClickBox function // these comments actually appear in the code as I find them internally useful
The order in which paper.js draws objects is important. This is the code that redraws the screen:
createHexaGonBoard(); // order is important
createDefaultPage();
If the order was reversed, the hexagons would appear on top of the text
and it would be darn near impossible to read and of the PointText information. (Trust me on this.)
Subsequently, I like the idea of the board being redrawn at every
button click and just inserting a few lines of code into the above will
function will accomplish this (the last few lines included here only):
case 6:
paper.project.activeLayer.removeChildren();
createHexaGonBoard(); // order is important
createDefaultPage();
updateFeedbackPointText(); // keep or delete this block, doesn't matter
break;
} // end switch
paper.project.activeLayer.removeChildren();
createHexaGonBoard(); // order is important
createDefaultPage();
updateFeedbackPointText(); // add it down here and it runs for every case
} // end contains if
} // end for
} // end checkClickBox function
To redraw at every click in the boxes, just add the redraw commands
(from case 6) inside the end of the if/then function. Of course,
board will redraw even for the case where it's not supposed to (case
5); and that explains why I didn't implement the code this way.
Philosophy of an Education
It's my web page and I'll rant if I want to, but not for very long, as my fingers are getting tired.
Once again, let me reiterate how helpful I find the PointText objects
(the ones I use for feedback going down the left side of the screen).
Those are items from inside the code, derived at runtime, and is about
as useful and detailed information about what's going on inside the
code at runTime as I've seen demonstrated anywhere. (Granted, I live a
sheltered life.) The first half correspond to the work in
progress, the filling of a screen with hexagrams. The second
half, well, I had to put something there. Oh, I don't know.
Let's see. How about a little color. Yes, the color effect
was a complete afterthought, something I inserted into the code because
I was looking for values to plug into the PointText's and nothing
relevant came to mind. So, when in doubt, explore something new for
next time. Walla, shifting color.
It's arguable the coolest effect on the page and it required two lines
of code. Well, three, I had to comment out another pre-existing
line of code as well:
//gameHex[gTNV][gTNH].strokeColor = 'black'; // outline color is commented out
gameHex[gTNV][gTNH].fillColor = 'red'; // create a fill color, set it to something that is not black
gameHex[gTNV][gTNH].fillColor.hue += gTNV*gTNH; // vary it with some random equation, truly, the first mathematical operation I could think of
So, that's not really well established guidance, so let's rework it into a general rule, something along the lines of:
- Push yourself a little further each time you code.
And now, what I really wanted to rant about (but since I grow weary, I
really won't go on for any length at all).
I am disillusioned with
schools and universities. Yes, I am an old man. Yes, I
already have my degree(s). But most importantly (and this is very
important): NO, I don't go back to college whenever I want to learn
something new. Read between the lines. In my ever so humble
opinion, colleges are great for granting credentials (and in many
instances give access to wonderful equipment and resources:
mainframes, labs, particle colliders, telescopes, frat parties, and
world renown researchers -- call them teachers), but if one actually
wants to learn, well, learning is a solitary endeavor. Yeah,
schools might
be great places to do that, but they also happen to be expensive places
to do that. And I've taken enough classes and earned enough
degrees and certificates to know that more often than not, it's all
focused at the lowest common denominator in the classroom, which is not
me. (At times, I may be among the most arrogant participants in a
room, but hardly ever the one bringing the average down. It's
just not my style or who I am. I am also a writer of fiction,
which means I am more than comfortable lying to myself and others, so
deal with it.)
Whatever. Doesn't matter.
The point of it all, is that these tutorials are, in fact, my chosen
learning environment (for paper.js, JavaScript, and coding at
large). And nestled in there somewhere (the 'why' of why I chose
to do it that way), is the idea I wished to convey at this
junction. And that is, as soon as
possible, one should:
A 'Deliverable' is a web page, a program, a short story (I believe I
may have just recently mentioned that I also write, so, please, feel
free to visit my other web site Brett Words
and help market my books for me). But we were talking about what
a deliverable is. A deliverable is a short story, a long story, a
meal that you've cooked yourself (see my cooking blog, BrettFood) if you have ambitions in that regard.
And, believe it or not, mentioning my belief in the notion of
'Generating Deliverables' wasn't intended to be just a random excuse to
hype my own work (though I
will take and create any excuse I can get), but rather to show that I
put my money where my mouth is and as proof that I do honestly and
sincerely believe that the proof of an education isn't a degree (they
grant millions of those each year), but rather in the portfolio of work
an individual is able to lay on the table the day of their graduation.
So, presumably you're reading a tutorial. Or if I'm writing to air, then I will write to myself.
- Content Is Important
- Create Content
- Create It Early
- Create It Often
- For It Is On Your Content That You Shall Be Judged
In other words, if you fancy yourself a coder, code. Don't worry
about the rest. After a thousand or ten-thousand hours, you will
be a master of the craft.
The Great Brett has spoken.
Oh, and if I'm really going to push my content, I just posted this a
few days back and I'm really proud to be associated with this
particular writing project, so you might want to check it out... or
maybe I will when I review this web page in a week or two (I mean, it's
only good practice to check to make sure all the links are working on a
page).
Anyhow, the work in question is the first chapter of:
The Suki Kamasutri: Queen of the Galactic Frontier
A transcript from the classic ether of the same name from the late 23rd
Century. Hopefully, I'll get it published sometime before then.
previous (Angles Revisited) paper.js tutorial
index next (Circle Bubble Game Board)
Back to BrettCode Home
Brett Words
my writing site (Home to the writing of Celli the Happy Go Lucky
Celaphopod, Eddie Takosori, Fritz Heinmillerstein, Morgan Feldstone,
Kevin Stillwater, and of course, me, your host, Brett Paufler)
paper.js official site = http://www.paperJS.org
© Copyright 2013 Brett Paufler