ZIM - Code and Learn Coding with ZIM for JavaScript and HTML Canvas with CreateJS

BADGES

"ZIM Badges train and test you as you make art!"
"Step by step, we see the consistency of ZIM"
"If you can get Badge 6, you are a digital artist!"
"Tell your Teachers about ZIM!"
"Make four types of interactive art!"
"Learn the words coders use!"

Follow these steps to get ZIM Badges!

ZIM BADGES link to Badge 1 section -
    			 for JavaScript HTML Canvas Coding ZIM BADGES link to Badge 2 section -
    			 for JavaScript HTML Canvas Coding ZIM BADGES link to Badge 3 section -
    			 for JavaScript HTML Canvas Coding ZIM BADGES link to Badge 4 section -
    			 for JavaScript HTML Canvas Coding ZIM BADGES link to Badge 5 section -
    			 for JavaScript HTML Canvas Coding ZIM BADGES link to Badge 6 section -
    			 for JavaScript HTML Canvas Coding
BADGE 1
TOP

Use a template and start coding!

1. Copy and paste the code below into a text document on your computer - save as art.html. We like using ATOM which is a free text editor with good code syntax coloring. HIGHLIGHT MORE
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM Badges - ART</title>

<!-- Welcome to ZIM at http://zimjs.com - Code Interactive Media Pizzazz! 				-->
<!-- ZIM runs on the HTML Canvas powered by JavaScript and CreateJS http://createjs.com -->
<!-- Founded by Inventor Dan Zen - http://danzen.com - Canadian New Media Award Winner 	-->
<!-- ZIM is free to use. You can donate to help improve ZIM at http://zimjs.com/donate 	-->

<script src="https://d309knd7es5f10.cloudfront.net/createjs.min.js"></script>
<script>
	var zon = true; // set to false to turn off console messages from zim
	var zns = false; // set to true to require zim namespace - eg. new zim.Frame( )
</script>
<script src="http://d309knd7es5f10.cloudfront.net/zim_6.2.2.js"></script><!-- add _doc to see code -->
<!-- use zimjs.com/code/distill for minified individual functions! -->

<style>
	body {background-color:#000;}
</style>

<script>

// SCALING OPTIONS
// scaling can have values as follows with full being the default
// "fit"        sets canvas and stage to dimensions and scales to fit inside window size
// "outside"    sets canvas and stage to dimensions and scales to fit outside window size
// "full"       sets stage to window size with no scaling
// "tagID"      add canvas to HTML tag of ID - set to dimensions if provided - no scaling

var scaling = "fit"; // fit scales to fit the browser window while keeping the aspect ratio
var width = 1024; // can go higher...
var height = 768;
var frame = new Frame(scaling, width, height); // see docs for more options and info
frame.on("ready", function( ) {
	zog("ready from ZIM Frame");

	var stage = frame.stage;
	var stageW = frame.width;
	var stageH = frame.height;
	frame.color = frame.green;

	// put your code here (you can delete this code)



	stage.update( ); // update the stage to see any changes

}); // end of ready
</script>

</head>

<body>
<!-- canvas with id="myCanvas" is made by zim Frame -->
</body>
</html>

                    

2. After it says put your code here, make a variable (var) called circle and use the new keyword to assign (=) a new Circle() with a radius of 50 and a color of frame.pink.
Click on any of the green links to see the docs about the feature and show you how to use it. Here we need to pass extra information to the new Circle( ) when we make it. We pass the extra information in as parameters separated by commas (,). In this case, we need to put the values 50 and frame.pink in the brackets of Circle( ) and separate them with a comma. The color could be any HTML color such as "blue", "#333", etc. (note the quotes) but we have stored a few special ZIM colors in the frame class so we often use those.
On the end of this statement, use a dot (.) to chain the circle's center() method which adds the circle to and centers the circle on the stage.
There is a helpful LEARN section on ZIM but we will tell you some tips in the grey dashed sections (like this one) as we go. Here is tip: a method does something (it is like a verb). To use a method, you put the object first (in this case the object is the new circle( )) then a period (.) and then the method with round brackets. We call this dot syntax because a dot separates the object and the method. You can pass extra information into the round brackets as parameters. Here, we need to pass a reference to the stage to tell the center( ) method to center the circle on the stage. Chaining is a technique that can be used with ZIM methods. See the MORE link for a video about Chaining.
HIGHLIGHT MORE ANSWER
3. Chain the circle's drag() method to make the circle draggable. Test the app in a Browser by finding the page on your computer and dropping it on an open Browser. (In Atom, you should get the open-in-browser package) HIGHLIGHT MORE ANSWER
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)
BADGE 2
TOP

