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:
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.


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