Use a loop and random numbers to create art!

4. Comment out the previous circle code using // at the start of the lines (or CTRL / in ATOM).
Hahaha - wasn't that productive! We are about to use the power of code to do our work for us and make 100 circles!
HIGHLIGHT MORE ANSWER
5. Make a variable (var) called circles and assign (=) a new Container() with a width value of stageW and a height value of stageH. Then addTo() the container to the stage.
Containers are objects that are used to hold Display objects. You cannot see the container but you can see the objects inside. The advantage is that you can move the container around and all its contents will move. You can remove a container and all its contents are removed. You can add an event to a container and its children will trigger the event. You can add a drag to a container and its children can individually be dragged.
HIGHLIGHT MORE ANSWER
6. Use loop() to loop 100 times and each time call a function( ){ } with a zog() of "hello" inside.
A zim loop( ) is like a for loop in JavaScript with a slightly easier syntax. It has three different modes to handle looping through Numbers, Arrays and Containers. In this case we put a Number 100 as the first parameter and a function literal (anonymous function) as a second parameter. The function will be called 100 times. The function literal receives parameters such as the index number of the loop but we are not using these in this case.
HIGHLIGHT MORE ANSWER
7. Create a new Circle() with a radius of 50, a color of frame.pink (for now) and a borderColor of frame.blue. Then chain an addTo() to add the circle to the circles container (NOT the stage). In this case, we do not need to store the circle in a variable. They will just become children of the circles container.
To make art, we want to vary the properties of objects often either sequentially or randomly. In this case we will use randomness with the zim rand() function. This is just like Math.random( ) but with a helpful format - you can pass rand( ) two numbers and it will pick a number between them. Optionally, if you pass one number, it picks between 0 and the number. There are other features of rand( ) too that you can read about in the docs. We will start off positioning the circles in random x and y positions on the stage.
Chain on a pos() method to receive x and y values as parameters. For the x value use the rand() on stageW and for the y value use the rand() on stageH. This will place the circles randomly on the stage. HIGHLIGHT MORE ANSWER
ZIM Learn References
8. Go back and adjust the radius of the Circle() to a random number between 20 and 100 using rand(). Also chain on an alp() method with a value of a random number between .1 and .5 to randomize the transparency. HIGHLIGHT MORE ANSWER
9. ABOVE the loop code, create a var called colors and assign (=) an Array that holds frame.pink, frame.purple, frame.blue and frame.yellow. Then replace the Circle's frame.pink (color parameter) with shuffle() to shuffle the array and right on the end of the shuffle( ) use the array access operator [ ] to access the first (0) element. This will get the first color of the shuffled array - in other words, a random color from the array. There are other ways to do this, but this way is cool. HIGHLIGHT MORE ANSWER
10. Chain on a animate() with a single configuration object { } as a parameter (ZIM Duo Technique). The configuration object should have an obj property of {scale:2}, a time property of 2000, a loop property of true and a rewind property of true. This will animate all the circles bigger and smaller which will not look very good - but we will fix it in the next step.
The ZIM DUO technique (introduced in ZIM DUO (2)) is when you can pass in parameters in the regular orderly way or pass in a single parameter that is a configuration object. This is just an object literal { } that has properties that match the parameter names. This allows you to skip parameters you do not need and to not worry about the order. The drawback is that you have to type the parameter names.
HIGHLIGHT MORE ANSWER
ZIM animate() parameters can receive ZIM VEE values (introduced in ZIM VEE (5)) that allow for dynamic choices. These can be an Array of options, a Function that returns a value or a ZIM RAND Object that has a min and max property. There are other nuances, but this is the general functionality.
11. Change the scale property of the obj property of the animate() configuration object to an Array [ ] of options such as .1, .5, .7, 1.3, 1.5, 2. This is tricky because we do not want a random number from a range as that would give us numbers close to 1 which would leave circles unchanging and looking awkward. Also change the time property to a ZIM RAND object { } with a min property of 5000 and a max property of 10000. This sets random times between 5 seconds and 10 seconds. HIGHLIGHT MORE ANSWER
12. On the circles container, call its drag() method. Pass in a configuration object { } as single parameter that has a removeTweens property set to false.
Putting a drag( ) on a container will make it so any object within the container will be draggable. We could make the whole container drag by setting the currentTarget parameter to true but we do not want to. The drag method, by default, will stop any animation on the object being dragged. We have turned this feature off as we want to continue to animate while dragging.
HIGHLIGHT MORE ANSWER
ZIM Learn References
This is the last step of our first art piece! In the next sections we will make three more art pieces and controls to go from one piece to the other. When we do this, we transition between pieces with a page slide. During this page slide, the art piece is cached which is like a screen capture. If the animation continues "behind the scene" then when we come back to the art piece, there will be a jumping to the art piece at a different time. This is not good. So here is a way to pause the animation of the art. We will turn off and on the animation in the page controls in the next section.
13. In the configuration object { } of the animation() add an id property with a value of "circles". AFTER our drag( ) code, use a pauseZimAnimate() function with first parameter of true and a second parameter of "circles". This will pause only the animations with the id of circle. If we left out the id then all animations would pause including our future page transition. HIGHLIGHT MORE ANSWER
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)
BADGE 3
TOP

Create pages with a navigation bar

In this Badges section, we will make our navigation at the BOTTOM of the template. In the last three badges sections we will add our art pieces ABOVE the navigation and keep adding to the navigation as we go.
14. Just ABOVE the stage.update( ), make a variable (var) called pages and assign (=) a new Pages() object. Add an Array [ ] with our pages as the first parameter - currently, we have one page: circles - so add circles to the array. As a second parameter, add "slide" which is the type of transition and as a third parameter, add 1000 for the transition speed in milliseconds. HIGHLIGHT MORE ANSWER
15 a) Make a variable (var) called nav and assign (=) a new Container() with a width of stageW and a height of 100. Chain on an addTo() and pass in the stage as the parameter. Chain on a pos() and pass in 0 and stageH-100 as the x and y parameters.

15 b) Make a variable (var) called backing and assign (=) a new Rectangle() with a width of nav.width and a height of nav.height. The color will default to black. Chain on an addTo() and pass nav as the parameter (NOT stage). Chain on an alp() with .5 as the parameter.

15 c) So that we cannot click through the nav and drag the circles we can put a mousedown event on the backing that calls an empty function. On the next line (do not chain!), add an on( ) method to the backing with "mousedown" as the first parameter and a function literal function( ){ } as the second parameter. Test in a browser to see our panel. HIGHLIGHT MORE ANSWER
16 a) We will make an arrow button to go from page to page. Make a variable (var) called arrow and assign (=) a new Triangle() with 60, 60, 60, frame.white as parameters. Chain on a rot() and pass in 90 as a parameter to point the arrow to the right.

16 b) Make a variable (var) called arrow2 and assign (=) a clone( ) of the arrow. On the next line (do not chain!), set the arrow2's color property to frame.yellow.

16 c) Make a variable (var) called button and assign (=) a new Button() with a single parameter that is a configuration object. The configuration object should have the following properties: label of "" (so we do not see words), backing of arrow, rollBacking of arrow2, and a hitPadding of 10 to make it easier to press. Chain on a centerReg() and pass nav as the parameter (NOT stage). Chain on an alp() with .7 as the parameter. Chain on a mov() with stageW/2-60 as the parameter. HIGHLIGHT MORE ANSWER
17. ABOVE the navigation, make a variable (var) called rectangles and assign (=) a new Container() with a width of stageW and a height of stageH. Chain on an alp() with a parameter of .8 (we will blend in our page a bit with the background color) Add rectangles to the start of the Pages array before circles as this will be our next art piece! By default, Pages will put the first page in the array on the stage so we do not have to add it ourselves. HIGHLIGHT MORE ANSWER
18. BENEATH the button add an on( ) method to the button to capture a "click" event and call a function literal function( ){ }. Inside the function, use a conditional if ( ) { } to find out if the page property of pages is equal to (==) rectangles. If it is then use the Pages() go( ) method of pages to go to circles. Add an else if ( ) { } to find out if the page property of pages is equal to (==) circles. If it is then use pauseZimAnimate() with parameters of true and "circles" to pause the circle animation now that we are leaving the page. Then use the go( ) method of pages to go to rectangles. HIGHLIGHT MORE ANSWER
We want to turn the circles animation on once the transition to the circles page is finished. Otherwise, if we animate during the transition, it is not seen due to the caching (screen shot) during transition and when the transition is done, the circles will be in a different position and there will be an undesired jump.
19. BELOW the button event code, use the on( ) method of the pages to capture a pagetransitioned event and call a function literal function( ){ }. INSIDE the function use a conditional if ( ) { } to test if the page property of pages is equal to (==) circles. If it is then use pauseZimAnimate() with parameters of false and "circles" to start the circles animating now that the transition is complete.

View in a Browser and now the empty rectangles page should transition to the circles page when you press the arrow button. Pressing the button again transitions to the empty rectangles page, etc. In the next section, we will complete the rectangles page. In the two sections after that, we will make two more pages and add them to the navigation as we go! Get your ZIM Badge! HIGHLIGHT MORE ANSWER
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)
BADGE 4
TOP

Create art using noise

For the rectangles art piece we will use noise. ZIM Noise() has an equation (OpenSimplex) that looks random but is actually a weirdly wiggly line, or plane or structure. See the MORE section for related links with explanations and examples. In this case, we have a number of tall rectangles that we animate with noise. We use 2D noise and set the height of the rectangles to the result of the noise. We pass in the rectangle number (adjusted) as the first parameter of the noise. We animate the second parameter of the noise inside a ZIM Ticker(). We will use two Slider() objects to control properties of the noise.
20. BELOW the rectangles code, make a variable (var) called noise and assign (=) a new Noise() object. HIGHLIGHT MORE ANSWER
21 a) Prepare to make Rectangles in a loop. Make a variable (var) called greys and assign (=) an Array [ ] with the following values: frame.light, frame.lighter, frame.dark, frame.darker, frame.silver, frame.tin, frame.grey. Set a variable called margin to 100. Set a variable called total to 20. Set a variable called width to (stageW-margin*2)/total. This will divide up our space (less the margins on each side) into the width for each rectangle. Set a variable called height to stageH/2.

21 b) Create a loop() and pass in total and a function literal function( ){ } as parameters.

21 c) INSIDE the loop create a new Rectangle() with the following parameters: width, height, shuffle(greys)[0], frame.black, 1, width/2. This will make rectangles of random shades of grey with a black border and rounded corner (the last parameter). Chain on a reg() and pass 0, height/2 as parameters. Chain on an addTo() with parameter of rectangles (NOT stage). Chain on a pos() with margin+i*width, stageH/2-50 as parameters. This will place the rectangles next to one another across the stage. HIGHLIGHT MORE ANSWER
Here we will use a Ticker.add() to animate the rectangles. We will keep track of an increasing number, num, to animate the noise value. Each time we will increase num by a small amount, speed. And we will apply a factor, zoom, to the first parameter of noise to say how close we are zooming in on the noise equation. A higher zoom makes smaller steps and therefore a smaller difference in the rectangle heights.
22 a) Set a variable called num to 0. Set a variable called speed to .05. Set a variable called zoom to 20.

22 b) Create a variable called ticker and store the result of the add( ) static method of a Ticker. Pass in a function literal function( ){ } as its parameter. This is the function that will run constantly at the framerate - probably 60 times a second. We store the result of the add() method this time so that we can add and remove the function later.

22 c) INSIDE the Ticker function add speed to the num using the addition assignment operator (+=). Then create a loop() with rectangles as the first parameter and a function literal function( ){ } as the second parameter. Collect the two parameters that loop passes to the function literal as rect and i.

22 d) INSIDE the loop function make a variable called result hold the result of the simplex2D( ) method of noise. Pass in i/zoom, num as parameters for simplex2D. Set the heightOnly property of the rect to stageH/2 + result*200.
The first parameter of the simplex2D( ) specifies where on the noise equation to look for a value. The second parameter moves this location in a second dimension which changes it over time (as we increase num). The result of simplex2D( ) will always be a number from -1 to 1. The heightOnly value is determined from the starting height of the rectangles (stageH/2) plus the noise value (from -1 to 1) multiplied by 200. So we will end up with the original height plus or minus 200.
HIGHLIGHT MORE ANSWER
In this step and the next, we are going to set up controls for the speed and zoom values using a Slider(). These will range from .001 to .1 and from 30 to 1. Sliders can use bigger numbers as their min (left) and smaller numbers as their max (right). We will add the sliders to the nav.
23 a) At the bottom, BEFORE the last stage.update( ) and AFTER the pages event code, make a variable (var) called slider and assign (=) a new Slider() with a single configuration object { } as its parameter. The configuration object should have a min property of .001, a max property of .1 and a barColor property of frame.silver. Chain on a center() and pass the nav as a parameter (NOT stage). Chain on an mov() with a parameter of -250. Set the alpha property of the button property of the slider to .5. Start the slider at the current speed value by setting the currentValue property of the slider to speed.

23 b) Use the on( ) method of the Slider() to set a "change" event and call a function literal function( ){ }. INSIDE the function set speed to the slider's currentValue property using the assignment operator (=). HIGHLIGHT MORE ANSWER
24 a) Make a variable (var) called slider2 and assign (=) a new Slider() with a single configuration object { } as its parameter. The configuration object should have a min property of 30, a max property of 1 and a barColor property of frame.silver. Chain on a center() and pass the nav as a parameter (NOT stage). Chain on an mov() with a parameter of 150. Set the alpha property of the button property of the slider2 to .5. Start the slider2 at the current zoom value by setting the currentValue property of slider2 to zoom.

24 b) Use the on( ) method of the Slider() to set a "change" event and call a function literal function( ){ }. INSIDE the function set zoom to the slider2's currentValue property using the assignment operator (=). Try out the code in a Browser and adjust the Sliders! Cool! HIGHLIGHT MORE ANSWER
We have a problem transitioning animating the rectangles that is similar to the problem with transitioning the animated circles. So we will want to turn off the Ticker and let the navigation turn it on when needed. We do not turn off the Ticker right away as we want to set the rectangles to a random state first rather than all in a straight line.
25. BELOW the Ticker function, use timeout() with a first parameter of 500 for half a second and a second parameter of a function literal function( ){ }. INSIDE the function use the remove( ) static method of the Ticker and pass ticker as the parameter. This will stop the rectangle animation after half a second. HIGHLIGHT MORE ANSWER
26. Prepare for the next section. UNDER the timeout create a variable called mosaic and assign (=) a new Container() with stageW and stageH passed in as parameters. ADD the mosaic to the start of the pages array below. Now, our app will start at the empty mosaic page. HIGHLIGHT MORE ANSWER
27. We want to hide the sliders and let the nav take care of showing them. Chain on an alp() with a parameter value of 0 to each slider. HIGHLIGHT ANSWER
28. Add an else if ( ) { } to the pagetransitioned event function conditional. Test if the page property of pages is equal to (==) rectangles then use the add() method of the Ticker and pass ticker as the parameter value. This will turn back on the animation after the page transitions to the rectangles. Also fade in the sliders using the animate() method of each slider. The parameters for each will be {alpha:1}, 1000. HIGHLIGHT MORE ANSWER
29. In the button "click" event function ADJUST the rectangles part of the conditional. Add the following: use the remove( ) method of the Ticker with a parameter of ticker to stop the rectangles from animating. Use the animate() method of each slider to animate the alpha out. The parameters for each will be {alpha:0}, 1000. ADJUST the go( ) method of pages to go to mosaic rather than circles. ADD an else if ( ) that tests to see if the page property of pages is equal to (==) mosaic and if so, uses the go( ) method of pages to go to circles.
Whew! Claim you Badge! We are now ready to go to the next section and make Mosaic Art!
HIGHLIGHT MORE ANSWER
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)
BADGE 5
TOP

Use tiling and reflection to make art!

For our mosaic art, we are going to make a tile container with a backing rectangle and some circles inside. We will then use Tile to tile the tile ;-). We will make it so that we can the circles in any tile and the rest of the tiles move to match!
30. BELOW the mosaic code, make a variable (var) called tile and assign (=) a new Container() with a stageW and stageH as parameter values. Chain on a center() temporarily with a parameter of mosaic to see the tile on the screen. Make a variable (var) called rect and assign (=) a new Rectangle() with tile.width, tile.height, frame.blue as parameters. Chain on an addTo() and pass in tile to add the backing to the tile. We do not want to drag the backing so on the next line (do not chain properties) set the mouseEnabled property of rect to false. HIGHLIGHT MORE ANSWER
31. Make THREE Circle() objects - do not add them to variables. The first will have parameters of: 50, frame.yellow, frame.grey, 5. The second will have parameters of: 30, frame.orange, frame.purple, 4. And the last will have parameters of: 10, frame.pink, frame.purple, 3.. Chain on the center() method of each to center the circles on the tile (NOT the stage). Also chain on the setMask() method for each circle and pass in rect as the mask parameter. Now the circles when dragged will not go outside the shape of the rect which would look bad when tiled. HIGHLIGHT MORE ANSWER
Here we will use a Tile() object to tile 8 columns and 4 rows of our tile. We can put a drag() on the Tile object and anything inside will drag (except the backings). We will make the matching circles move as we drag a circle and we will put a frame behind the art.
32. Make a variable (var) called tiles and assign (=) a new Tile() with parameters of: tile, 8, 4, 0, 0, true, true. This will tile 8 times across and 4 times down with 0 spacing and reflect every other tile horizontally and vertically. Chain on an center() and pass in mosaic to add the tiles to the page. Chain on an mov() and pass in 0, -50 to move the tiles up. Chain on a drag() with a single configuration object { } as a parameter having a property of onTop set to false. Now the circles will maintain their stacking order so the smaller ones never go behind the larger ones. IMPORTANT - remove the center() method from the original tile as we no longer need to do that. HIGHLIGHT MORE ANSWER
33. Make a new Rectangle() - do not store it in a variable. Set the parameters to tiles.width+50, tiles.height+50, frame.black. Chain on an center() and pass in mosaic then 0 as the parameters to add the rectangle behind the tiles. Chain on an alp() and pass in .1 to fade the rectangle out. Chain on a mov() with parameters of 0 and -50 to match where we moved the tiles. HIGHLIGHT ANSWER
As we move a circle, we want the same circle in the other tiles to move at the same time. We can capture a pressmove event and then find the depth of the master circle we are moving. We can then loop through all the tiles and set the circle at that depth to the position of the master circle.
34 a) Use the on( ) method of the Tile() to capture a "pressmove" event and call a function literal function( ){ }. Collect the event object as e inside the round brackets ( ) of the function literal. This will give us extra information about the event such as the target inside the tile that caused the event. INSIDE the function, make a variable (var) called master and assign (=) the target property of the event object, e. This refers to the circle we are dragging.

34 b) Make a variable (var) called depth and store result of the getChildIndex( ) method that is placed on the parent property of the master. Pass the master in as the parameter. This finds the level or depth of the master inside its parent (the tile that holds the circle we are dragging). This can seem a little backwards but that is how it is done.

34 c) Use a loop() and pass in parameters of tiles and a function literal function( ){ }. Capture a parameter called tile inside the round brackets ( ) of the function literal. This means that we loop through the tiles and each time are given a tile in the parameter, tile. INSIDE the function, use the pos() method of the result of the getChildAt() method on the tile passing in the depth as the parameter for getChildAt(). Pass in the x and y properties of the master into the two parameters of the pos(). This sets the position of the circle at the same depth of the master to the position of the master. Finally, call the update() method of the stage to update the stage. All this is inside the "pressmove" event function.
Try out the code in a Browser and drag the circles about! In the next steps we prepare for the final section.
HIGHLIGHT MORE ANSWER
35. Prepare for the next section. UNDER the "pressmove" event create a variable called blobs and assign (=) a new Container() with stageW and stageH passed in as parameters. ADD blobs to the start of the pages array below. Now, our app will start at the empty blobs page. HIGHLIGHT MORE ANSWER
36. In the button "click" event function ADJUST the mosaic part of the conditional. Set the go() method of pages to go to blobs rather than circles. ADD an else if ( ) that tests to see if the page property of pages is equal to (==) blobs and if so, uses the go() method of pages to go to circles.
Claim you Badge! We are now ready to go to the next section to draw shapes with Blobs and save the changes!
HIGHLIGHT MORE ANSWER
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)
BADGE 6
TOP

Make pictures with Blobs and save changes!

In this last section we will make three Blob() objects that are interactive and have their states saved so the user's picture is saved. Blobs by default will show Bezier curves to be able to change the blob shape. We can also set the dblclick to true which allows the user to double click on the blob to hide the Bezier curves and drag the blob.
37 a) BELOW the blobs code, make a variable (var) called blobColors and assign (=) an Array [ ] with the following elements: frame.purple, frame.orange, frame.blue.

37 b) Use a loop() and pass in 3 as the first parameter (to make three blobs) and a function literal function( ){ }. Collect the parameter i inside the round brackets ( ) of the function literal. INSIDE the function, make a variable (var) called blob and assign (=) a new Blob() with a single configuration object { }. The configuration object has a color property of blobColors[i], a points property of i+3 (to set the number of points on the blobs to 3, 4 and 5) and a dblclick property of true. Chain on a center() method with blobs as the parameter (NOT stage). Chain on a mov() method with a parameter of 300*(i-1). This will spread the blobs out across the page at -300, 0 and 300 from the center.

37 c) Still INSIDE the loop function, set the blendMode property of the blob to "difference". This will mix the colors as the blobs overlap - of course, this is optional. HIGHLIGHT MORE ANSWER
We will now start the process of recording and saving the Blob() objects. We use the record() method and we do this every time we "pressup" on a blob. We will start by viewing the recorded data in the console and in the next step we will record the data.
38. Use the on() method of the blobs (Container) to capture a "pressup" event and call a function literal function( ){ }. INSIDE the function, use a loop() with the first parameter set to blobs and the second parameter set to a function literal function( ){ }. Set the parameter of the function literal to blob so that as we loop through the blobs, we get each blob object as blob. INSIDE the function, use zog() to log to the console the result of the record() method of blob. HIGHLIGHT MORE ANSWER
We will now save the Blob() data that we get from the record() method. We do this with the localStorage object provided by Web Storage API of JavaScript that saves the data even after the Browser is closed. We need to JSON encode this data to turn it into a String and decode it when we get it back. This all sounds scary but it is really easy. We have a slight glitch if we record the data right away, because there is a delay in setting Blob properties on double clicking. So we will use a timeout in our code.
39 a) INSIDE the "pressup" at the top of the function, set a variable (var) blobData equal to (=) an empty Array [ ]. We will use this to keep track of all the data for the three blobs.

39 b) Wrap the loop() in a timeout() function with a first parameter of 50 for a 50 millisecond delay and the second parameter a function literal function( ){ } that holds the loop function. This just lets the blob set its controls before recording the blob data.

39 c) INSIDE the loop, replace the zog() with following command to add the current blob's data to the blobData array: use the push() method of the blobData with parameter of: an Array [ ] with the following elements: blob.color, blob.x, blob.y, blob.controls, blob.record().
The record() method only records the position of the Bezier points and handles. We also want to record the color, x and y, and if we are currently showing the controls. We store this information in an array for each blob. And we push that array into the blobData array.

39 d) AFTER the loop but still INSIDE the timeout, make a conditional if ( ) { } and test for localStorage. Just put localStorage in the round brackets ( ) as this will evaluate to true if it is available for the user. In the { } or leave the brackets out as there is only one line, make a blobData property of localStorage equal to (=) the results of the stringify() static method of the JSON class. Pass blobData into the stringify() method as its parameter.
The localStorage can only hold strings and numbers, not Arrays or other complex objects. JSON.stringify() will encode our array as a string and in the next step we will decode the string back into our array!
HIGHLIGHT MORE ANSWER
40. At the TOP of the page == sound conditional, stop the animation from the animation page using the zim function zim.stopZimAnimate(). Now the animation will stop when going from the animation page to the sound page when viewing in a Browser. HIGHLIGHT ANSWER
We now need to adjust the creation of the Blob() objects. We want to create the blobs as they were saved if the user has already been to the app and changed the blobs. We will create the blobs the same way, but if there is localStorage data for the blobs, then we will use the data from the localStorage. We must use the parse() method of JSON to decode the data before we use it.
41 a) BELOW the blobColors array assignment, create a conditional if ( ) { } that tests to see if localStorage && localStorage.blobData so in other words, if there is blob data stored. For now, put nothing in the first { } and add an else { }. Put the whole loop function that we made earlier into the second { }. So, if there is blob data, we will do what is in the first brackets (the next step), else we make the blobs from the default data like we did before.

41 b) INSIDE the first { } of the conditional make a variable (var) data equal to (=) the result of the parse() static method of the JSON class. Pass localStorage.blobData as a parameter to the parse() method.

41 c) COPY the whole loop that is inside the second { } and place the copy INSIDE the first { } beneath the var data. We will make adjustments to the values in the next step.

As we loop through the blobs, the value i goes from 0 to 1 to 2. If we access the blobData[i] we are getting the internal data array for each blob. So, data[0][0] gives us the color of the first blob. data[2][4] gives us the Bezier point data for the third blob.
41 d) For the color of the blob, change the value to data[i][0]. For the points of the blob, change the value to data[i][4]. Instead of mov(), use a pos() method with parameters of data[i][1], data[i][2]. BEFORE the blendMode, set the controls property of the blob to data[i][3]. HIGHLIGHT MORE ANSWER
42 a) In the Pages() "pagetransitioned" event, add an else if ( ) to the bottom of the conditional that test to see if the page property of pages is equal to (==) rectangles and if so, uses the animate() method of text with the first parameter being a configuration object { } having an alpha property of .5 and the SECOND parameter (not property) being 1000 for the time.

42 b) UP in the pages "click" event function in the blobs part of the conditional, animate the alpha of the text to 0 in 400 milliseconds so it fades away when clicking away from the blobs page.

42 c) DOWN where we declared the text CHANGE the alp() to 0 so we no longer see the text to start. HIGHLIGHT MORE ANSWER
43. ADJUST the Pages() array to start with circles - we will show the circles art first. HIGHLIGHT ANSWER
44. Now that we are showing circles first, go UP to the circles code and comment out (//) or delete the pauseZimAnimate(). HIGHLIGHT MORE ANSWER
CONCLUSION: The world of generative and interactive art is wondrous and wild! You can get lost in experimentation and even hone in on the fabric of life itself. One thing to think about... if you can make art, then perhaps provide controls so that others can make art as well. ZIM Ornamate is an example. ZIM provides a series of components to let you dynamically adjust properties. An example of some can be found at the NOISE Examples after choosing an example. ZIM Bits also has several starts to art projects.

ZIM helps you code the Canvas. Pretty well any 2D art techniques that have been available to coders - in Flash, Processing, etc. can be used in ZIM. Of course, it is always best when you unleash your own imagination and CODE CREATIVITY.
FINAL STEP: if you are in school, please show ZIM to your coding teacher and what you have accomplished. Inventor Dan Zen recently won a 2017 Hamilton Arts Award in the Media Arts category for his interactive works - many were created in ZIM.
CLAIM YOUR BADGE
(SHOW YOUR TEACHER)